urbit/f/meme.c
2014-08-06 14:03:33 -07:00

443 lines
8.7 KiB
C

/* f/meme.c
**
** This file is in the public domain.
*/
#include "all.h"
#include <sys/uio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sigsegv.h>
#include <termios.h>
#include <uv.h>
#include "v/vere.h"
/* _me_boot_north(): install a north road.
*/
static u2_road*
_me_boot_north(c3_w* mem_w, c3_w len_w)
{
c3_w* rut_w = mem_w;
c3_w* hat_w = rut_w;
c3_w* mat_w = ((mem_w + len_w) - c3_wiseof(u2_road));
c3_w* cap_w = mat_w;
u2_road* rod_u = (void*) mat_w;
memset(rod_u, 0, sizeof(u2_road));
rod_u->rut_w = rut_w;
rod_u->hat_w = hat_w;
rod_u->mat_w = mat_w;
rod_u->cap_w = cap_w;
return rod_u;
}
/* _me_boot_south(): install a south road.
*/
static u2_road*
_me_boot_south(c3_w* mem_w, c3_w len_w)
{
c3_w* rut_w = mem_w;
c3_w* hat_w = rut_w;
c3_w* mat_w = ((mem_w + len_w) - c3_wiseof(u2_road));
c3_w* cap_w = mat_w;
u2_road* rod_u = (void*) mat_w;
memset(rod_u, 0, sizeof(u2_road));
rod_u->rut_w = rut_w;
rod_u->hat_w = hat_w;
rod_u->mat_w = mat_w;
rod_u->cap_w = cap_w;
return rod_u;
}
/* u2_me_boot(): make u2R and u2H from nothing.
*/
void
u2_me_boot(void* mem_v, c3_w len_w)
{
u2H = u2R = _me_boot_north(mem_v, len_w);
}
/* _me_road_all_hat(): in u2R, allocate directly on the hat.
*/
static c3_w*
_me_road_all_hat(c3_w len_w)
{
if ( len_w > u2_me_open ) {
return u2_me_bail(c3__meme);
}
if ( u2_yes == u2_me_is_north ) {
c3_w* all_w;
all_w = u2R->hat;
u2R->hat += len_w;
return all_w;
}
else {
u2R->hat -= len_w;
return u2R->hat;
}
}
/* _me_road_all_cap(): in u2R, allocate directly on the cap.
*/
static c3_w*
_me_road_all_hat(c3_w len_w)
{
if ( len_w > u2_me_open ) {
return u2_me_bail(c3__meme);
}
if ( u2_yes == u2_me_is_north ) {
u2R->cap -= len_w;
return u2R->cap;
}
else {
c3_w* all_w;
all_w = u2R->cap;
u2R->cap += len_w;
return all_w;
}
}
/* u2_me_leap(): in u2R, create a new road within the existing one.
*/
void
u2_me_leap()
{
u2_road* rod_u;
if ( u2_yes == u2_me_is_north ) {
rod_u = _me_boot_south(u2R->hat_w, (u2R->cap_w - u2R->hat_w));
}
else {
rod_u = _me_boot_south(u2R->cap_w, (u2R->hat_w - u2R->cap_w));
}
c3_assert(0 == u2R->kid_u);
rod_u->par_u = u2R;
u2R->kid_u = rod_u;
u2R = rod_u;
}
/* u2_me_fall(): in u2R, return an inner road to its parent.
*/
void
u2_me_fall()
{
c3_assert(0 != u2R->par_u);
u2R->par_u->cap_w = u2R->hat_u;
u2R = u2R->par_u;
}
/* u2_me_golf(): record cap length for u2_flog().
*/
c3_w
u2_me_golf(void)
{
if ( u2_yes == u2_me_is_north ) {
return u2R->mat - u2R->cap;
}
else {
return u2R->cap - u2R->mat;
}
}
/* u2_me_flog(): reset cap.
*/
void
u2_me_flog(c3_w gof_w)
{
if ( u2_yes == u2_me_is_north ) {
u2R->cap = u2R->mat - gof_w;
} else {
u2R->cap = u2R->mat + gof_w;
}
}
/* u2_me_water(): produce watermarks.
*/
void
u2_me_water(c3_w* low_w, c3_w* hig_w);
{
c3_assert(u2R == u2H);
*low_w = (u2H->hat_w - u2H->rut_w);
*hig_w = (u2H->mat_w - u2H->cap_w) + c3_wiseof(u2_road);
}
/* _me_box_slot(): select the right free list to search for a block.
*/
c3_w
_me_box_slot(c3_w siz_w)
{
if ( siz_w < 8 ) {
return 0;
}
else {
c3_w i_w = 1;
while ( 1 ) {
if ( i_w == u2_me_free_no ) {
return (i_w - 1);
}
if ( siz_w < 16 ) {
return i_w;
}
siz_w = (siz_w + 1) >> 1;
i_w += 1;
}
}
}
/* _me_box_make(): construct a box.
*/
u2_me_box*
_me_box_make(c3_v* box_v, c3_w siz_w, c3_w use_w)
{
u2_me_box* box_u = box_v;
c3_w* box_w = box_v;
box_w[0] = siz_w;
box_w[siz_w - 1] = siz_w;
#ifdef U2_MEMORY_DEBUG
box_u->cod_w = COD_w;
#endif
box_u->use_w = use_w;
return box_u;
}
/* _me_box_attach(): attach a box to the free list.
*/
void*
_me_box_attach(u2_me_box* box_u)
{
c3_assert(box_u->siz_w >= (1 + c3_wiseof(u2_me_free)));
{
c3_w sel_w = _me_box_slot(box_u->siz_w);
u2_me_free* fre_u = (void *)box_u;
u2_me_free** pfr_u = &u2R->all.fre_u[sel_w];
fre_u->pre_u = 0;
fre_u->nex_u = (*pfr_u);
(*pfr_u) = fre_u;
}
}
/* u2_me_walloc(): allocate storage words on hat.
*/
void*
u2_me_walloc(c3_w len_w)
{
c3_w siz_w = c3_max(u2_me_minimum, u2_me_boxed(len_w));
c3_w sel_w = _me_box_slot(siz_w);
// XX: this logic is totally bizarre, but preserve it.
//
if ( (sel_w != 0) && (sel_w != u2_me_free_no - 1) ) {
sel_w += 1;
}
while ( 1 ) {
u2_me_free** pfr_u = &u2R->all.fre_u[sel_w];
while ( 1 ) {
if ( 0 == *pfr_u ) {
if ( sel_w < (u2_me_free_no - 1) ) {
sel_w += 1;
break;
}
else {
/* Nothing in top free list. Chip away at the hat.
*/
return u2_me_boxto(_me_box_make(_me_road_all_hat(siz_w), siz_w, 1));
}
}
else {
if ( siz_w > (*pfr_u)->box_u->siz_w ) {
/* This free block is too small. Continue searching.
*/
pfr_u = &((*pfr_u)->nex_u);
continue;
}
else {
u2_me_box* box_u = &((*pfr_u)->box_u);
/* We have found a free block of adequate size. Remove it
** from the free list.
*/
{
{
c3_assert((0 == (*pfr_u)->pre_u) ||
(*pfr_u)->pre_u->nex_u == (*pfr_u));
c3_assert((0 == (*pfr_u)->nex_u) ||
(*pfr_u)->nex_u->pre_u == (*pfr_u));
}
if ( 0 != (*pfr_u)->nex_u ) {
(*pfr_u)->nex_u->pre_u = (*pfr_u)->pre_u;
}
*pfr_u = (*pfr_u)->nex_u;
}
/* If we can chop off another block, do it.
*/
if ( (siz_w + c3_wiseof(u2_me_free) + 1) <= box_u->siz_w ) {
/* Split the block.
*/
c3_w* box_w = ((c3_w *)(void *)box_uy);
c3_w* end_w = box_w + siz_w;
c3_w lef_w = (box_u->siz_w - siz_w);
_me_box_attach(_me_box_make(end_w, lef_w, 0));
return u2_me_boxto(_me_box_make(box_w, siz_w, 1));
}
else {
c3_assert(0 == box_u->use_w);
#ifdef U2_MEMORY_DEBUG
box_u->cod_w = COD_w;
#endif
return u2_me_boxto(box_u);
}
}
}
}
}
/* u2_me_malloc(): allocate storage measured in bytes.
*/
void*
u2_me_malloc(c3_w len_w)
{
return u2_me_walloc((len_w + 3) >> 2);
}
/* u2_me_free(): free storage.
*/
void
u2_me_free(void* tox_v);
{
u2_me_box* box_u = u2_me_botox(tox_v);
/* Clear the contents of the block, for debugging.
*/
{
c3_w i_w;
for ( i_w = c3_wiseof(u2_me_box); (i_w + 1) < box_u->siz_w; i_w++ ) {
((c3_w*)tox_v)[i_w] = 0xdeadbeef;
}
}
if ( ((c3_w*) tox_v) ==
/* Try to coalesce with the previous block.
*/
if ( box_r != beg_r ) {
c3_w las_w = *u2_at_ray(box_r - 1);
u2_ray tod_r = (box_r - las_w);
if ( 0 == u2_rail_hut_use(tod_r) ) {
_rl_bloq_detach(ral_r, tod_r);
_rl_bloq_make(ral_r, tod_r, (las_w + u2_rail_hut_siz(box_r)), 0);
box_r = tod_r;
}
}
/* Try to coalesce with the next block, or with the wilderness.
*/
{
c3_w siz_w = u2_rail_hut_siz(box_r);
if ( (box_r + siz_w == hat_r) ) {
u2_rail_hat_r(ral_r) = box_r;
}
else {
u2_ray hob_r = (box_r + siz_w);
if ( 0 == u2_rail_hut_use(hob_r) ) {
_rl_bloq_detach(ral_r, hob_r);
_rl_bloq_make(ral_r, box_r, (siz_w + u2_rail_hut_siz(hob_r)), 0);
}
/* Add to the appropriate free list.
*/
_rl_bloq_attach(ral_r, box_r);
}
}
}
//////// Atoms from proto-atoms.
/* Basic allocation.
*/
/* u2_me_walloc(): allocate storage measured in words.
*/
void*
u2_me_walloc(c3_w len_w);
/* u2_me_malloc(): allocate storage measured in bytes.
*/
void*
u2_me_malloc(c3_w len_w);
/* u2_me_free(): free storage.
*/
void
u2_me_free(void* lag_v);
/* u2_me_slab(): create a length-bounded proto-atom.
*/
c3_w*
u2_me_slab(c3_w len_w)
{
u2_ray nov_r = u2_rl_ralloc(ral_r, (len_w + c3_wiseof(u2_loom_atom)));
u2_atom nov = u2_pug_of(nov_r, 0);
*u2_at_dog_mug(nov) = 0;
*u2_at_pug_len(nov) = len_w;
/* Clear teh slab.
*/
{
c3_w i_w;
for ( i_w=0; i_w < len_w; i_w++ ) {
*u2_at_pug_buf(nov, i_w) = 0;
}
}
return (nov_r + c3_wiseof(u2_loom_atom));
/* u2_me_slaq(): u2_me_slaq() with a defined blocksize.
*/
c3_w*
u2_me_slaq(c3_g met_g, c3_w len_w);
/* u2_me_malt(): measure and finish a proto-atom.
*/
u2_noun
u2_me_malt(c3_w* sal_w);
/* u2_me_moot(): finish a pre-measured proto-atom; dangerous.
*/
u2_noun
u2_me_moot(c3_w* sal_w);
/* u2_me_mint(): finish a measured proto-atom.
*/
u2_noun
u2_me_mint(c3_w* sal_w, c3_w len_w);