shrub/noun/events.c
Joe Bryan 54bc2c54a5 Merge branch 'master' into cc-release
* master: (50 commits)
  stop snprintfing from a string into itself
  pin arvo version number
  bumped urbit version number
  saves a checkpoint during replay, every 100K events or on failure
  simplifies loom init and checkpoint restore
  - Adds tracing during playback - stop snprintf-ing from one string into another, which is undefined behavior
  reclaim memory every 1k events in live operation or replay
  splits log files between arvo events
  name trace files by urbit date
  automatically split json trace outputs at 100000 line intervals
  stick |mass outputs in mass subdirectory of put
  adds comment about %funk hook in +ut
  adds sha-256 battery hashes to the jet dashboard, corrects axes
  [CI] disables deployment of tagged builds
  removes unused fprintf arg
  [CI] updates pinned arvo commit
  bumps urbit patch number to 0.7.1
  removes obsolete, commented-out gc implementation from loop.c
  moves all vere gc to _raft_grab(), run once after event
  Move _XOPEN_SOURCE #define to include/c/portable.h
  ...
2019-02-06 20:52:44 -05:00

890 lines
19 KiB
C

/* g/e.c
**
*/
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "all.h"
#if 0
/* Image check.
*/
struct {
c3_w nor_w;
c3_w sou_w;
c3_w mug_w[u3a_pages];
} u3K;
/* _ce_check_page(): checksum page.
*/
static c3_w
_ce_check_page(c3_w pag_w)
{
c3_w* mem_w = u3_Loom + (pag_w << u3a_page);
c3_w mug_w = u3r_mug_words(mem_w, (1 << u3a_page));
return mug_w;
}
/* u3e_check(): compute a checksum on all memory within the watermarks.
*/
void
u3e_check(c3_c* cap_c)
{
c3_w nor_w = 0;
c3_w sou_w = 0;
{
c3_w nwr_w, swu_w;
u3m_water(&nwr_w, &swu_w);
nor_w = (nwr_w + ((1 << u3a_page) - 1)) >> u3a_page;
sou_w = (swu_w + ((1 << u3a_page) - 1)) >> u3a_page;
}
/* Count dirty pages.
*/
{
c3_w i_w, sum_w, mug_w;
sum_w = 0;
for ( i_w = 0; i_w < nor_w; i_w++ ) {
mug_w = _ce_check_page(i_w);
if ( strcmp(cap_c, "boot") ) {
c3_assert(mug_w == u3K.mug_w[i_w]);
}
sum_w += mug_w;
}
for ( i_w = 0; i_w < sou_w; i_w++ ) {
mug_w = _ce_check_page((u3a_pages - (i_w + 1)));
if ( strcmp(cap_c, "boot") ) {
c3_assert(mug_w == u3K.mug_w[(u3a_pages - (i_w + 1))]);
}
sum_w += mug_w;
}
printf("%s: sum %x (%x, %x)\r\n", cap_c, sum_w, nor_w, sou_w);
}
}
/* _ce_maplloc(): crude off-loom allocator.
*/
static void*
_ce_maplloc(c3_w len_w)
{
void* map_v;
map_v = mmap(0,
len_w,
(PROT_READ | PROT_WRITE),
(MAP_ANON | MAP_PRIVATE),
-1, 0);
if ( -1 == (c3_ps)map_v ) {
c3_assert(0);
}
else {
c3_w* map_w = map_v;
map_w[0] = len_w;
return map_w + 1;
}
}
/* _ce_mapfree(): crude off-loom allocator.
*/
static void
_ce_mapfree(void* map_v)
{
c3_w* map_w = map_v;
c3_i res_i;
map_w -= 1;
res_i = munmap(map_w, map_w[0]);
c3_assert(0 == res_i);
}
#endif
/* u3e_fault(): handle a memory event with libsigsegv protocol.
*/
c3_i
u3e_fault(void* adr_v, c3_i ser_i)
{
// Let the stack overflow handler run.
if ( 0 == ser_i ) {
return 0;
}
c3_w* adr_w = (c3_w*) adr_v;
if ( (adr_w < u3_Loom) || (adr_w >= (u3_Loom + u3a_words)) ) {
fprintf(stderr, "address %p out of loom!\r\n", adr_v);
fprintf(stderr, "loom: [%p : %p)\r\n", u3_Loom, u3_Loom + u3a_words);
c3_assert(0);
return 0;
}
else {
c3_w off_w = (adr_w - u3_Loom);
c3_w pag_w = off_w >> u3a_page;
c3_w blk_w = (pag_w >> 5);
c3_w bit_w = (pag_w & 31);
#if 0
if ( pag_w == 131041 ) {
printf("dirty page %d (at %p); unprotecting %p to %p\r\n",
pag_w,
adr_v,
(u3_Loom + (pag_w << u3a_page)),
(u3_Loom + (pag_w << u3a_page) + (1 << u3a_page)));
}
#endif
if ( 0 != (u3P.dit_w[blk_w] & (1 << bit_w)) ) {
fprintf(stderr, "strange page: %d, at %p, off %x\r\n",
pag_w, adr_w, off_w);
abort();
}
c3_assert(0 == (u3P.dit_w[blk_w] & (1 << bit_w)));
u3P.dit_w[blk_w] |= (1 << bit_w);
if ( -1 == mprotect((void *)(u3_Loom + (pag_w << u3a_page)),
(1 << (u3a_page + 2)),
(PROT_READ | PROT_WRITE)) )
{
perror("mprotect");
c3_assert(0);
return 0;
}
}
return 1;
}
/* _ce_image_open(): open or create image.
*/
static c3_o
_ce_image_open(u3e_image* img_u)
{
c3_i mod_i = O_RDWR | O_CREAT;
c3_c ful_c[8193];
snprintf(ful_c, 8192, "%s", u3P.dir_c);
mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk", u3P.dir_c);
mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk/%s.bin", u3P.dir_c, img_u->nam_c);
if ( -1 == (img_u->fid_i = open(ful_c, mod_i, 0666)) ) {
perror(ful_c);
return c3n;
}
else {
struct stat buf_u;
if ( -1 == fstat(img_u->fid_i, &buf_u) ) {
perror(ful_c);
c3_assert(0);
return c3n;
}
else {
c3_d siz_d = buf_u.st_size;
c3_d pgs_d = (siz_d + (c3_d)((1 << (u3a_page + 2)) - 1)) >>
(c3_d)(u3a_page + 2);
if ( !siz_d ) {
return c3y;
}
else {
if ( siz_d != (pgs_d << (c3_d)(u3a_page + 2)) ) {
fprintf(stderr, "%s: corrupt size %" PRIx64 "\r\n", ful_c, siz_d);
return c3n;
}
img_u->pgs_w = (c3_w) pgs_d;
c3_assert(pgs_d == (c3_d)img_u->pgs_w);
return c3y;
}
}
}
}
/* _ce_patch_write_control(): write control block file.
*/
static void
_ce_patch_write_control(u3_ce_patch* pat_u)
{
c3_w len_w = sizeof(u3e_control) +
(pat_u->con_u->pgs_w * sizeof(u3e_line));
if ( len_w != write(pat_u->ctl_i, pat_u->con_u, len_w) ) {
c3_assert(0);
}
}
/* _ce_patch_read_control(): read control block file.
*/
static c3_o
_ce_patch_read_control(u3_ce_patch* pat_u)
{
c3_w len_w;
c3_assert(0 == pat_u->con_u);
{
struct stat buf_u;
if ( -1 == fstat(pat_u->ctl_i, &buf_u) ) {
c3_assert(0);
return c3n;
}
len_w = (c3_w) buf_u.st_size;
}
pat_u->con_u = malloc(len_w);
if ( (len_w != read(pat_u->ctl_i, pat_u->con_u, len_w)) ||
(len_w != sizeof(u3e_control) +
(pat_u->con_u->pgs_w * sizeof(u3e_line))) )
{
free(pat_u->con_u);
pat_u->con_u = 0;
return c3n;
}
return c3y;
}
/* _ce_patch_create(): create patch files.
*/
static void
_ce_patch_create(u3_ce_patch* pat_u)
{
c3_c ful_c[8193];
snprintf(ful_c, 8192, "%s", u3P.dir_c);
mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
if ( -1 == (pat_u->ctl_i = open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
perror(ful_c);
c3_assert(0);
}
snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
if ( -1 == (pat_u->mem_i = open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
perror(ful_c);
c3_assert(0);
}
}
/* _ce_patch_delete(): delete a patch.
*/
static void
_ce_patch_delete(void)
{
c3_c ful_c[8193];
snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
unlink(ful_c);
snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
unlink(ful_c);
}
/* _ce_patch_verify(): check patch data mug.
*/
static c3_o
_ce_patch_verify(u3_ce_patch* pat_u)
{
c3_w i_w;
for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) {
c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w;
c3_w mug_w = pat_u->con_u->mem_u[i_w].mug_w;
c3_w mem_w[1 << u3a_page];
if ( -1 == lseek(pat_u->mem_i, (i_w << (u3a_page + 2)), SEEK_SET) ) {
perror("seek");
c3_assert(0);
return c3n;
}
if ( -1 == read(pat_u->mem_i, mem_w, (1 << (u3a_page + 2))) ) {
perror("read");
c3_assert(0);
return c3n;
}
{
c3_w nug_w = u3r_mug_words(mem_w, (1 << u3a_page));
if ( mug_w != nug_w ) {
printf("_ce_patch_verify: mug mismatch %d/%d; (%x, %x)\r\n",
pag_w, i_w, mug_w, nug_w);
c3_assert(0);
return c3n;
}
#if 0
else {
printf("verify: patch %d/%d, %x\r\n", pag_w, i_w, mug_w);
}
#endif
}
}
return c3y;
}
/* _ce_patch_free(): free a patch.
*/
static void
_ce_patch_free(u3_ce_patch* pat_u)
{
free(pat_u->con_u);
close(pat_u->ctl_i);
close(pat_u->mem_i);
free(pat_u);
}
/* _ce_patch_open(): open patch, if any.
*/
static u3_ce_patch*
_ce_patch_open(void)
{
u3_ce_patch* pat_u;
c3_c ful_c[8193];
c3_i ctl_i, mem_i;
snprintf(ful_c, 8192, "%s", u3P.dir_c);
mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
if ( -1 == (ctl_i = open(ful_c, O_RDWR)) ) {
return 0;
}
snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
if ( -1 == (mem_i = open(ful_c, O_RDWR)) ) {
close(ctl_i);
_ce_patch_delete();
return 0;
}
pat_u = malloc(sizeof(u3_ce_patch));
pat_u->ctl_i = ctl_i;
pat_u->mem_i = mem_i;
pat_u->con_u = 0;
if ( c3n == _ce_patch_read_control(pat_u) ) {
close(pat_u->ctl_i);
close(pat_u->mem_i);
free(pat_u);
_ce_patch_delete();
return 0;
}
if ( c3n == _ce_patch_verify(pat_u) ) {
_ce_patch_free(pat_u);
_ce_patch_delete();
return 0;
}
return pat_u;
}
/* _ce_patch_write_page(): write a page of patch memory.
*/
static void
_ce_patch_write_page(u3_ce_patch* pat_u,
c3_w pgc_w,
c3_w* mem_w)
{
if ( -1 == lseek(pat_u->mem_i, (pgc_w << (u3a_page + 2)), SEEK_SET) ) {
c3_assert(0);
}
if ( (1 << (u3a_page + 2)) !=
write(pat_u->mem_i, mem_w, (1 << (u3a_page + 2))) )
{
c3_assert(0);
}
}
/* _ce_patch_count_page(): count a page, producing new counter.
*/
static c3_w
_ce_patch_count_page(c3_w pag_w,
c3_w pgc_w)
{
c3_w blk_w = (pag_w >> 5);
c3_w bit_w = (pag_w & 31);
if ( u3P.dit_w[blk_w] & (1 << bit_w) ) {
pgc_w += 1;
}
return pgc_w;
}
/* _ce_patch_save_page(): save a page, producing new page counter.
*/
static c3_w
_ce_patch_save_page(u3_ce_patch* pat_u,
c3_w pag_w,
c3_w pgc_w)
{
c3_w blk_w = (pag_w >> 5);
c3_w bit_w = (pag_w & 31);
if ( u3P.dit_w[blk_w] & (1 << bit_w) ) {
c3_w* mem_w = u3_Loom + (pag_w << u3a_page);
pat_u->con_u->mem_u[pgc_w].pag_w = pag_w;
pat_u->con_u->mem_u[pgc_w].mug_w = u3r_mug_words(mem_w,
(1 << u3a_page));
#if 0
printf("protect a: page %d\r\n", pag_w);
#endif
_ce_patch_write_page(pat_u, pgc_w, mem_w);
if ( -1 == mprotect(u3_Loom + (pag_w << u3a_page),
(1 << (u3a_page + 2)),
PROT_READ) )
{
c3_assert(0);
}
u3P.dit_w[blk_w] &= ~(1 << bit_w);
pgc_w += 1;
}
return pgc_w;
}
/* _ce_patch_junk_page(): mark a page as junk.
*/
static void
_ce_patch_junk_page(u3_ce_patch* pat_u,
c3_w pag_w)
{
c3_w blk_w = (pag_w >> 5);
c3_w bit_w = (pag_w & 31);
// printf("protect b: page %d\r\n", pag_w);
if ( -1 == mprotect(u3_Loom + (pag_w << u3a_page),
(1 << (u3a_page + 2)),
PROT_READ) )
{
c3_assert(0);
}
u3P.dit_w[blk_w] &= ~(1 << bit_w);
}
/* u3e_dirty(): count dirty pages.
*/
c3_w
u3e_dirty(void)
{
c3_w pgs_w = 0;
c3_w nor_w = 0;
c3_w sou_w = 0;
/* Calculate number of saved pages, north and south.
*/
{
c3_w nwr_w, swu_w;
u3m_water(&nwr_w, &swu_w);
nor_w = (nwr_w + ((1 << u3a_page) - 1)) >> u3a_page;
sou_w = (swu_w + ((1 << u3a_page) - 1)) >> u3a_page;
}
// u3K.nor_w = nor_w;
// u3K.sou_w = sou_w;
/* Count dirty pages.
*/
{
c3_w i_w;
for ( i_w = 0; i_w < nor_w; i_w++ ) {
pgs_w = _ce_patch_count_page(i_w, pgs_w);
}
for ( i_w = 0; i_w < sou_w; i_w++ ) {
pgs_w = _ce_patch_count_page((u3a_pages - (i_w + 1)), pgs_w);
}
}
return pgs_w;
}
/* _ce_patch_compose(): make and write current patch.
*/
static u3_ce_patch*
_ce_patch_compose(void)
{
c3_w pgs_w = 0;
c3_w nor_w = 0;
c3_w sou_w = 0;
/* Calculate number of saved pages, north and south.
*/
{
c3_w nwr_w, swu_w;
u3m_water(&nwr_w, &swu_w);
nor_w = (nwr_w + ((1 << u3a_page) - 1)) >> u3a_page;
sou_w = (swu_w + ((1 << u3a_page) - 1)) >> u3a_page;
}
// u3K.nor_w = nor_w;
// u3K.sou_w = sou_w;
/* Count dirty pages.
*/
{
c3_w i_w;
for ( i_w = 0; i_w < nor_w; i_w++ ) {
pgs_w = _ce_patch_count_page(i_w, pgs_w);
}
for ( i_w = 0; i_w < sou_w; i_w++ ) {
pgs_w = _ce_patch_count_page((u3a_pages - (i_w + 1)), pgs_w);
}
}
if ( !pgs_w ) {
return 0;
}
else {
u3_ce_patch* pat_u = malloc(sizeof(u3_ce_patch));
c3_w i_w, pgc_w;
_ce_patch_create(pat_u);
pat_u->con_u = malloc(sizeof(u3e_control) + (pgs_w * sizeof(u3e_line)));
pgc_w = 0;
for ( i_w = 0; i_w < nor_w; i_w++ ) {
pgc_w = _ce_patch_save_page(pat_u, i_w, pgc_w);
}
for ( i_w = 0; i_w < sou_w; i_w++ ) {
pgc_w = _ce_patch_save_page(pat_u, (u3a_pages - (i_w + 1)), pgc_w);
}
for ( i_w = nor_w; i_w < (u3a_pages - sou_w); i_w++ ) {
_ce_patch_junk_page(pat_u, i_w);
}
pat_u->con_u->nor_w = nor_w;
pat_u->con_u->sou_w = sou_w;
pat_u->con_u->pgs_w = pgc_w;
_ce_patch_write_control(pat_u);
return pat_u;
}
}
/* _ce_sync(): sync a file descriptor.
*/
static void
_ce_sync(c3_i fid_i)
{
#if defined(U3_OS_linux)
fdatasync(fid_i);
#elif defined(U3_OS_osx)
fcntl(fid_i, F_FULLFSYNC);
#elif defined(U3_OS_bsd)
fsync(fid_i);
#else
# error "port: datasync"
#endif
}
/* _ce_patch_sync(): make sure patch is synced to disk.
*/
static void
_ce_patch_sync(u3_ce_patch* pat_u)
{
_ce_sync(pat_u->ctl_i);
_ce_sync(pat_u->mem_i);
}
/* _ce_image_sync(): make sure image is synced to disk.
*/
static void
_ce_image_sync(u3e_image* img_u)
{
_ce_sync(img_u->fid_i);
}
/* _ce_patch_apply(): apply patch to image.
*/
static void
_ce_patch_apply(u3_ce_patch* pat_u)
{
c3_w i_w;
//printf("image: nor_w %d, new %d\r\n", u3P.nor_u.pgs_w, pat_u->con_u->nor_w);
//printf("image: sou_w %d, new %d\r\n", u3P.sou_u.pgs_w, pat_u->con_u->sou_w);
if ( u3P.nor_u.pgs_w > pat_u->con_u->nor_w ) {
ftruncate(u3P.nor_u.fid_i, u3P.nor_u.pgs_w << (u3a_page + 2));
}
u3P.nor_u.pgs_w = pat_u->con_u->nor_w;
if ( u3P.sou_u.pgs_w > pat_u->con_u->sou_w ) {
ftruncate(u3P.sou_u.fid_i, u3P.sou_u.pgs_w << (u3a_page + 2));
}
u3P.sou_u.pgs_w = pat_u->con_u->sou_w;
if ( (-1 == lseek(pat_u->mem_i, 0, SEEK_SET)) ||
(-1 == lseek(u3P.nor_u.fid_i, 0, SEEK_SET)) ||
(-1 == lseek(u3P.sou_u.fid_i, 0, SEEK_SET)) )
{
perror("apply: seek");
c3_assert(0);
}
for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) {
c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w;
c3_w mem_w[1 << u3a_page];
c3_i fid_i;
c3_w off_w;
if ( pag_w < pat_u->con_u->nor_w ) {
fid_i = u3P.nor_u.fid_i;
off_w = pag_w;
}
else {
fid_i = u3P.sou_u.fid_i;
off_w = (u3a_pages - (pag_w + 1));
}
if ( -1 == read(pat_u->mem_i, mem_w, (1 << (u3a_page + 2))) ) {
perror("apply: read");
c3_assert(0);
}
else {
if ( -1 == lseek(fid_i, (off_w << (u3a_page + 2)), SEEK_SET) ) {
perror("apply: lseek");
c3_assert(0);
}
if ( -1 == write(fid_i, mem_w, (1 << (u3a_page + 2))) ) {
perror("apply: write");
c3_assert(0);
}
}
#if 0
printf("apply: %d, %x\n", pag_w, u3r_mug_words(mem_w, (1 << u3a_page)));
#endif
}
}
/* _ce_image_blit(): apply image to memory.
*/
static void
_ce_image_blit(u3e_image* img_u,
c3_w* ptr_w,
c3_ws stp_ws)
{
c3_w i_w;
lseek(img_u->fid_i, 0, SEEK_SET);
for ( i_w=0; i_w < img_u->pgs_w; i_w++ ) {
if ( -1 == read(img_u->fid_i, ptr_w, (1 << (u3a_page + 2))) ) {
perror("read");
c3_assert(0);
}
#if 0
{
c3_w off_w = (ptr_w - u3_Loom);
c3_w pag_w = (off_w >> u3a_page);
printf("blit: page %d, mug %x\r\n", pag_w,
u3r_mug_words(ptr_w, (1 << u3a_page)));
}
#endif
ptr_w += stp_ws;
}
}
#if 0
/* _ce_image_fine(): compare image to memory.
*/
static void
_ce_image_fine(u3e_image* img_u,
c3_w* ptr_w,
c3_ws stp_ws)
{
c3_w i_w;
c3_w buf_w[1 << u3a_page];
lseek(img_u->fid_i, 0, SEEK_SET);
for ( i_w=0; i_w < img_u->pgs_w; i_w++ ) {
c3_w mem_w, fil_w;
if ( -1 == read(img_u->fid_i, buf_w, (1 << (u3a_page + 2))) ) {
perror("read");
c3_assert(0);
}
mem_w = u3r_mug_words(ptr_w, (1 << u3a_page));
fil_w = u3r_mug_words(buf_w, (1 << u3a_page));
if ( mem_w != fil_w ) {
c3_w pag_w = (ptr_w - u3_Loom) >> u3a_page;
fprintf(stderr, "mismatch: page %d, mem_w %x, fil_w %x, K %x\r\n",
pag_w,
mem_w,
fil_w,
u3K.mug_w[pag_w]);
abort();
}
ptr_w += stp_ws;
}
}
#endif
/* u3e_save(): save current changes.
*/
void
u3e_save(void)
{
u3_ce_patch* pat_u;
// In dry-run mode, we never touch this stuff.
//
if ( u3C.wag_w & u3o_dryrun ) {
return;
}
// Write all dirty pages to disk; clear protection and dirty bits.
//
// This has to block the main thread. All further processing can happen
// in a separate thread, though we can't save again till this completes.
//
if ( !(pat_u = _ce_patch_compose()) ) {
return;
}
// Sync the patch files.
//
// u3a_print_memory(stderr, "sync: save", 4096 * pat_u->con_u->pgs_w);
_ce_patch_sync(pat_u);
// Verify the patch - because why not?
//
// printf("_ce_patch_verify\r\n");
_ce_patch_verify(pat_u);
// Write the patch data into the image file. Idempotent.
//
// printf("_ce_patch_apply\r\n");
_ce_patch_apply(pat_u);
#if 0
{
_ce_image_fine(&u3P.nor_u,
u3_Loom,
(1 << u3a_page));
_ce_image_fine(&u3P.sou_u,
(u3_Loom + (1 << u3a_bits) - (1 << u3a_page)),
-(1 << u3a_page));
c3_assert(u3P.nor_u.pgs_w == u3K.nor_w);
c3_assert(u3P.sou_u.pgs_w == u3K.sou_w);
}
#endif
// Sync the image file.
//
// printf("_ce_image_sync\r\n");
_ce_image_sync(&u3P.nor_u);
_ce_image_sync(&u3P.sou_u);
// Delete the patchfile and free it.
//
// printf("_ce_patch_delete\r\n");
_ce_patch_delete();
// printf("_ce_patch_free\r\n");
_ce_patch_free(pat_u);
}
/* u3e_live(): start the checkpointing system.
*/
c3_o
u3e_live(c3_o nuu_o, c3_c* dir_c)
{
u3P.dir_c = dir_c;
u3P.nor_u.nam_c = "north";
u3P.sou_u.nam_c = "south";
#if 0
if ( u3C.wag_w & u3o_dryrun ) {
return c3y;
} else
#endif
{
// Open image files.
//
if ( (c3n == _ce_image_open(&u3P.nor_u)) ||
(c3n == _ce_image_open(&u3P.sou_u)) )
{
printf("boot: image failed\r\n");
exit(1);
}
else {
u3_ce_patch* pat_u;
/* Load any patch files; apply them to images.
*/
if ( 0 != (pat_u = _ce_patch_open()) ) {
printf("boot: _ce_patch_apply\r\n");
_ce_patch_apply(pat_u);
printf("boot: _ce_image_sync\r\n");
_ce_image_sync(&u3P.nor_u);
_ce_image_sync(&u3P.sou_u);
printf("boot: _ce_patch_delete\r\n");
_ce_patch_delete();
printf("boot: _ce_patch_free\r\n");
_ce_patch_free(pat_u);
}
/* Write image files to memory; reinstate protection.
*/
{
_ce_image_blit(&u3P.nor_u,
u3_Loom,
(1 << u3a_page));
_ce_image_blit(&u3P.sou_u,
(u3_Loom + (1 << u3a_bits) - (1 << u3a_page)),
-(1 << u3a_page));
if ( 0 != mprotect((void *)u3_Loom, u3a_bytes, PROT_READ) ) {
perror("protect");
c3_assert(0);
}
printf("boot: protected loom\r\n");
}
/* If the images were empty, we are logically booting.
*/
if ( (0 == u3P.nor_u.pgs_w) && (0 == u3P.sou_u.pgs_w) ) {
printf("live: logical boot\r\n");
nuu_o = c3y;
}
else {
u3a_print_memory(stderr, "live: loaded",
(u3P.nor_u.pgs_w + u3P.sou_u.pgs_w) << u3a_page);
}
}
}
return nuu_o;
}