Various fixes and documentations.

This commit is contained in:
C. Guy Yarvin 2014-11-25 15:31:35 -08:00
parent c6d53985d6
commit 80d6f74886
11 changed files with 522 additions and 157 deletions

View File

@ -563,6 +563,27 @@ remote node, render the stacktrace as a consequence of the user's
action - even if its its direct cause was (for instance) a Unix
SIGINT or SIGALRM.
### u3: C structures on the loom
Normally, all data on the loom is nouns. Sometimes we break this
rule just a little, though - eg, in the `u3h` hashtables.
To point to non-noun C structs on the loom, we use a `u3_post`,
which is just a loom word offset. A macro lets us declare this
as if it was a pointer:
typedef c3_w u3_post;
#define u3p(type) u3_post
Some may regard this as clever, others as pointless. Anyway, use
`u3to()` and `u3of()` to convert to and from pointers.
When using C structs on the loom - generally a bad idea - make
sure anything which could be on the surface road is structurally
portable, eg, won't change size when the pointer size changes.
(Note also: we consider little-endian, rightly or wrongly, to
have won the endian wars.)
## u3: API overview by prefix
Let's run through the `u3` modules one by one. All public
@ -623,7 +644,6 @@ For descending into a subroad *without* Nock virtualization,
use `u3m_hate()` and `u3m_love` respectively. Hating enters
a subroad; loving leaves it, copying out a product noun.
Other miscellaneous tools in `u3m`: `u3m_file()` loads a Unix
file as a Nock atom; `u3m_water()` measures the boundaries of
the loom in current use (ie, watermarks); and a variety of
@ -631,6 +651,10 @@ prettyprinting routines, none perfect, are available, mainly for
debugging printfs: `u3m_pretty()`, `u3m_p()`, `u3m_tape()` and
`u3m_wall()`.
It's sometimes nice to run a mark-and-sweep garbage collector,
`u3m_grab()`, which collects the world from a list of roots,
and asserts if it finds any leaks or incorrect refcounts.
### u3j: jets
The jet system, `u3j`, is what makes `u3` and `nock` in any sense
@ -726,8 +750,7 @@ Cold state is associated with the logical execution history of
the pier. It consists entirely of nouns and ignores restarts.
Warm state contains all dependencies between cold and hot
state. It consists of C structures allocated on the loom (with
`u3_post`, ie, a word pointer relative to the loom).
state. It consists of C structures allocated on the loom.
Warm state is purely a function of cold and hot states, and
we can wipe and regenerate it at any time. On any restart where
@ -1080,8 +1103,8 @@ transfer both arguments and results.
### u3a: allocation functions
`u3a` allocates on the current road (u3R). Its internal structures
are entirely uninteresting and typical of a naive allocator.
`u3a` allocates on the current road (u3R). Its internal
structures are uninteresting and typical of a naive allocator.
The two most-used `u3a` functions are `u3a_gain()` to add a
reference count, and `u3a_lose()` to release one (and free the
@ -1148,7 +1171,359 @@ atoms. When building atoms, please remember that it's incorrect
to have a high 0 word - the word length in the atom structure
must be strictly correct.
Of course, we don't always know how large our atom will be.
Therefore, the standard way of building large atoms is to
allocate a block of raw space with `u3a_slab()`, then chop off
the end with `u3a_malt()` (which does the measuring itself)
or `u3a_mint()` in case you've measured it yourself.
Once again, *do not call `malloc()`* (or C++ `new`) within any
code that may be run within a jet. This will cause rare sporadic
corruption when we interrupt execution within a `malloc()`. We'd
just override the symbol, but `libuv` uses `malloc()` across
threads within its own synchronization primitives - for this to
work with `u3a_malloc()`, we'd have to introduce our own locks on
the surface-level road (which might be a viable solution).
### u3n: nock execution
The `u3n` routines execute Nock itself. On the inside, they have
a surprising resemblance to the spec proper (the only interesting
detail is how we handle tail-call elimination) and are, as one
would expect, quite slow. (There is no such thing as a fast tree
interpreter.)
There is only one Nock, but there are lots of ways to call it.
(Remember that all `u3n` functions *transfer* C arguments and
returns.)
The simplest interpreter, `u3n_nock_on(u3_noun bus, u3_noun fol)`
invokes Nock on `bus` (the subject) and `fol` (the formula).
(Why is it`[subject formula]`, not `[formula subject]`? The same
reason `0` is true and `1` is false.)
A close relative is `u3n_slam_on(u3_noun gat, u3_noun sam)`,
which slams a *gate* (`gat`) on a sample (`sam`). (In a normal
programming language which didn't talk funny and was retarded,
`u3n_slam_on()` would call a function on an argument.) We could
write it most simply as:
u3_noun
u3n_slam_on(u3_noun gat, u3_noun sam)
{
u3_noun pro = u3n_nock_on
(u3nc(u3k(u3h(gat)),
u3nc(sam, u3k(u3t(u3t(gat))))),
u3k(u3h(gat)));
u3z(gat);
return pro;
}
Simpler is `u3n_kick_on(u3_noun gat)`, which slams a gate (or,
more generally, a *trap* - because sample structure is not even
needed here) without changing its sample:
u3_noun
u3n_kick_on(u3_noun gat, u3_noun sam)
{
return u3n_nock_on(gat, u3k(u3h(gat)));
}
The `_on` functions in `u3n` are all defined as pure Nock. But
actually, even though we say we don't extend Nock, we do. But we
don't. But we do.
Note that `u3` has a well-developed error handling system -
`u3m_bail()` to throw an exception, `u3m_soft_*` to catch one.
But Nock has no exception model at all. That's okay - all it
means if that if an `_on` function bails, the exception is an
exception in the caller.
However, `u3`'s exception handling happens to match a convenient
virtual super-Nock in `hoon.hoon`, the infamous `++mock`. Of
course, Nock is slow, and `mock` is Nock in Nock, so it is
(logically) super-slow. Then again, so is decrement.
With the power of `u3`, we nest arbitrary layers of `mock`
without any particular performance cost. Moreover, we simply
treat Nock proper as a special case of `mock`. (More precisely,
the internal VM loop is `++mink` and the error compiler is
`++mook`. But we call the whole sandbox system `mock`.)
The nice thing about `mock` functions is that (by executing
within `u3m_soft_run()`, which as you may recall uses a nested
road) they provide both exceptions and the namespace operator -
`.^` in Hoon, which becomes operator `11` in `mock`.
`11` requires a namespace function, or `fly`, which produces a
`++unit` - `~` (`0`) for no binding, or `[0 value]`. The sample
to a `fly` is a `++path`, just a list of text `span`.
`mock` functions produce a `++toon`. Fully elaborated:
++ noun ,* :: any noun
++ path (list ,@ta) :: namespace path
++ span ,@ta :: text-atom (ASCII)
++ toon $% [%0 p=noun] :: success
[%1 p=(list path)] :: blocking paths
[%2 p=(list tank)] :: stack trace
== ::
++ tank :: printable
$% [%leaf p=tape] :: flat text
$: %palm :: backstep list
p=[p=tape q=tape r=tape s=tape] :: mid cap open close
q=(list tank) :: contents
== ::
$: %rose :: straight list
p=[p=tape q=tape r=tape] :: mid open close
q=(list tank) :: contents
== ::
==
(Note that `tank` is overdesigned and due for replacement.)
What does a `toon` mean? Either your computation succeded (`[0
noun]`, or could not finish because it blocked on one or more
global paths (`[1 (list path)]`), or it exited with a stack trace
(`[2 (list tank)]`).
Note that of all the `u3` exceptions, only `%exit` is produced
deterministically by the Nock definition. Therefore, only
`%exit` produces a `2` result. Any other argument to
`u3m_bail()` will unwind the virtualization stack all the way to
the top - or to be more exact, to `u3m_soft_top()`.
In any case, the simplest `mock` functions are `u3n_nock_un()`
and `u3n_slam_un()`. These provide exception control without
any namespace change, as you can see by the code:
/* u3n_nock_un(): produce .*(bus fol), as ++toon.
*/
u3_noun
u3n_nock_un(u3_noun bus, u3_noun fol)
{
u3_noun fly = u3nt(u3nt(11, 0, 6), 0, 0); // |=(a=* .^(a))
return u3n_nock_in(fly, bus, fol);
}
/* u3n_slam_un(): produce (gat sam), as ++toon.
*/
u3_noun
u3n_slam_un(u3_noun gat, u3_noun sam)
{
u3_noun fly = u3nt(u3nt(11, 0, 6), 0, 0); // |=(a=* .^(a))
return u3n_slam_in(fly, gat, sam);
}
The `fly` is added as the first argument to `u3n_nock_in()` and
`u3n_slam_in()`. Of course, logically, `fly` executes in the
caller's exception layer. (Maintaining this illusion is slightly
nontrivial.) Finally, `u3n_nock_an()` is a sandbox with a null
namespace.
### u3e: persistence
The only `u3e` function you should need to call is `u3e_save()`,
which saves the loom. As it can be restored on any platform,
please make sure you don't have any state in the loom that is
bound to your process or architecture - except for exceptions
like the warm jet state, which is actively purged on reboot.
### u3r: reading nouns (weak)
As befits accessors they don't make anything, `u3r` noun reading
functions always retain their arguments and their returns. They
never bail; rather, when they don't work, they return a `u3_weak`
result.
Most of these functions are straightforward and do only what
their comments say. A few are interesting enough to discuss.
`u3r_at()` is the familiar tree fragment function, `/` from the
Nock spec. For taking complex nouns apart, `u3r_mean()` is a
relatively funky way of deconstructing nouns with a varargs list
of `axis`, `u3_noun *`. For cells, triples, etc, decompose with
`u3r_cell()`, `u3r_trel()`, etc. For the tagged equivalents, use
`u3r_pq()` and friends.
`u3r_sing(u3_noun a, u3_noun b)` (true if `a` and `b` are a
*single* noun) are interesting because it uses mugs to help it
out. Clearly, different nouns may have the same mug, but the
same nouns cannot have a different mug. It's important to
understand the performance characteristics of `u3r_sing()`:
the worst possible case is a comparison of duplicate nouns,
which have the same value but were created separately. In this
case, the tree is traversed
`u3r_sung()` is a deeply funky and frightening version of
`u3r_sing()` that unifies pointers to the duplicate nouns it
finds, freeing the second copy. Obviously, do not use
`u3r_sung()` when you have live, but not reference counted, noun
references from C - if they match a noun with a refcount of 1
that gets freed, bad things happen.
It's important to remember that `u3r_mug()`, which produces a
31-bit, nonzero insecure hash, uses the `mug_w` slot in any boxed
noun as a lazy cache. There are a number of variants of
`u3r_mug()` that can get you out of building unneeded nouns.
### u3x: reading nouns (bail)
`u3x` functions are like `u3r` functions, but instead of
returning `u3_none` when (for instance) we try to take the head
of an atom, they bail with `%exit`. In other words, they do what
the same operation would do in Nock.
### u3h: hash tables.
We can of course use the Hoon `map` structure as an associative
array. This is a balanced treap and reasonably fast. However,
it's considerably inferior to a custom structure like an HAMT
(hash array-mapped trie). We use `u3_post` to allocate HAMT
structures on the loom.
(Our HAMT implements the classic Bagwell algorithm which depends
on the `gcc` standard directive `__builtin_popcount()`. On a CPU
which doesn't support popcount or an equivalent instruction, some
other design would probably be preferable.)
There's no particular rocket science in the API. `u3h_new()`
creates a hashtable; `u3h_free()` destroys one; `u3h_put()`
inserts, `u3h_get()` retrieves. You can transform values in a
hashtable with `u3h_walk()`.
The only funky function is `u3h_gut()`, which unifies keys with
`u3r_sung()`. As with all cases of `u3r_sung()`, this must be
used with extreme caution.
### u3z: memoization
Connected to the `~+` rune in Hoon, via the Nock `%memo` hint,
the memoization facility is a general-purpose cache.
(It's also used for partial memoization - a feature that'll
probably be removed, in which conservative worklist algorithms
(which would otherwise be exponential) memoize everything in the
subject *except* the worklist. This is used heavily in the Hoon
compiler jets (j/f/*.c). Unfortunately, it's probably not
possible to make this work perfectly in that it can't be abused
to violate Nock, so we'll probably remove it at a later date,
instead making `++ut` keep its own monadic cache.)
Each `u3z` function comes with a `c3_m` mote which disambiguates
the function mapping key to value. For Nock itself, use 0. For
extra speed, small tuples are split out in C; thus, find with
u3_weak u3z_find(c3_m, u3_noun);
u3_weak u3z_find_2(c3_m, u3_noun, u3_noun);
u3_weak u3z_find_3(c3_m, u3_noun, u3_noun, u3_noun);
u3_weak u3z_find_4(c3_m, u3_noun, u3_noun, u3_noun, u3_noun);
and save with
u3_noun u3z_save(c3_m, u3_noun, u3_noun);
u3_noun u3z_save_2(c3_m, u3_noun, u3_noun, u3_noun);
u3_noun u3z_save_3(c3_m, u3_noun, u3_noun, u3_noun, u3_noun);
u3_noun u3z_save_4(c3_m, u3_noun, u3_noun, u3_noun, u3_noun, u3_noun);
where the value is the last argument. To eliminate duplicate
nouns, there is also
u3_noun
u3z_uniq(u3_noun);
`u3z` functions retain keys and transfer values.
The `u3z` cache, built on `u3h` hashes, is part of the current
road, and goes away when it goes away. (In future, we may wish
to promote keys/values which outlive the road, as we do with jet
state.) There is no cache reclamation at present, so be careful.
### u3t: tracing and profiling.
TBD.
### u3v: the Arvo kernel
An Arvo kernel - or at least, a core that compiles with the Arvo
interface - is part of the global `u3` state. What is an Arvo
core? Slightly pseudocoded:
++ arvo
|%
++ come |= [yen=@ ova=(list ovum) nyf=pone] :: 11
^- [(list ovum) _+>]
!!
++ keep |= [now=@da hap=path] :: 4
^- (unit ,@da)
!!
++ load |= [yen=@ ova=(list ovum) nyf=pane] :: 86
^- [(list ovum) _+>]
!!
++ peek |= [now=@da path] :: 87
^- (unit)
!!
++ poke |= [now=@da ovo=ovum] :: 42
^- [(list ovum) _+>]
!!
++ wish |= txt=@ta :: 20
^- *
!!
--
++ card ,[p=@tas q=*] :: typeless card
++ ovum ,[p=wire q=card] :: Arvo event
++ wire path :: event cause
This is the Arvo ABI in a very real sense. Arvo is a core with
these six arms. To use these arms, we hardcode the axis of the
formula (`11`, `4`, `86`, etc) into the C code that calls Arvo,
because otherwise we'd need type metadata - which we can get, by
calling Arvo.
It's important to understand the Arvo event/action structure, or
`++ovum`. An `ovum` is a `card`, which is any `[term noun]`
cell, and a `++wire`, a `path` which indicates the location of
the event. At the Unix level, the `wire` corresponds to a system
module or context. For input events, this is the module that
caused the event; for output actions, it's the module that
performs the action.
`++poke` sends Arvo an event `ovum`, producing a cell of action
ova and a new Arvo core.
`++peek` dereferences the Arvo namespace. It takes a date and a
key, and produces `~` (`0`) or `[~ value]`.
`++keep` asks Arvo the next time it wants to be woken up, for the
given `wire`. (This input will probably be eliminated in favor
of a single global timer.)
`++wish` compiles a string of Hoon source. While just a
convenience, it's a very convenient convenience.
`++come` and `++load` are used by Arvo to reset itself (more
precisely, to shift the Arvo state from an old kernel to a new
one); there is no need to call them from C.
Now that we understand the Arvo kernel interface, let's look at
the `u3v` API. As usual, all the functions in `u3v` are
commented, but unfortunately it's hard to describe this API as
clean at present. The problem is that `u3v` remains design
coupled to the old `vere` event handling code written for `u2`.
But let's describe the functions you should be calling, assuming
you're not writing the next event system. There are only two.
`u3v_wish(str_c)` wraps the `++wish` functionality in a cache
(which is read-only unless you're on the surface road).
`u3v_do()` uses `wish` to provide a convenient interface for
calling Hoon kernel functions by name. Even more conveniently,
we tend to call `u3v_do()` with these convenient aliases:
#define u3do(txt_c, arg) u3v_do(txt_c, arg)
#define u3dc(txt_c, a, b) u3v_do(txt_c, u3nc(a, b))
#define u3dt(txt_c, a, b, c) u3v_do(txt_c, u3nt(a, b, c))
#define u3dq(txt_c, a, b, c, d) u3v_do(txt_c, u3nt(a, b, c, d))
###

View File

@ -207,9 +207,6 @@
# define u3a_into(x) ((void *)(u3_Loom + (x)))
# define u3a_outa(p) (((c3_w*)(void*)(p)) - u3_Loom)
# define u3to(type, x) ((type *) u3a_into(x))
# define u3of(type, x) (u3a_outa((type *)x))
# define u3a_is_north(r) __(r->cap_p > r->hat_p)
# define u3a_is_south(r) !u3a_is_north(r)
@ -369,7 +366,7 @@
/* u3a_sweep(): sweep a fully marked road.
*/
void
u3a_sweep(c3_c* cap_c);
u3a_sweep(void);
/* u3a_sane(): check allocator sanity.
*/
@ -398,7 +395,7 @@
c3_w*
u3a_slab(c3_w len_w);
/* u3a_slaq(): u3a_slaq() with a defined blocksize.
/* u3a_slaq(): u3a_slab() with a defined blocksize.
*/
c3_w*
u3a_slaq(c3_g met_g, c3_w len_w);

15
i/n/e.h
View File

@ -73,21 +73,6 @@
c3_o
u3e_live(c3_o nuu_o, c3_c* dir_c);
/* u3e_boot(): start the u3 system.
*/
void
u3e_boot(c3_o nuu_o, c3_o bug_o, c3_c* dir_c);
/* u3e_init(): start the environment, with/without checkpointing.
*/
void
u3e_init(c3_o chk_o);
/* u3e_grab(): garbage-collect the world, plus extra roots.
*/
void
u3e_grab(c3_c* cap_c, u3_noun som, ...); // terminate with u3_none
/* u3e_dirty(): count dirty pages.
*/
c3_w

View File

@ -81,6 +81,11 @@
u3_noun
u3m_soft_esc(u3_noun sam);
/* u3m_grab(): garbage-collect the world, plus extra roots.
*/
void
u3m_grab(u3_noun som, ...); // terminate with u3_none
/* u3m_water(): produce high and low watermarks. Asserts u3R == u3H.
*/
void

174
i/n/r.h
View File

@ -22,8 +22,7 @@
/* u3r_at(): fragment `a` of `b`, or u3_none.
*/
u3_weak
u3r_at(u3_atom a,
u3_weak b);
u3r_at(u3_atom a, u3_weak b);
/* u3r_mean():
**
@ -31,8 +30,7 @@
** Axes must be sorted in tree order.
*/
c3_o
u3r_mean(u3_noun a,
...);
u3r_mean(u3_noun a, ...);
/* u3r_mug():
**
@ -54,7 +52,7 @@
*/
c3_w
u3r_mug_words(const c3_w *buf_w,
c3_w len_w);
c3_w len_w);
/* u3r_mug_cell():
**
@ -62,7 +60,7 @@
*/
c3_w
u3r_mug_cell(u3_noun a,
u3_noun b);
u3_noun b);
/* u3r_mug_trel():
**
@ -70,8 +68,8 @@
*/
c3_w
u3r_mug_trel(u3_noun a,
u3_noun b,
u3_noun c);
u3_noun b,
u3_noun c);
/* u3r_mug_qual():
**
@ -79,9 +77,9 @@
*/
c3_w
u3r_mug_qual(u3_noun a,
u3_noun b,
u3_noun c,
u3_noun d);
u3_noun b,
u3_noun c,
u3_noun d);
/* u3r_mug_both():
**
@ -98,7 +96,7 @@
*/
c3_o
u3r_fing(u3_noun a,
u3_noun b);
u3_noun b);
/* u3r_fing_cell():
**
@ -106,8 +104,8 @@
*/
c3_o
u3r_fing_cell(u3_noun p,
u3_noun q,
u3_noun b);
u3_noun q,
u3_noun b);
/* u3r_fing_mixt():
**
@ -115,8 +113,8 @@
*/
c3_o
u3r_fing_mixt(const c3_c* p_c,
u3_noun q,
u3_noun b);
u3_noun q,
u3_noun b);
/* u3r_fing_trel():
**
@ -124,9 +122,9 @@
*/
c3_o
u3r_fing_trel(u3_noun p,
u3_noun q,
u3_noun r,
u3_noun b);
u3_noun q,
u3_noun r,
u3_noun b);
/* u3r_fing_qual():
**
@ -134,18 +132,17 @@
*/
c3_o
u3r_fing_qual(u3_noun p,
u3_noun q,
u3_noun r,
u3_noun s,
u3_noun b);
u3_noun q,
u3_noun r,
u3_noun s,
u3_noun b);
/* u3r_sing():
**
** Yes iff (a) and (b) are the same noun.
*/
c3_o
u3r_sing(u3_noun a,
u3_noun b);
u3r_sing(u3_noun a, u3_noun b);
/* u3r_sung(): yes iff (a) and (b) are the same noun, unifying equals.
**
@ -153,8 +150,7 @@
** within (a) or (b)!
*/
c3_o
u3r_sung(u3_noun a,
u3_noun b);
u3r_sung(u3_noun a, u3_noun b);
/* u3r_sing_c):
**
@ -162,7 +158,7 @@
*/
c3_o
u3r_sing_c(const c3_c* a_c,
u3_noun b);
u3_noun b);
/* u3r_sing_cell():
**
@ -170,8 +166,8 @@
*/
c3_o
u3r_sing_cell(u3_noun p,
u3_noun q,
u3_noun b);
u3_noun q,
u3_noun b);
/* u3r_sing_mixt():
**
@ -179,8 +175,8 @@
*/
c3_o
u3r_sing_mixt(const c3_c* p_c,
u3_noun q,
u3_noun b);
u3_noun q,
u3_noun b);
/* u3r_sing_trel():
**
@ -188,9 +184,9 @@
*/
c3_o
u3r_sing_trel(u3_noun p,
u3_noun q,
u3_noun r,
u3_noun b);
u3_noun q,
u3_noun r,
u3_noun b);
/* u3r_sing_qual():
**
@ -198,10 +194,10 @@
*/
c3_o
u3r_sing_qual(u3_noun p,
u3_noun q,
u3_noun r,
u3_noun s,
u3_noun b);
u3_noun q,
u3_noun r,
u3_noun s,
u3_noun b);
/* u3r_nord():
**
@ -209,7 +205,7 @@
*/
u3_atom
u3r_nord(u3_noun a,
u3_noun b);
u3_noun b);
/* u3r_mold():
**
@ -217,8 +213,8 @@
*/
c3_o
u3r_mold(u3_noun a,
u3_noun* b,
u3_noun* c);
u3_noun* b,
u3_noun* c);
/* u3r_cell():
**
@ -226,8 +222,8 @@
*/
c3_o
u3r_cell(u3_noun a,
u3_noun* b,
u3_noun* c);
u3_noun* b,
u3_noun* c);
/* u3r_trel():
**
@ -235,9 +231,9 @@
*/
c3_o
u3r_trel(u3_noun a,
u3_noun* b,
u3_noun* c,
u3_noun* d);
u3_noun* b,
u3_noun* c,
u3_noun* d);
/* u3r_qual():
**
@ -245,10 +241,10 @@
*/
c3_o
u3r_qual(u3_noun a,
u3_noun* b,
u3_noun* c,
u3_noun* d,
u3_noun* e);
u3_noun* b,
u3_noun* c,
u3_noun* d,
u3_noun* e);
/* u3r_quil():
**
@ -256,11 +252,11 @@
*/
c3_o
u3r_quil(u3_noun a,
u3_noun* b,
u3_noun* c,
u3_noun* d,
u3_noun* e,
u3_noun* f);
u3_noun* b,
u3_noun* c,
u3_noun* d,
u3_noun* e,
u3_noun* f);
/* u3r_p():
**
@ -268,8 +264,8 @@
*/
c3_o
u3r_p(u3_noun a,
u3_noun b,
u3_noun* c);
u3_noun b,
u3_noun* c);
/* u3r_bush():
**
@ -277,8 +273,8 @@
*/
c3_o
u3r_bush(u3_noun a,
u3_noun* b,
u3_noun* c);
u3_noun* b,
u3_noun* c);
/* u3r_pq():
**
@ -286,9 +282,9 @@
*/
c3_o
u3r_pq(u3_noun a,
u3_noun b,
u3_noun* c,
u3_noun* d);
u3_noun b,
u3_noun* c,
u3_noun* d);
/* u3r_pqr():
**
@ -296,10 +292,10 @@
*/
c3_o
u3r_pqr(u3_noun a,
u3_noun b,
u3_noun* c,
u3_noun* d,
u3_noun* e);
u3_noun b,
u3_noun* c,
u3_noun* d,
u3_noun* e);
/* u3r_pqrs():
**
@ -307,11 +303,11 @@
*/
c3_o
u3r_pqrs(u3_noun a,
u3_noun b,
u3_noun* c,
u3_noun* d,
u3_noun* e,
u3_noun* f);
u3_noun b,
u3_noun* c,
u3_noun* d,
u3_noun* e,
u3_noun* f);
/* u3r_met():
**
@ -322,7 +318,7 @@
*/
c3_w
u3r_met(c3_y a_y,
u3_atom b);
u3_atom b);
/* u3r_bit():
**
@ -330,7 +326,7 @@
*/
c3_b
u3r_bit(c3_w a_w,
u3_atom b);
u3_atom b);
/* u3r_byte():
**
@ -338,7 +334,7 @@
*/
c3_y
u3r_byte(c3_w a_w,
u3_atom b);
u3_atom b);
/* u3r_bytes():
**
@ -346,9 +342,9 @@
*/
void
u3r_bytes(c3_w a_w,
c3_w b_w,
c3_y* c_y,
u3_atom d);
c3_w b_w,
c3_y* c_y,
u3_atom d);
/* u3r_chop():
**
@ -358,11 +354,11 @@
*/
void
u3r_chop(c3_g met_g,
c3_w fum_w,
c3_w wid_w,
c3_w tou_w,
c3_w* dst_w,
u3_atom src);
c3_w fum_w,
c3_w wid_w,
c3_w tou_w,
c3_w* dst_w,
u3_atom src);
/* u3r_mp():
**
@ -370,7 +366,7 @@
*/
void
u3r_mp(mpz_t a_mp,
u3_atom b);
u3_atom b);
/* u3r_word():
**
@ -378,7 +374,7 @@
*/
c3_w
u3r_word(c3_w a_w,
u3_atom b);
u3_atom b);
/* u3r_chub():
**
@ -386,7 +382,7 @@
*/
c3_d
u3r_chub(c3_w a_w,
u3_atom b);
u3_atom b);
/* u3r_words():
**
@ -394,9 +390,9 @@
*/
void
u3r_words(c3_w a_w,
c3_w b_w,
c3_w* c_w,
u3_atom d);
c3_w b_w,
c3_w* c_w,
u3_atom d);
/* u3r_string(): `a`, a text atom, as malloced C string.
*/

View File

@ -100,3 +100,9 @@
# define u3dc(txt_c, a, b) u3v_do(txt_c, u3nc(a, b))
# define u3dt(txt_c, a, b, c) u3v_do(txt_c, u3nt(a, b, c))
# define u3dq(txt_c, a, b, c, d) u3v_do(txt_c, u3nt(a, b, c, d))
/* u3to(), u3of(): offset/pointer conversion.
*/
# define u3to(type, x) ((type *) u3a_into(x))
# define u3of(type, x) (u3a_outa((type *)x))

12
i/n/v.h
View File

@ -9,10 +9,10 @@
struct _u3v_arvo;
typedef struct _u3v_cart {
u3_noun vir; // effects of ovum
c3_o did; // cart considered for commit?
c3_o cit; // cart committed?
c3_d ent_d; // entry in raft queue?
u3_noun vir; // effects of ovum
c3_o did; // cart considered for commit?
c3_o cit; // cart committed?
c3_d ent_d; // event number
u3p(struct _u3v_cart) nex_p;
} u3v_cart;
@ -34,8 +34,8 @@
u3_noun roc; // kernel core
struct { // ova waiting to process
u3p(u3v_cart) egg_p; // exit of ovum queue
u3p(u3v_cart) geg_p; // entry of ovum queue
u3p(u3v_cart) egg_p; // exit of ovum queue
u3p(u3v_cart) geg_p; // entry of ovum queue
} ova;
} u3v_arvo;

8
n/a.c
View File

@ -1325,7 +1325,7 @@ u3a_print_memory(c3_c* cap_c, c3_w wor_w)
/* u3a_sweep(): sweep a fully marked road.
*/
void
u3a_sweep(c3_c* cap_c)
u3a_sweep(void)
{
c3_w neg_w, pos_w, leq_w, weq_w, tot_w, caf_w;
@ -1493,10 +1493,10 @@ u3a_malt(c3_w* sal_w)
u3_noun
u3a_moot(c3_w* sal_w)
{
c3_w* nov_w = (sal_w - c3_wiseof(u3a_atom));
c3_w* nov_w = (sal_w - c3_wiseof(u3a_atom));
u3a_atom* nov_u = (void*)nov_w;
c3_w len_w = nov_u->len_w;
c3_w las_w = nov_u->buf_w[len_w - 1];
c3_w len_w = nov_u->len_w;
c3_w las_w = nov_u->buf_w[len_w - 1];
c3_assert(0 != len_w);
c3_assert(0 != las_w);

1
n/e.c
View File

@ -881,3 +881,4 @@ u3e_live(c3_o nuu_o, c3_c* dir_c)
}
return nuu_o;
}

60
n/m.c
View File

@ -827,7 +827,7 @@ u3m_soft_top(c3_w sec_w, // timer seconds
/* Make sure the inner routine did not create garbage.
*/
if ( u3R->how.fag_w & u3a_flag_debug ) {
u3e_grab("top", pro, u3_none);
u3m_grab(pro, u3_none);
}
/* Revert to external signal regime.
@ -917,7 +917,7 @@ u3m_soft_run(u3_noun fly,
pro = fun_f(aga, agb);
if ( u3R->how.fag_w & u3a_flag_debug ) {
u3e_grab("top", pro, u3_none);
u3m_grab(pro, u3_none);
}
/* Produce success, on the old road.
@ -1024,6 +1024,34 @@ u3m_soft_esc(u3_noun sam)
return pro;
}
/* u3m_grab(): garbage-collect the world, plus extra roots.
*/
void
u3m_grab(u3_noun som, ...) // terminate with u3_none
{
// u3h_free(u3R->cax.har_p);
// u3R->cax.har_p = u3h_new();
u3v_mark();
u3m_mark();
{
va_list vap;
u3_noun tur;
va_start(vap, som);
if ( som != u3_none ) {
u3a_mark_noun(som);
while ( u3_none != (tur = va_arg(vap, u3_noun)) ) {
u3a_mark_noun(tur);
}
}
va_end(vap);
}
u3a_sweep();
}
/* u3m_soft(): top-level wrapper.
**
** Produces [0 product] or [%error (list tank)], top last.
@ -1372,34 +1400,6 @@ _cm_init(c3_o chk_o)
}
}
/* u3e_grab(): garbage-collect the world, plus extra roots, then
*/
void
u3e_grab(c3_c* cap_c, u3_noun som, ...) // terminate with u3_none
{
// u3h_free(u3R->cax.har_p);
// u3R->cax.har_p = u3h_new();
u3v_mark();
u3m_mark();
{
va_list vap;
u3_noun tur;
va_start(vap, som);
if ( som != u3_none ) {
u3a_mark_noun(som);
while ( u3_none != (tur = va_arg(vap, u3_noun)) ) {
u3a_mark_noun(tur);
}
}
va_end(vap);
}
u3a_sweep(cap_c);
}
/* u3m_boot(): start the u3 system.
*/
void

View File

@ -420,7 +420,7 @@ u3_lo_open(void)
if ( (u3H->rod_u.how.fag_w & u3a_flag_gc) ||
(u3H->rod_u.how.fag_w & u3a_flag_debug) )
{
u3e_grab("lo_open", u3_none);
u3m_grab(u3_none);
}
_lo_time();
}
@ -430,7 +430,7 @@ u3_lo_open(void)
void
u3_lo_shut(c3_o inn)
{
// u3e_grab("lo_shut a", u3_none);
// u3m_grab(u3_none);
// process actions
//