Merge remote-tracking branch 'origin/test' into dish

This commit is contained in:
Philip C Monk 2014-11-06 17:09:18 -05:00
commit 3bdcfedb2a
2 changed files with 104 additions and 74 deletions

View File

@ -159,87 +159,117 @@ Regular symbols follow this pattern:
u3q[a-g] jets (retain, C args) i/j/q.h j/[a-g]/*.c
u3w[a-g] jets (retain, nock core) i/j/w.h j/[a-g]/*.c
Irregular symbols always start with `u3` and obey no other rules.
They're defined in `i/n/u.h`. Finally, `i/all.h` includes all
these headers (fast compilers, yay) and is all you need to
program in `u3`.
u3 deals with reference-counted, immutable, acyclic nouns. 90%
of what you need to know to program in u3 is just how to get your
refcounts right.
### u3: reference counts
The only really essential thing you need to know about `u3` is
how to handle reference counts. Everything else, you can skip
and just get to work.
/** Prefix definitions:
***
*** u3a_: fundamental allocators.
*** u3c_: constants.
*** u3e_: checkpointing.
*** u3h_: HAMT hash tables.
*** u3i_: noun constructors
*** u3j_: jets.
*** u3k*: direct jet calls (modern C convention)
*** u3m_: system management etc.
*** u3n_: nock interpreter.
*** u3o_: fundamental macros.
*** u3q*: direct jet calls (archaic C convention)
*** u3r_: read functions which never bail out.
*** u3s_: structures and definitions.
*** u3t_: tracing.
*** u3w_: direct jet calls (core noun convention)
*** u3x_: read functions which do bail out.
*** u3v_: arvo specific structures.
*** u3z_: memoization.
***
*** u3_cr_, u3_cx_, u3_cz_ functions use retain conventions; the caller
*** retains ownership of passed-in nouns, the callee preserves
*** ownership of returned nouns.
***
*** Unless documented otherwise, all other functions use transfer
*** conventions; the caller logically releases passed-in nouns,
*** the callee logically releases returned nouns.
***
*** In general, exceptions to the transfer convention all occur
*** when we're using a noun as a key.
**/
u3 deals with reference-counted, immutable, acyclic nouns.
Unfortunately, we are not Apple and can't build reference
counting into your C compiler, so you need to count by hand.
Every allocated noun contains a counter which counts the number
of references to it - typically variables with type `u3_noun`.
When this counter goes to 0, the noun is freed.
To tell `u3` that you've added a reference to a noun, call the
function `u3a_gain()` or its shorthand `u3k()`. (For your
convenience, this function returns its argument.) To tell `u3`
that you've destroyed a reference, call `u3a_lose()` or `u3z()`.
(If you screw up by decrementing the counter too much, `u3` will
dump core in horrible ways. If you screw up by incrementing it
too much, `u3` will leak memory. To check for memory leaks,
set the `bug_o` flag in `u3e_boot()` - eg, run `vere` with `-g`.
Memory leaks are difficult to debug - the best way to handle
leaks is just to revert to a version that didn't have them, and
look over your code again.)
The best way to introduce `u3` is with a simple map of the Urbit
build directory:
### u3: reference protocols
g/ u3 implementation
g/a.c allocation
g/e.c persistence
g/h.c hashtables
g/i.c noun construction
g/j.c jet control
g/m.c master state
g/n.c nock execution
g/r.c noun access, error returns
g/t.c tracing/profiling
g/v.c arvo kernel
g/x.c noun access, error crashes
g/z.c memoization/caching
i/ all includes
i/v vere systems headers
i/g u3 headers (matching g/ names)
i/c c3 headers
i/c/defs.h miscellaneous c3 macros
i/c/motes.h symbolic constants
i/c/portable.h portability definitions
i/c/types.h c3 types
i/j jet headers
i/j/k.h jet interfaces (transfer, args)
i/j/q.h jet interfaces (retain, args)
i/j/w.h jet interfaces (retain, core)
j/ jet code
j/dash.c jet structures
j/1 tier 1 jets: basic math
j/2 tier 2 jets: lists
j/3 tier 3 jets: bit twiddling
j/4 tier 4 jets: containers
j/5 tier 5 jets: misc
j/6 tier 6 jets: hoon
v/ vere systems code
outside/ all external bundled code
*THIS IS THE MOST CRITICAL SECTION IN THE `u3` DOCUMENTATION.*
The key question when calling a C function in a refcounted world
is what the function will do to the noun refcounts - and, if the
function returns a noun, what it does to the return.
There are two semantic patterns, `transfer` and `retain`. In
`transfer` semantics, the caller "gives" a use count to the
callee, which "gives back" any return. For instance, if I have
{
u3_noun foo = u3i_string("foobar");
u3_noun bar;
bar = u3f_futz(foo);
[...]
u3z(bar);
}
Suppose `u3f_futz()` has `transfer` semantics. At `[...]`, my
code holds one reference to `bar` and zero references to `foo` -
which has been freed, unless it's part of `bar`. My code now
owns `bar` and gets to work with it until it's done, at which
point a `u3z()` is required.
On the other hand, if `u3f_futz()` has `retain` semantics, we
need to write
{
u3_noun foo = u3i_string("foobar");
u3_noun bar;
bar = u3f_futz(foo);
[...]
u3z(foo);
}
because calling `u3f_futz()` does not release our ownership of
`foo`, which we have to free ourselves.
But if we free `bar`, we are making a great mistake, because our
reference to it is not in any way registered in the memory
manager (which cannot track references in C variables, of
course). It is normal and healthy to have these uncounted
C references, but they must be treated with care.
The bottom line is that it's essential for the caller to know
the refcount semantics of any function which takes or returns a
noun. (In some unusual circumstances, different arguments or
returns in one function may be handled differently.)
Broadly speaking, as a design question, retain semantics are more
appropriate for functions which inspect or query nouns. For
instance, `u3h()` (which takes the head of a noun) retains, so
that we can traverse a noun tree without constantly incrementing
and decrementing.
Transfer semantics are more appropriate for functions which make
nouns, which is obviously what most functions do.
In general, though, in most places it's not worth thinking about
what your function does. There is probably a convention for it.
Follow the convention.
### u3: reference conventions
The `u3` convention is that, unless otherwise specified, *all
functions have transfer semantics* - with the exception of the
prefixes: `u3r`, `u3x`, `u3z`, `u3q` and `u3w`. Also, within
jet directories `a` through `f` (but not `g`), internal functions
retain (for historical reasons).
If functions outside this set have retain semantics, they need to
be commented, both in the `.h` and `.c` file, with `RETAIN` in
all caps. Yes, it's this important.
### u3: system and memory architecture
Describing

View File

@ -385,7 +385,7 @@ u3_lo_shut(c3_o inn)
// u3_lo_grab("lo_exit", u3_none);
// u3_loom_save(u3A->ent_d);
// u3_loom_exit();
u3t_boff();
// u3t_boff();
u3_lo_exit();
exit(u3_Host.xit_i);
@ -553,7 +553,7 @@ u3_lo_loop()
_lo_init();
u3_raft_init();
u3t_boot(); // activate profiling
// u3t_boot(); // activate profiling
if ( c3n == u3_Host.ops_u.bat ) {
uv_run(u3L, UV_RUN_DEFAULT);