Merge pull request #6171 from urbit/jb/release/vere

1.14 Vere Release
This commit is contained in:
Joe Bryan 2022-12-16 23:09:01 -05:00 committed by GitHub
commit 21f7023198
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 2707 additions and 985 deletions

View File

@ -23,12 +23,13 @@ jobs:
name: ${{ secrets.CACHIX_NAME }}
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- uses: google-github-actions/setup-gcloud@v0.2.0
- uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- uses: google-github-actions/setup-gcloud@v1
with:
version: '290.0.1'
service_account_key: ${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}
project_id: ${{ secrets.GCS_PROJECT }}
export_default_credentials: true
- run: nix-build -A tarball --arg enableStatic true

View File

@ -125,13 +125,14 @@ jobs:
echo -n "$version" > ./version-string
- name: upload version string artifact
if: matrix.type == 'linux'
if: inputs.upload && matrix.type == 'linux'
uses: actions/upload-artifact@v3
with:
name: version-string
path: version-string
- uses: google-github-actions/auth@v1
if: inputs.upload
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
@ -244,12 +245,13 @@ jobs:
needs: [urbit, mingw]
if: inputs.upload
steps:
- uses: google-github-actions/setup-gcloud@v0.2.0
- uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- uses: google-github-actions/setup-gcloud@v1
with:
version: '290.0.1'
service_account_key: ${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}
project_id: ${{ secrets.GCS_PROJECT }}
export_default_credentials: true
- name: download version-string
uses: actions/download-artifact@v3

View File

@ -2,6 +2,7 @@ include config.mk
compat_mks := $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.mk))
include $(compat_mks)
c = $(wildcard c/*.c)
jets = jets/tree.c $(wildcard jets/*/*.c)
noun = $(wildcard noun/*.c)
ur = $(wildcard ur/*.c)
@ -13,7 +14,7 @@ bench = $(wildcard bench/*.c)
compat := $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.c))
common = $(jets) $(noun) $(ur) $(vere) $(compat)
common = $(c) $(jets) $(noun) $(ur) $(vere) $(compat)
headers = $(shell find include -type f)
common_objs = $(shell echo $(common) | sed 's/\.c/.o/g')

View File

@ -7,9 +7,7 @@
static void
_setup(void)
{
u3m_init(1 << 24);
u3m_pave(c3y);
u3e_init();
u3m_boot_lite(1 << 24);
}
/* _ames_writ_ex(): |hi packet from fake ~zod to fake ~nec

96
pkg/urbit/c/defs.c Normal file
View File

@ -0,0 +1,96 @@
/// @file defs.c
#include "c/defs.h"
/* c3_pread(): full positioned read(), up to eof, retrying errors.
*/
ssize_t
c3_pread(c3_i fid_i, void* buf_v, size_t len_i, off_t off_i)
{
c3_w max_w = 128;
c3_w try_w = 0;
size_t rem_i = len_i;
ssize_t ret_i;
do {
if ( (0 > (ret_i = pread(fid_i, buf_v, rem_i, off_i)))
&& ( (++try_w == max_w)
|| ( (EINTR != errno)
&& (EAGAIN != errno)
&& (EWOULDBLOCK != errno) )))
{
return -1;
}
else if ( 0 == ret_i ) {
break;
}
else {
buf_v = (void*)((c3_c*)buf_v + ret_i);
rem_i -= ret_i;
off_i += ret_i;
}
}
while ( rem_i );
return len_i - rem_i;
}
/* c3_pwrite(): full positioned write(), retrying errors.
*/
ssize_t
c3_pwrite(c3_i fid_i, const void* buf_v, size_t len_i, off_t off_i)
{
c3_w max_w = 128;
c3_w try_w = 0;
size_t rem_i = len_i;
ssize_t ret_i;
do {
if ( (0 > (ret_i = pwrite(fid_i, buf_v, rem_i, off_i)))
&& ( (++try_w == max_w)
|| ( (EINTR != errno)
&& (EAGAIN != errno)
&& (EWOULDBLOCK != errno) )))
{
return -1;
}
else {
buf_v = (void*)((c3_c*)buf_v + ret_i);
rem_i -= ret_i;
off_i += ret_i;
}
}
while ( rem_i );
return len_i;
}
/* c3_write(): full write(), retrying errors.
*/
ssize_t
c3_write(c3_i fid_i, const void* buf_v, size_t len_i)
{
c3_w max_w = 128;
c3_w try_w = 0;
size_t rem_i = len_i;
ssize_t ret_i;
do {
if ( (0 > (ret_i = write(fid_i, buf_v, rem_i)))
&& ( (++try_w == max_w)
|| ( (EINTR != errno)
&& (EAGAIN != errno)
&& (EWOULDBLOCK != errno) )))
{
return -1;
}
else {
buf_v = (void*)((c3_c*)buf_v + ret_i);
rem_i -= ret_i;
}
}
while ( rem_i );
return len_i;
}

View File

@ -144,6 +144,63 @@ int link(const char *path1, const char *path2)
return -1;
}
ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
DWORD len = 0;
OVERLAPPED overlapped = {0};
overlapped.OffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((offset >> 32) & 0xFFFFFFFFL);
overlapped.Offset = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)offset : (DWORD)(offset & 0xFFFFFFFFL);
HANDLE h = (HANDLE)_get_osfhandle(fd);
if ( INVALID_HANDLE_VALUE == h ) {
errno = EBADF;
return -1;
}
if ( !ReadFile(h, buf, count, &len, &overlapped) ) {
DWORD err = GetLastError();
if ( ERROR_HANDLE_EOF != err ) {
errno = err_win_to_posix(err);
return -1;
}
}
return (ssize_t)len;
}
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
{
DWORD len = 0;
OVERLAPPED overlapped = {0};
overlapped.OffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((offset >> 32) & 0xFFFFFFFFL);
overlapped.Offset = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)offset : (DWORD)(offset & 0xFFFFFFFFL);
HANDLE h = (HANDLE)_get_osfhandle(fd);
if ( INVALID_HANDLE_VALUE == h ) {
errno = EBADF;
return -1;
}
if ( !WriteFile(h, buf, count, &len, &overlapped) ) {
errno = err_win_to_posix(GetLastError());
return -1;
}
return (ssize_t)len;
}
// from msys2 mingw-packages-dev patches
// -----------------------------------------------------------------------

View File

@ -4,6 +4,8 @@
#define mkdir(A, B) mkdir(A)
int link(const char *path1, const char *path2);
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
char *realpath(const char *path, char *resolved_path);
int fdatasync(int fd);
int utimes(const char *path, const struct timeval times[2]);

View File

@ -12,7 +12,7 @@ EXCEPTION_DISPOSITION _mingw_exception_filter(
{
if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
ExceptionRecord->ExceptionInformation[0] == 1 &&
u3e_fault((void*)ExceptionRecord->ExceptionInformation[1], 1))
u3m_fault((void*)ExceptionRecord->ExceptionInformation[1], 1))
{
return ExceptionContinueExecution;
}

View File

@ -9,6 +9,8 @@
#include "rsignal.h"
#include <vere/serf.h>
#include "vere/vere.h"
#include "vere/mars.h"
#include "noun/events.h"
#if !defined(U3_OS_mingw)
#include <sigsegv.h>
#endif
@ -153,6 +155,15 @@ _main_init(void)
//
u3_Host.ops_u.has = c3y;
// demand paging (ie, file-backed mapping for the loom)
// is not yet supported on windows
//
#ifdef U3_OS_mingw
u3_Host.ops_u.map = c3n;
#else
u3_Host.ops_u.map = c3y;
#endif
u3_Host.ops_u.net = c3y;
u3_Host.ops_u.lit = c3n;
u3_Host.ops_u.nuu = c3n;
@ -246,6 +257,7 @@ _main_getopt(c3_i argc, c3_c** argv)
{ "scry-format", required_argument, NULL, 'Z' },
//
{ "urth-loom", required_argument, NULL, 5 },
{ "no-demand", no_argument, NULL, 6 },
//
{ NULL, 0, NULL, 0 },
};
@ -266,6 +278,10 @@ _main_getopt(c3_i argc, c3_c** argv)
u3_Host.ops_u.lut_y = lut_w;
break;
}
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
break;
}
case 'X': {
u3_Host.ops_u.pek_c = strdup(optarg);
break;
@ -630,14 +646,17 @@ _cw_usage(c3_c* bin_c)
"utilities:\n",
" %s cram %.*s jam state:\n",
" %s dock %.*s copy binary:\n",
" %s eval %.*s eval hoon:\n",
" %s grab %.*s measure memory usage:\n",
" %s info %.*s print pier info:\n",
" %s meld %.*s deduplicate snapshot:\n",
" %s pack %.*s defragment snapshot:\n",
" %s play %.*s recompute events:\n",
" %s prep %.*s prepare for upgrade:\n",
" %s next %.*s request upgrade:\n",
" %s queu %.*s<at-event> cue state:\n",
" %s vere ARGS <output dir> download binary:\n",
" %s vile %.*s print keyfile:\n",
"\n run as a 'serf':\n",
" %s serf <pier> <key> <flags> <cache-size> <at-event>"
#ifdef U3_OS_mingw
@ -1372,7 +1391,8 @@ _cw_cram(c3_i argc, c3_c* argv[])
c3_w arg_w;
static struct option lop_u[] = {
{ "loom", required_argument, NULL, c3__loom },
{ "loom", required_argument, NULL, c3__loom },
{ "no-demand", no_argument, NULL, 6 },
{ NULL, 0, NULL, 0 }
};
@ -1380,6 +1400,11 @@ _cw_cram(c3_i argc, c3_c* argv[])
while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) {
switch ( ch_i ) {
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
@ -1432,7 +1457,7 @@ _cw_cram(c3_i argc, c3_c* argv[])
// save even on failure, as we just did all the work of deduplication
//
u3e_save();
u3m_save();
u3_disk_exit(log_u);
if ( c3n == ret_o ) {
@ -1447,18 +1472,26 @@ _cw_cram(c3_i argc, c3_c* argv[])
static void
_cw_queu(c3_i argc, c3_c* argv[])
{
c3_i ch_i, lid_i;
c3_w arg_w;
c3_i ch_i, lid_i;
c3_w arg_w;
c3_c* roc_c = 0;
static struct option lop_u[] = {
{ "loom", required_argument, NULL, c3__loom },
{ "loom", required_argument, NULL, c3__loom },
{ "no-demand", no_argument, NULL, 6 },
{ "replay-from", required_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
u3_Host.dir_c = _main_pier_run(argv[0]);
while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) {
while ( -1 != (ch_i=getopt_long(argc, argv, "r:", lop_u, &lid_i)) ) {
switch ( ch_i ) {
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
@ -1469,6 +1502,10 @@ _cw_queu(c3_i argc, c3_c* argv[])
u3_Host.ops_u.lom_y = lom_w;
} break;
case 'r': {
roc_c = strdup(optarg);
} break;
case '?': {
fprintf(stderr, "invalid argument\r\n");
exit(1);
@ -1476,9 +1513,13 @@ _cw_queu(c3_i argc, c3_c* argv[])
}
}
if ( !roc_c ) {
fprintf(stderr, "invalid command, -r $EVENT required\r\n");
exit(1);
}
// argv[optind] is always "queu"
//
if ( !u3_Host.dir_c ) {
if ( optind + 1 < argc ) {
u3_Host.dir_c = argv[optind + 1];
@ -1496,11 +1537,10 @@ _cw_queu(c3_i argc, c3_c* argv[])
exit(1);
}
c3_c* eve_c;
c3_d eve_d;
c3_d eve_d;
if ( 1 != sscanf(eve_c, "%" PRIu64 "", &eve_d) ) {
fprintf(stderr, "urbit: queu: invalid number '%s'\r\n", eve_c);
if ( 1 != sscanf(roc_c, "%" PRIu64 "", &eve_d) ) {
fprintf(stderr, "urbit: queu: invalid number '%s'\r\n", roc_c);
exit(1);
}
else {
@ -1519,7 +1559,7 @@ _cw_queu(c3_i argc, c3_c* argv[])
exit(1);
}
u3e_save();
u3m_save();
u3_disk_exit(log_u);
fprintf(stderr, "urbit: queu: rock loaded at event %" PRIu64 "\r\n", eve_d);
@ -1536,7 +1576,8 @@ _cw_meld(c3_i argc, c3_c* argv[])
c3_w arg_w;
static struct option lop_u[] = {
{ "loom", required_argument, NULL, c3__loom },
{ "loom", required_argument, NULL, c3__loom },
{ "no-demand", no_argument, NULL, 6 },
{ NULL, 0, NULL, 0 }
};
@ -1544,6 +1585,11 @@ _cw_meld(c3_i argc, c3_c* argv[])
while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) {
switch ( ch_i ) {
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
@ -1587,11 +1633,9 @@ _cw_meld(c3_i argc, c3_c* argv[])
u3C.wag_w |= u3o_hashless;
u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y);
pre_w = u3a_open(u3R);
u3u_meld();
u3a_print_memory(stderr, "urbit: meld: gained", (u3a_open(u3R) - pre_w));
u3a_print_memory(stderr, "urbit: meld: gained", u3u_meld());
u3e_save();
u3m_save();
u3_disk_exit(log_u);
u3m_stop();
}
@ -1605,8 +1649,9 @@ _cw_next(c3_i argc, c3_c* argv[])
c3_w arg_w;
static struct option lop_u[] = {
{ "arch", required_argument, NULL, 'a' },
{ "loom", required_argument, NULL, c3__loom },
{ "arch", required_argument, NULL, 'a' },
{ "loom", required_argument, NULL, c3__loom },
{ "no-demand", no_argument, NULL, 6 },
{ NULL, 0, NULL, 0 }
};
@ -1618,6 +1663,11 @@ _cw_next(c3_i argc, c3_c* argv[])
u3_Host.arc_c = strdup(optarg);
} break;
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
@ -1669,7 +1719,8 @@ _cw_pack(c3_i argc, c3_c* argv[])
c3_w arg_w;
static struct option lop_u[] = {
{ "loom", required_argument, NULL, c3__loom },
{ "loom", required_argument, NULL, c3__loom },
{ "no-demand", no_argument, NULL, 6 },
{ NULL, 0, NULL, 0 }
};
@ -1677,6 +1728,11 @@ _cw_pack(c3_i argc, c3_c* argv[])
while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) {
switch ( ch_i ) {
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
@ -1719,7 +1775,161 @@ _cw_pack(c3_i argc, c3_c* argv[])
u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y);
u3a_print_memory(stderr, "urbit: pack: gained", u3m_pack());
u3e_save();
u3m_save();
u3_disk_exit(log_u);
u3m_stop();
}
/* _cw_play_slog(): print during replay.
*/
static void
_cw_play_slog(u3_noun hod)
{
u3_pier_tank(0, 0, u3k(u3t(hod)));
u3z(hod);
}
/* _cw_play_exit(): exit immediately.
*/
static void
_cw_play_exit(c3_i int_i)
{
// explicit fprintf to avoid allocation in u3l_log
//
fprintf(stderr, "\r\n[received keyboard stop signal, exiting]\r\n");
raise(SIGINT);
}
/* _cw_play(): replay events, but better.
*/
static void
_cw_play(c3_i argc, c3_c* argv[])
{
c3_i ch_i, lid_i;
c3_w arg_w;
c3_o ful_o = c3n;
c3_o mel_o = c3n;
static struct option lop_u[] = {
{ "loom", required_argument, NULL, c3__loom },
{ "auto-meld", no_argument, NULL, 4 },
{ "no-demand", no_argument, NULL, 6 },
{ "full", required_argument, NULL, 'f' },
{ "replay-to", no_argument, NULL, 'n' },
{ NULL, 0, NULL, 0 }
};
u3_Host.dir_c = _main_pier_run(argv[0]);
while ( -1 != (ch_i=getopt_long(argc, argv, "fn:", lop_u, &lid_i)) ) {
switch ( ch_i ) {
case 4: { // auto-meld
mel_o = c3y;
} break;
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
if ( (c3n == res_o) || (lom_w < 20) ) {
fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2);
exit(1);
}
u3_Host.ops_u.lom_y = lom_w;
} break;
case 'f': {
ful_o = c3y;
break;
}
case 'n': {
u3_Host.ops_u.til_c = strdup(optarg);
break;
}
case '?': {
fprintf(stderr, "invalid argument\r\n");
exit(1);
} break;
}
}
// argv[optind] is always "play"
//
if ( !u3_Host.dir_c ) {
if ( optind + 1 < argc ) {
u3_Host.dir_c = argv[optind + 1];
}
else {
fprintf(stderr, "invalid command, pier required\r\n");
exit(1);
}
optind++;
}
if ( optind + 1 != argc ) {
fprintf(stderr, "invalid command\r\n");
exit(1);
}
u3_disk* log_u = _cw_disk_init(u3_Host.dir_c); // XX s/b try_aquire lock
#if !defined(U3_OS_mingw)
// Handle SIGTSTP as if it was SIGINT.
//
// Configured here using signal() so as to be immediately available.
//
signal(SIGTSTP, _cw_play_exit);
#endif
if ( c3y == mel_o ) {
u3C.wag_w |= u3o_auto_meld;
}
u3C.wag_w |= u3o_hashless;
if ( c3y == ful_o ) {
u3l_log("mars: preparing for full replay\r\n");
u3m_init((size_t)1 << u3_Host.ops_u.lom_y);
u3e_live(u3m_pier(u3_Host.dir_c));
u3e_yolo();
u3m_pave(c3y);
u3j_boot(c3y);
u3A->eve_d = 0;
}
else {
u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y);
}
u3C.slog_f = _cw_play_slog;
{
u3_mars mar_u = {
.log_u = log_u,
.dir_c = u3_Host.dir_c,
.sen_d = u3A->eve_d,
.dun_d = u3A->eve_d,
.mug_l = u3r_mug(u3A->roc)
};
c3_d eve_d = 0;
c3_c* eve_c = u3_Host.ops_u.til_c;
if ( u3_Host.ops_u.til_c ) {
if ( 1 != sscanf(eve_c, "%" PRIu64 "", &eve_d) ) {
fprintf(stderr, "mars: replay-to invalid: '%s'\r\n", eve_c);
}
}
u3_mars_play(&mar_u, eve_d);
}
u3_disk_exit(log_u);
u3m_stop();
}
@ -1733,7 +1943,8 @@ _cw_prep(c3_i argc, c3_c* argv[])
c3_w arg_w;
static struct option lop_u[] = {
{ "loom", required_argument, NULL, c3__loom },
{ "loom", required_argument, NULL, c3__loom },
{ "no-demand", no_argument, NULL, 6 },
{ NULL, 0, NULL, 0 }
};
@ -1741,6 +1952,11 @@ _cw_prep(c3_i argc, c3_c* argv[])
while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) {
switch ( ch_i ) {
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
@ -1904,7 +2120,8 @@ _cw_vile(c3_i argc, c3_c* argv[])
c3_w arg_w;
static struct option lop_u[] = {
{ "loom", required_argument, NULL, c3__loom },
{ "loom", required_argument, NULL, c3__loom },
{ "no-demand", no_argument, NULL, 6 },
{ NULL, 0, NULL, 0 }
};
@ -1912,6 +2129,11 @@ _cw_vile(c3_i argc, c3_c* argv[])
while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) {
switch ( ch_i ) {
case 6: { // no-demand
u3_Host.ops_u.map = c3n;
u3C.wag_w |= u3o_no_demand;
} break;
case c3__loom: {
c3_w lom_w;
c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w);
@ -1999,11 +2221,13 @@ _cw_utils(c3_i argc, c3_c* argv[])
// $@ ~ :: usage
// $% [%cram dir=@t] :: jam state
// [%dock dir=@t] :: copy binary
// [%eval ~] :: eval hoon
// [?(%grab %mass) dir=@t] :: gc
// [%info dir=@t] :: print
// [%meld dir=@t] :: deduplicate
// [?(%next %upgrade) dir=@t] :: upgrade
// [%pack dir=@t] :: defragment
// [%play dir=@t] :: recompute
// [%prep dir=@t] :: prep upgrade
// [%queu dir=@t eve=@ud] :: cue state
// [?(%vere %fetch-vere) dir=@t] :: download vere
@ -2044,6 +2268,7 @@ _cw_utils(c3_i argc, c3_c* argv[])
case c3__meld: _cw_meld(argc, argv); return 1;
case c3__next: _cw_next(argc, argv); return 2; // continue on
case c3__pack: _cw_pack(argc, argv); return 1;
case c3__play: _cw_play(argc, argv); return 1;
case c3__prep: _cw_prep(argc, argv); return 2; // continue on
case c3__queu: _cw_queu(argc, argv); return 1;
case c3__vere: _cw_vere(argc, argv); return 1;
@ -2181,6 +2406,12 @@ main(c3_i argc,
u3C.wag_w |= u3o_debug_ram;
}
/* Set no-demand flag.
*/
if ( !_(u3_Host.ops_u.map) ) {
u3C.wag_w |= u3o_no_demand;
}
/* Set profile flag.
*/
if ( _(u3_Host.ops_u.pro) ) {

View File

@ -1,4 +1,6 @@
// (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
// without any warranty.
// by Gregory Pakosz (@gpakosz)
// https://github.com/gpakosz/whereami
// in case you want to #include "whereami.c" in a larger compilation unit
@ -10,6 +12,15 @@
extern "C" {
#endif
#if defined(__linux__) || defined(__CYGWIN__)
#undef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#elif defined(__APPLE__)
#undef _DARWIN_C_SOURCE
#define _DARWIN_C_SOURCE
#define _DARWIN_BETTER_REALPATH
#endif
#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
#include <stdlib.h>
#endif
@ -46,7 +57,9 @@ extern "C" {
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#if defined(_MSC_VER)
#pragma warning(push, 3)
#endif
@ -55,6 +68,7 @@ extern "C" {
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#include <stdbool.h>
static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
{
@ -62,8 +76,9 @@ static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, i
wchar_t buffer2[MAX_PATH];
wchar_t* path = NULL;
int length = -1;
bool ok;
for (;;)
for (ok = false; !ok; ok = true)
{
DWORD size;
int length_, length__;
@ -119,14 +134,12 @@ static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, i
}
length = length__;
break;
}
if (path != buffer1)
WAI_FREE(path);
return length;
return ok ? length : -1;
}
WAI_NOINLINE WAI_FUNCSPEC
@ -156,7 +169,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
return length;
}
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun)
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(WAI_USE_PROC_SELF_EXE)
#include <stdio.h>
#include <stdlib.h>
@ -170,6 +183,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#include <stdbool.h>
#if !defined(WAI_PROC_SELF_EXE)
#if defined(__sun)
@ -185,8 +199,9 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
char buffer[PATH_MAX];
char* resolved = NULL;
int length = -1;
bool ok;
for (;;)
for (ok = false; !ok; ok = true)
{
resolved = realpath(WAI_PROC_SELF_EXE, buffer);
if (!resolved)
@ -211,11 +226,9 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
}
}
}
break;
}
return length;
return ok ? length : -1;
}
#if !defined(WAI_PROC_SELF_MAPS_RETRY)
@ -235,6 +248,7 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
#include <sys/mman.h>
#include <unistd.h>
#endif
#include <stdbool.h>
WAI_NOINLINE WAI_FUNCSPEC
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
@ -281,15 +295,24 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
&&buffer[length - 4] == '.')
{
int fd = open(path, O_RDONLY);
char* begin;
char* p;
if (fd == -1)
{
length = -1; // retry
break;
}
begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
p = begin + offset;
char* begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
if (begin == MAP_FAILED)
{
close(fd);
length = -1; // retry
break;
}
char* p = begin + offset - 30; // minimum size of local file header
while (p >= begin) // scan backwards
{
if (*((uint32_t*)p) == 0x04034b50UL) // local file header found
if (*((uint32_t*)p) == 0x04034b50UL) // local file header signature found
{
uint16_t length_ = *((uint16_t*)(p + 26));
@ -303,7 +326,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
break;
}
p -= 4;
--p;
}
munmap(begin, offset);
@ -341,20 +364,17 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
break;
}
if (maps)
fclose(maps);
return length;
}
#elif defined(__APPLE__)
#define _DARWIN_BETTER_REALPATH
#include <mach-o/dyld.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <stdbool.h>
WAI_FUNCSPEC
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
@ -364,8 +384,9 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
char* path = buffer1;
char* resolved = NULL;
int length = -1;
bool ok;
for (;;)
for (ok = false; !ok; ok = true)
{
uint32_t size = (uint32_t)sizeof(buffer1);
if (_NSGetExecutablePath(path, &size) == -1)
@ -398,14 +419,12 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
}
}
}
break;
}
if (path != buffer1)
WAI_FREE(path);
return length;
return ok ? length : -1;
}
WAI_NOINLINE WAI_FUNCSPEC
@ -459,6 +478,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <stdbool.h>
#if !defined(WAI_PROC_SELF_EXE)
#define WAI_PROC_SELF_EXE "/proc/self/exefile"
@ -472,8 +492,9 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
char* resolved = NULL;
FILE* self_exe = NULL;
int length = -1;
bool ok;
for (;;)
for (ok = false; !ok; ok = true)
{
self_exe = fopen(WAI_PROC_SELF_EXE, "r");
if (!self_exe)
@ -505,13 +526,11 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
}
}
}
break;
}
fclose(self_exe);
return length;
return ok ? length : -1;
}
WAI_FUNCSPEC
@ -559,7 +578,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
}
#elif defined(__DragonFly__) || defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || defined(__NetBSD__)
defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <limits.h>
#include <stdlib.h>
@ -567,6 +586,116 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
#include <sys/types.h>
#include <sys/sysctl.h>
#include <dlfcn.h>
#include <stdbool.h>
#if defined(__OpenBSD__)
#include <unistd.h>
WAI_FUNCSPEC
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
{
char buffer1[4096];
char buffer2[PATH_MAX];
char buffer3[PATH_MAX];
char** argv = (char**)buffer1;
char* resolved = NULL;
int length = -1;
bool ok;
for (ok = false; !ok; ok = true)
{
int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
size_t size;
if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0)
break;
if (size > sizeof(buffer1))
{
argv = (char**)WAI_MALLOC(size);
if (!argv)
break;
}
if (sysctl(mib, 4, argv, &size, NULL, 0) != 0)
break;
if (strchr(argv[0], '/'))
{
resolved = realpath(argv[0], buffer2);
if (!resolved)
break;
}
else
{
const char* PATH = getenv("PATH");
if (!PATH)
break;
size_t argv0_length = strlen(argv[0]);
const char* begin = PATH;
while (1)
{
const char* separator = strchr(begin, ':');
const char* end = separator ? separator : begin + strlen(begin);
if (end - begin > 0)
{
if (*(end -1) == '/')
--end;
if (((end - begin) + 1 + argv0_length + 1) <= sizeof(buffer2))
{
memcpy(buffer2, begin, end - begin);
buffer2[end - begin] = '/';
memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1);
resolved = realpath(buffer2, buffer3);
if (resolved)
break;
}
}
if (!separator)
break;
begin = ++separator;
}
if (!resolved)
break;
}
length = (int)strlen(resolved);
if (length <= capacity)
{
memcpy(out, resolved, length);
if (dirname_length)
{
int i;
for (i = length - 1; i >= 0; --i)
{
if (out[i] == '/')
{
*dirname_length = i;
break;
}
}
}
}
}
if (argv != (char**)buffer1)
WAI_FREE(argv);
return ok ? length : -1;
}
#else
WAI_FUNCSPEC
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
@ -576,13 +705,18 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
char* path = buffer1;
char* resolved = NULL;
int length = -1;
bool ok;
for (;;)
for (ok = false; !ok; ok = true)
{
#if defined(__NetBSD__)
int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
#else
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
#endif
size_t size = sizeof(buffer1);
if (sysctl(mib, (u_int)(sizeof(mib) / sizeof(mib[0])), path, &size, NULL, 0) != 0)
if (sysctl(mib, 4, path, &size, NULL, 0) != 0)
break;
resolved = realpath(path, buffer2);
@ -608,16 +742,13 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
}
}
}
break;
}
if (path != buffer1)
WAI_FREE(path);
return length;
return ok ? length : -1;
}
#endif
WAI_NOINLINE WAI_FUNCSPEC
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
{
@ -670,4 +801,4 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,4 +1,6 @@
// (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
// without any warranty.
// by Gregory Pakosz (@gpakosz)
// https://github.com/gpakosz/whereami
#ifndef WHEREAMI_H
@ -62,4 +64,4 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length);
}
#endif
#endif // #ifndef WHEREAMI_H
#endif // #ifndef WHEREAMI_H

View File

@ -11,7 +11,6 @@
# include "noun/aliases.h" // general u3
# include "noun/allocate.h" // u3a: allocation
# include "noun/events.h" // u3e: persistence
# include "noun/hashtable.h" // u3h: hashtables
# include "noun/imprison.h" // u3i: noun construction
# include "noun/jets.h" // u3j: jet control

View File

@ -1,6 +1,11 @@
#ifndef C3_DEFS_H
#define C3_DEFS_H
#include "c/portable.h"
#include "c/types.h"
#include <errno.h>
/** Loobeans - inverse booleans to match nock.
**/
# define c3y 0
@ -157,4 +162,28 @@
# define c3_fopen(a, b) ({ \
fopen(a, b);})
/** i/o wrappers
***
*** these handle partial success and retry ephemeral errors
*** up to hardcoded max try count, either reading/writing fully
*** (up to EOF on read) or returning on error.
***
*** a wrapper for read() is not provided, as file cursor position
*** is undefined on error. use pread() or loop yourself.
**/
/* c3_pread(): full positioned read(), up to eof, retrying errors.
*/
ssize_t
c3_pread(c3_i fid_i, void* buf_v, size_t len_i, off_t off_i);
/* c3_pwrite(): full positioned write(), retrying errors.
*/
ssize_t
c3_pwrite(c3_i fid_i, const void* buf_v, size_t len_i, off_t off_i);
/* c3_write(): full write(), retrying errors.
*/
ssize_t
c3_write(c3_i fid_i, const void* buf_v, size_t len_i);
#endif /* ifndef C3_DEFS_H */

View File

@ -645,6 +645,11 @@
void
u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w);
/* u3a_prof(): mark/measure/print memory profile. RETAIN.
*/
c3_w
u3a_prof(FILE* fil_u, c3_w den_w, u3_noun mas);
/* u3a_maid(): maybe print memory.
*/
c3_w

View File

@ -39,13 +39,22 @@
/* u3e_pool: entire memory system.
*/
typedef struct _u3e_pool {
c3_c* dir_c; // path to
c3_c* dir_c; // checkpoint dir
c3_w dit_w[u3a_pages >> 5]; // touched since last save
c3_w pag_w; // number of pages (<= u3a_pages)
c3_w gar_w; // guard page
u3e_image nor_u; // north segment
u3e_image sou_u; // south segment
} u3e_pool;
/* u3e_flaw: loom fault result.
*/
typedef enum {
u3e_flaw_sham = 0, // bogus state
u3e_flaw_base = 1, // vm fail (mprotect)
u3e_flaw_meme = 2, // bail:meme
u3e_flaw_good = 3 // handled
} u3e_flaw;
/** Globals.
**/
@ -60,31 +69,26 @@
/** Functions.
**/
/* u3e_fault(): handle a memory event with libsigsegv protocol.
/* u3e_fault(): handle a memory fault.
*/
c3_i
u3e_fault(void* adr_v, c3_i ser_i);
u3e_flaw
u3e_fault(u3_post low_p, u3_post hig_p, u3_post off_p);
/* u3e_save():
/* u3e_save(): update the checkpoint.
*/
void
u3e_save(void);
u3e_save(u3_post low_p, u3_post hig_p);
/* u3e_live(): start the persistence system. Return c3y if no image.
*/
c3_o
u3e_live(c3_o nuu_o, c3_c* dir_c);
u3e_live(c3_c* dir_c);
/* u3e_yolo(): disable dirty page tracking, read/write whole loom.
*/
c3_o
u3e_yolo(void);
/* u3e_foul(): dirty all the pages of the loom.
*/
void
u3e_foul(void);
/* u3e_init(): initialize guard page tracking.
*/
void

View File

@ -8,6 +8,11 @@
c3_d
u3m_boot(c3_c* dir_c, size_t len_i);
/* u3m_pier(): make a pier.
*/
c3_c*
u3m_pier(c3_c* dir_c);
/* u3m_boot_lite(): start without checkpointing.
*/
c3_d
@ -34,6 +39,21 @@
c3_i
u3m_bail(c3_m how_m) __attribute__((noreturn));
/* u3m_fault(): handle a memory event with libsigsegv protocol.
*/
c3_i
u3m_fault(void* adr_v, c3_i ser_i);
/* u3m_save(): update the checkpoint.
*/
void
u3m_save(void);
/* u3m_ward(): tend the guard page.
*/
void
u3m_ward(void);
/* u3m_init(): start the environment.
*/
void
@ -117,7 +137,7 @@
/* u3m_water(): produce high and low watermarks. Asserts u3R == u3H.
*/
void
u3m_water(c3_w *low_w, c3_w *hig_w);
u3m_water(u3_post* low_p, u3_post* hig_p);
/* u3m_pretty(): dumb prettyprint to string. RETAIN.
*/

View File

@ -22,15 +22,17 @@
** _check flags are set inside u3 and heard outside it.
*/
enum u3o_flag { // execution flags
u3o_debug_ram = 0x1, // debug: gc
u3o_debug_cpu = 0x2, // debug: profile
u3o_check_corrupt = 0x4, // check: gc memory
u3o_check_fatal = 0x8, // check: unrecoverable
u3o_verbose = 0x10, // be remarkably wordy
u3o_dryrun = 0x20, // don't touch checkpoint
u3o_quiet = 0x40, // disable ~&
u3o_hashless = 0x80, // disable hashboard
u3o_trace = 0x100 // enables trace dumping
u3o_debug_ram = 1 << 0, // debug: gc
u3o_debug_cpu = 1 << 1, // debug: profile
u3o_check_corrupt = 1 << 2, // check: gc memory
u3o_check_fatal = 1 << 3, // check: unrecoverable
u3o_verbose = 1 << 4, // be remarkably wordy
u3o_dryrun = 1 << 5, // don't touch checkpoint
u3o_quiet = 1 << 6, // disable ~&
u3o_hashless = 1 << 7, // disable hashboard
u3o_trace = 1 << 8, // enables trace dumping
u3o_auto_meld = 1 << 9, // enables meld under pressure
u3o_no_demand = 1 << 10 // disables demand paging
};
/** Globals.

View File

@ -5,7 +5,7 @@
**/
/* u3u_meld(): globally deduplicate memory.
*/
void
c3_w
u3u_meld(void);
/* u3u_cram(): globably deduplicate memory, and write a rock to disk.

View File

@ -87,6 +87,11 @@
u3_noun
u3v_poke(u3_noun ovo);
/* u3v_poke_sure(): inject an event, saving new state if successful.
*/
c3_o
u3v_poke_sure(c3_w mil_w, u3_noun eve, u3_noun* pro);
/* u3v_tank(): dump single tank.
*/
void

View File

@ -6,6 +6,17 @@
/* lmdb api wrapper
*/
/* u3_lmdb_iter: event iterator
*/
typedef struct _u3_lmdb_walk {
MDB_txn* txn_u; // transaction handle
MDB_dbi mdb_u; // db handle
MDB_cursor* cur_u; // db cursor
c3_o red_o; // have we read from this yet?
c3_d nex_d; // next event number
c3_d las_d; // final event number, inclusive
} u3_lmdb_walk;
/* u3_lmdb_init(): open lmdb at [pax_c], mmap up to [siz_i].
*/
MDB_env*
@ -61,4 +72,22 @@
size_t val_i,
void* val_p);
/* u3_lmdb_walk_init(): initialize db iterator.
*/
c3_o
u3_lmdb_walk_init(MDB_env* env_u,
u3_lmdb_walk* itr_u,
c3_d nex_d,
c3_d las_d);
/* u3_lmdb_walk_next(): synchronously read next event from iterator.
*/
c3_o
u3_lmdb_walk_next(u3_lmdb_walk* itr_u, size_t* len_i, void** buf_v);
/* u3_lmdb_walk_done(): close iterator.
*/
void
u3_lmdb_walk_done(u3_lmdb_walk* itr_u);
#endif /* ifndef U3_VERE_DB_LMDB_H */

View File

@ -0,0 +1,22 @@
#ifndef U3_VERE_MARS_H
#define U3_VERE_MARS_H
/** Data types.
**/
/* u3_mars: the urbit state machine.
*/
typedef struct _u3_mars {
c3_d key_d[4]; // disk key
u3_disk* log_u; // event log
c3_c* dir_c; // execution directory (pier)
c3_d sen_d; // last event requested
c3_d dun_d; // last event processed
c3_l mug_l; // hash of state
} u3_mars;
/* u3_mars_play(): replay logged events up to [eve_d].
*/
void
u3_mars_play(u3_mars* mar_u, c3_d eve_d);
#endif /* ifndef U3_VERE_MARS_H */

View File

@ -313,6 +313,7 @@
c3_c* puf_c; // -Z, scry result format
c3_o con; // run conn
c3_o doc; // dock binary in pier
c3_o map; // --no-demand (reversed)
} u3_opts;
/* u3_host: entire host.
@ -562,6 +563,10 @@
u3_info put_u; // write queue
} u3_disk;
/* u3_disk_walk: opaque event log iterator.
*/
typedef struct _u3_disk_walk u3_disk_walk;
/* u3_psat: pier state.
*/
typedef enum {
@ -942,6 +947,23 @@
u3_disk*
u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u);
/* u3_disk_etch(): serialize an event for persistence. RETAIN [eve]
*/
size_t
u3_disk_etch(u3_disk* log_u,
u3_noun eve,
c3_l mug_l,
c3_y** out_y);
/* u3_disk_sift(): parse a persisted event buffer.
*/
c3_o
u3_disk_sift(u3_disk* log_u,
size_t len_i,
c3_y* dat_y,
c3_l* mug_l,
u3_noun* job);
/* u3_disk_info(): status info as $mass.
*/
u3_noun
@ -993,6 +1015,33 @@
void
u3_disk_plan(u3_disk* log_u, u3_fact* tac_u);
/* u3_disk_read_list(): synchronously read a cons list of events.
*/
u3_weak
u3_disk_read_list(u3_disk* log_u, c3_d eve_d, c3_d len_d, c3_l* mug_l);
/* u3_disk_walk_init(): init iterator.
*/
u3_disk_walk*
u3_disk_walk_init(u3_disk* log_u,
c3_d eve_d,
c3_d len_d);
/* u3_disk_walk_live(): check if live.
*/
c3_o
u3_disk_walk_live(u3_disk_walk* wok_u);
/* u3_disk_walk_live(): get next fact.
*/
c3_o
u3_disk_walk_step(u3_disk_walk* wok_u, u3_fact* tac_u);
/* u3_disk_walk_done(): close iterator.
*/
void
u3_disk_walk_done(u3_disk_walk* wok_u);
/* u3_lord_init(): start serf.
*/
u3_lord*
@ -1461,11 +1510,6 @@
void
u3_daemon_init();
/* u3_write_fd(): retry interrupts, continue partial writes, assert errors.
*/
void
u3_write_fd(c3_i fid_i, const void* buf_v, size_t len_i);
c3_w
u3_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

View File

@ -425,8 +425,18 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w)
alp_w = (alp_w + c3_wiseof(u3a_box)) % ald_w;
// XX: this logic is totally bizarre, but preserve it.
//
/* XX: this logic is totally bizarre, but preserve it.
**
** This means we use the next size bigger instead of the "correct"
** size. For example, a 20 word allocation will be freed into free
** list 2 but will be allocated from free list 3.
**
** This is important to preserve because the sequential search may be
** very slow. On a real-world task involving many compilations,
** removing this line made this function appear in ~80% of samples.
**
** For reference, this was added in cgyarvin/urbit ffed9e748d8f6c.
*/
if ( (sel_w != 0) && (sel_w != u3a_fbox_no - 1) ) {
sel_w += 1;
}
@ -1617,7 +1627,7 @@ u3a_mark_ptr(void* ptr_v)
if ( 0 == box_u->eus_w ) {
siz_w = box_u->siz_w;
}
else if ( 0xffffffff == box_u->eus_w ) { // see _raft_prof()
else if ( 0xffffffff == box_u->eus_w ) { // see u3a_prof()
siz_w = 0xffffffff;
box_u->eus_w = 0;
}
@ -1635,7 +1645,7 @@ u3a_mark_ptr(void* ptr_v)
else {
c3_assert(use_ws != 0);
if ( 0x80000000 == (c3_w)use_ws ) { // see _raft_prof()
if ( 0x80000000 == (c3_w)use_ws ) { // see u3a_prof()
use_ws = -1;
siz_w = 0xffffffff;
}
@ -1906,7 +1916,7 @@ u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w)
if ( byt_w ) {
if ( gib_w ) {
fprintf(fil_u, "%s: GB/%d.%03d.%03d.%03d\r\n",
cap_c, gib_w, mib_w, kib_w, bib_w);
cap_c, gib_w, mib_w, kib_w, bib_w);
}
else if ( mib_w ) {
fprintf(fil_u, "%s: MB/%d.%03d.%03d\r\n", cap_c, mib_w, kib_w, bib_w);
@ -1931,6 +1941,122 @@ u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w)
return wor_w;
}
/* _ca_print_memory(): un-captioned u3a_print_memory().
*/
static void
_ca_print_memory(FILE* fil_u, c3_w wor_w)
{
c3_w byt_w = (wor_w * 4);
c3_w gib_w = (byt_w / 1000000000);
c3_w mib_w = (byt_w % 1000000000) / 1000000;
c3_w kib_w = (byt_w % 1000000) / 1000;
c3_w bib_w = (byt_w % 1000);
if ( gib_w ) {
fprintf(fil_u, "GB/%d.%03d.%03d.%03d\r\n",
gib_w, mib_w, kib_w, bib_w);
}
else if ( mib_w ) {
fprintf(fil_u, "MB/%d.%03d.%03d\r\n", mib_w, kib_w, bib_w);
}
else if ( kib_w ) {
fprintf(fil_u, "KB/%d.%03d\r\n", kib_w, bib_w);
}
else {
fprintf(fil_u, "B/%d\r\n", bib_w);
}
}
/* u3a_prof(): mark/measure/print memory profile. RETAIN.
*/
c3_w
u3a_prof(FILE* fil_u, c3_w den_w, u3_noun mas)
{
c3_w tot_w = 0;
u3_noun h_mas, t_mas;
if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) {
fprintf(fil_u, "%.*smistyped mass\r\n", den_w, "");
return tot_w;
}
else if ( _(u3du(h_mas)) ) {
fprintf(fil_u, "%.*smistyped mass head\r\n", den_w, "");
{
c3_c* lab_c = u3m_pretty(h_mas);
fprintf(fil_u, "h_mas: %s", lab_c);
c3_free(lab_c);
}
return tot_w;
}
else {
{
c3_c* lab_c = u3m_pretty(h_mas);
fprintf(fil_u, "%*s%s: ", den_w, "", lab_c);
c3_free(lab_c);
}
u3_noun it_mas, tt_mas;
if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) {
fprintf(fil_u, "%*smistyped mass tail\r\n", den_w, "");
return tot_w;
}
else if ( c3y == it_mas ) {
tot_w += u3a_mark_noun(tt_mas);
_ca_print_memory(fil_u, tot_w);
#if 1
/* The basic issue here is that tt_mas is included in .sac
* (the whole profile), so they can't both be roots in the
* normal sense. When we mark .sac later on, we want tt_mas
* to appear unmarked, but its children should be already
* marked.
*
* see u3a_mark_ptr().
*/
if ( _(u3a_is_dog(tt_mas)) ) {
u3a_box* box_u = u3a_botox(u3a_to_ptr(tt_mas));
#ifdef U3_MEMORY_DEBUG
if ( 1 == box_u->eus_w ) {
box_u->eus_w = 0xffffffff;
}
else {
box_u->eus_w -= 1;
}
#else
if ( -1 == (c3_w)box_u->use_w ) {
box_u->use_w = 0x80000000;
}
else {
box_u->use_w += 1;
}
#endif
}
#endif
return tot_w;
}
else if ( c3n == it_mas ) {
fprintf(fil_u, "\r\n");
while ( _(u3du(tt_mas)) ) {
tot_w += u3a_prof(fil_u, den_w+2, u3h(tt_mas));
tt_mas = u3t(tt_mas);
}
fprintf(fil_u, "%*s--", den_w, "");
_ca_print_memory(fil_u, tot_w);
return tot_w;
}
else {
fprintf(fil_u, "%*smistyped (strange) mass tail\r\n", den_w, "");
return tot_w;
}
}
}
/* u3a_mark_road(): mark ad-hoc persistent road structures.
*/
c3_w

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
**
*/
#include "all.h"
#include "noun/events.h"
#include "rsignal.h"
#include "vere/vere.h"
#include <errno.h>
@ -436,7 +437,7 @@ u3m_file(c3_c* pas_c)
u3l_log("Loading file: %s\r\n", pas_c);
struct stat buf_b;
c3_i fid_i = c3_open(pas_c, O_RDONLY, 0644);
c3_w fln_w, red_w;
c3_w fln_w;
c3_y* pad_y;
if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) {
@ -448,10 +449,10 @@ u3m_file(c3_c* pas_c)
pad_y = c3_malloc(buf_b.st_size);
red_w = read(fid_i, pad_y, fln_w);
ssize_t red_i = c3_pread(fid_i, pad_y, fln_w, 0);
close(fid_i);
if ( fln_w != red_w ) {
if ( red_i != fln_w ) {
c3_free(pad_y);
return u3m_bail(c3__fail);
}
@ -527,6 +528,8 @@ _pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w)
// the stack starts at the end of the memory segment,
// minus space for the road structure [siz_w]
//
// NB: the returned road is "above" the stack
//
c3_w* rut_w = mem_w;
c3_w* mat_w = ((mem_w + len_w) - siz_w);
c3_w* cap_w = mat_w;
@ -545,6 +548,8 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w)
// the stack starts at the base memory pointer [mem_w],
// and ends after the space for the road structure [siz_w]
//
// NB: the returned road is *on* the stack
//
c3_w* rut_w = (mem_w + len_w);
c3_w* mat_w = mem_w;
c3_w* cap_w = mat_w + siz_w;
@ -600,7 +605,7 @@ _find_home(void)
// this looks risky, but there are no legitimate scenarios
// where it's wrong
//
u3R->cap_p = u3R->mat_p = u3C.wor_i - c3_wiseof(*u3H);
u3R->cap_p = u3R->mat_p = u3a_outa(u3H);
}
/* u3m_pave(): instantiate or activate image.
@ -819,7 +824,6 @@ u3m_leap(c3_w pad_w)
u3R->cap_p -= len_w;
rod_u = _pave_south(u3a_into(bot_p), c3_wiseof(u3a_road), len_w);
u3e_ward(rod_u->cap_p, rod_u->hat_p);
#if 0
fprintf(stderr, "leap: from north %p (cap 0x%x), to south %p\r\n",
u3R,
@ -832,7 +836,6 @@ u3m_leap(c3_w pad_w)
u3R->cap_p += len_w;
rod_u = _pave_north(u3a_into(bot_p), c3_wiseof(u3a_road), len_w);
u3e_ward(rod_u->hat_p, rod_u->cap_p);
#if 0
fprintf(stderr, "leap: from south %p (cap 0x%x), to north %p\r\n",
u3R,
@ -854,6 +857,7 @@ u3m_leap(c3_w pad_w)
*/
{
u3R = rod_u;
u3m_ward();
_pave_parts();
}
#ifdef U3_MEMORY_DEBUG
@ -1003,12 +1007,31 @@ u3m_flog(c3_w gof_w)
/* u3m_water(): produce watermarks.
*/
void
u3m_water(c3_w* low_w, c3_w* hig_w)
u3m_water(u3_post* low_p, u3_post* hig_p)
{
c3_assert(u3R == &u3H->rod_u);
*low_w = u3a_heap(u3R);
*hig_w = u3a_temp(u3R) + c3_wiseof(u3v_home);
// allow the segfault handler to fire before the road is set
//
// while not explicitly possible in the codebase,
// compiler optimizations can reorder stores
//
if ( !u3R ) {
*low_p = 0;
*hig_p = u3C.wor_i - 1;
}
// in a north road, hat points to the end of the heap + 1 word,
// while cap points to the top of the stack
//
else if ( c3y == u3a_is_north(u3R) ) {
*low_p = u3R->hat_p - 1;
*hig_p = u3R->cap_p;
}
// in a south road, hat points to the end of the heap,
// while cap points to the top of the stack + 1 word
//
else {
*low_p = u3R->cap_p - 1;
*hig_p = u3R->hat_p;
}
}
/* u3m_soft_top(): top-level safety wrapper.
@ -1692,6 +1715,80 @@ _cm_limits(void)
# endif
}
/* u3m_fault(): handle a memory event with libsigsegv protocol.
*/
c3_i
u3m_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;
u3_post low_p, hig_p;
if ( (adr_w < u3_Loom) || (adr_w >= (u3_Loom + u3C.wor_i)) ) {
fprintf(stderr, "loom: external fault: %p (%p : %p)\r\n\r\n",
adr_w, u3_Loom, u3_Loom + u3C.wor_i);
c3_assert(0);
return 0;
}
u3m_water(&low_p, &hig_p);
switch ( u3e_fault(low_p, hig_p, u3a_outa(adr_w)) ) {
// page tracking invariants violated, fatal
//
case u3e_flaw_sham: {
c3_assert(0);
return 0;
}
// virtual memory failure (protections), possibly recoverable XX
//
case u3e_flaw_base: {
c3_assert(0);
return 0;
}
// loom limits exceeded, recoverable
//
case u3e_flaw_meme: {
u3m_signal(c3__meme); // doesn't return
return 1;
}
case u3e_flaw_good: return 1;
}
c3_assert(!"unpossible");
}
/* u3m_save(): update the checkpoint.
*/
void
u3m_save(void)
{
u3_post low_p, hig_p;
u3m_water(&low_p, &hig_p);
c3_assert(u3R == &u3H->rod_u);
return u3e_save(low_p, hig_p);
}
/* u3m_ward(): tend the guard page.
*/
void
u3m_ward(void)
{
u3_post low_p, hig_p;
u3m_water(&low_p, &hig_p);
return u3e_ward(low_p, hig_p);
}
/* _cm_signals(): set up interrupts, etc.
*/
static void
@ -1707,7 +1804,7 @@ _cm_signals(void)
// filter (see compat/mingw/seh_handler.c) that handles both memory
// access and stack overflow exceptions. It calls u3e_fault directly.
# else
if ( 0 != sigsegv_install_handler(u3e_fault) ) {
if ( 0 != sigsegv_install_handler(u3m_fault) ) {
u3l_log("boot: sigsegv install failed\n");
exit(1);
}
@ -1864,6 +1961,46 @@ void
u3m_stop()
{
u3je_secp_stop();
// XX move to jets.c
//
c3_free(u3D.ray_u);
}
/* u3m_pier(): make a pier.
*/
c3_c*
u3m_pier(c3_c* dir_c)
{
c3_c ful_c[8193];
u3C.dir_c = dir_c;
snprintf(ful_c, 8192, "%s", dir_c);
if ( c3_mkdir(ful_c, 0700) ) {
if ( EEXIST != errno ) {
fprintf(stderr, "loom: pier create: %s\r\n", strerror(errno));
c3_assert(0);
}
}
snprintf(ful_c, 8192, "%s/.urb", dir_c);
if ( c3_mkdir(ful_c, 0700) ) {
if ( EEXIST != errno ) {
fprintf(stderr, "loom: .urb create: %s\r\n", strerror(errno));
c3_assert(0);
}
}
snprintf(ful_c, 8192, "%s/.urb/chk", dir_c);
if ( c3_mkdir(ful_c, 0700) ) {
if ( EEXIST != errno ) {
fprintf(stderr, "loom: .urb/chk create: %s\r\n", strerror(errno));
c3_assert(0);
}
}
return strdup(ful_c);
}
/* u3m_boot(): start the u3 system. return next event, starting from 1.
@ -1879,7 +2016,7 @@ u3m_boot(c3_c* dir_c, size_t len_i)
/* Activate the storage system.
*/
nuu_o = u3e_live(c3n, dir_c);
nuu_o = u3e_live(u3m_pier(dir_c));
/* Activate tracing.
*/
@ -1892,10 +2029,6 @@ u3m_boot(c3_c* dir_c, size_t len_i)
*/
u3m_pave(nuu_o);
/* Place the guard page.
*/
u3e_init();
/* Initialize the jet system.
*/
{

View File

@ -278,11 +278,19 @@ void
u3t_trace_open(c3_c* dir_c)
{
c3_c fil_c[2048];
if ( !dir_c ) {
return;
}
snprintf(fil_c, 2048, "%s/.urb/put/trace", dir_c);
struct stat st;
if ( -1 == stat(fil_c, &st) ) {
c3_mkdir(fil_c, 0700);
if ( (-1 == stat(fil_c, &st))
&& (-1 == c3_mkdir(fil_c, 0700)) )
{
fprintf(stderr, "mkdir: %s failed: %s\r\n", fil_c, strerror(errno));
return;
}
c3_c lif_c[2056];
@ -291,6 +299,11 @@ u3t_trace_open(c3_c* dir_c)
u3_Host.tra_u.fil_u = c3_fopen(lif_c, "w");
u3_Host.tra_u.nid_w = (int)getpid();
if ( !u3_Host.tra_u.fil_u) {
fprintf(stderr, "trace open: %s\r\n", strerror(errno));
return;
}
fprintf(u3_Host.tra_u.fil_u, "[ ");
// We have two "threads", the event processing and the nock stuff.

View File

@ -2,6 +2,7 @@
**
*/
#include "all.h"
#include "noun/events.h"
#include "ur/ur.h"
#include <errno.h>
#include <fcntl.h>
@ -416,10 +417,6 @@ _cu_realloc(FILE* fil_u, ur_root_t** tor_u, ur_nvec_t* doc_u)
//
u3A->eve_d = eve_d;
// mark all pages dirty
//
u3e_foul();
*tor_u = rot_u;
*doc_u = cod_u;
@ -429,15 +426,17 @@ _cu_realloc(FILE* fil_u, ur_root_t** tor_u, ur_nvec_t* doc_u)
/* u3u_meld(): globally deduplicate memory.
*/
#ifdef U3_MEMORY_DEBUG
void
c3_w
u3u_meld(void)
{
fprintf(stderr, "u3: unable to meld under U3_MEMORY_DEBUG\r\n");
return 0;
}
#else
void
c3_w
u3u_meld(void)
{
c3_w pre_w = u3a_open(u3R);
ur_root_t* rot_u;
ur_nvec_t cod_u;
@ -449,6 +448,8 @@ u3u_meld(void)
//
ur_nvec_free(&cod_u);
ur_root_free(rot_u);
return (u3a_open(u3R) - pre_w);
}
#endif
@ -564,56 +565,14 @@ _cu_rock_save(c3_c* dir_c, c3_d eve_d, c3_d len_d, c3_y* byt_y)
// write jam-buffer into [fid_i]
//
// XX deduplicate with _write() wrapper in term.c
//
{
ssize_t ret_i;
while ( len_d > 0 ) {
c3_w lop_w = 0;
// retry interrupt/async errors
//
do {
// abort pathological retry loop
//
if ( 100 == ++lop_w ) {
fprintf(stderr, "rock: write loop: %s\r\n", strerror(errno));
close(fid_i);
// XX unlink file?
//
return c3n;
}
ret_i = write(fid_i, byt_y, len_d);
}
while ( (ret_i < 0)
&& ( (errno == EINTR)
|| (errno == EAGAIN)
|| (errno == EWOULDBLOCK) ));
// assert on true errors
//
// NB: can't call u3l_log here or we would re-enter _write()
//
if ( ret_i < 0 ) {
fprintf(stderr, "rock: write failed %s\r\n", strerror(errno));
close(fid_i);
// XX unlink file?
//
return c3n;
}
// continue partial writes
//
else {
len_d -= ret_i;
byt_y += ret_i;
}
}
ssize_t rit_i = c3_pwrite(fid_i, byt_y, len_d, 0);
if ( rit_i < 0 ) {
fprintf(stderr, "rock: write failed: %s\r\n", strerror(errno));
}
close(fid_i);
return c3y;
return rit_i < 0 ? c3n : c3y;
}
/* u3u_cram(): globably deduplicate memory, and write a rock to disk.
@ -889,10 +848,6 @@ u3u_uncram(c3_c* dir_c, c3_d eve_d)
//
u3A->eve_d = eve_d;
// mark all pages dirty
//
u3e_foul();
// leave rocks on disk
//
// if ( 0 != c3_unlink(nam_c) ) {

View File

@ -27,9 +27,18 @@ u3v_life(u3_noun eve)
c3_o
u3v_boot(u3_noun eve)
{
c3_d len_d;
{
u3_noun len = u3qb_lent(eve);
c3_assert( c3y == u3r_safe_chub(len, &len_d) );
u3z(len);
}
// ensure zero-initialized kernel
//
u3A->roc = 0;
u3A->roc = 0;
u3A->eve_d = 0;
{
u3_noun pro = u3m_soft(0, u3v_life, eve);
@ -39,7 +48,8 @@ u3v_boot(u3_noun eve)
return c3n;
}
u3A->roc = u3k(u3t(pro));
u3A->roc = u3k(u3t(pro));
u3A->eve_d = len_d;
u3z(pro);
}
@ -260,6 +270,61 @@ u3v_poke(u3_noun ovo)
return pro;
}
/* _cv_poke_eve(): u3v_poke w/out u3A->now XX replace
*/
static u3_noun
_cv_poke_eve(u3_noun sam)
{
u3_noun fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_POKE, u3A->roc)));
u3_noun pro;
{
# ifdef U3_MEMORY_DEBUG
c3_w cod_w = u3a_lush(u3h(u3t(u3t(sam))));
# endif
pro = u3n_slam_on(fun, sam);
# ifdef U3_MEMORY_DEBUG
u3a_lop(cod_w);
# endif
}
return pro;
}
/* u3v_poke_sure(): inject an event, saving new state if successful.
*/
c3_o
u3v_poke_sure(c3_w mil_w, u3_noun eve, u3_noun* pro)
{
u3_noun gon = u3m_soft(mil_w, _cv_poke_eve, eve);
u3_noun tag, dat;
u3x_cell(gon, &tag, &dat);
// event failed, produce trace
//
if ( u3_blip != tag ) {
*pro = gon;
return c3n;
}
// event succeeded, persist state and produce effects
//
{
u3_noun vir, cor;
u3x_cell(dat, &vir, &cor);
u3z(u3A->roc);
u3A->roc = u3k(cor);
u3A->eve_d++;
*pro = u3k(vir);
u3z(gon);
return c3y;
}
}
/* u3v_tank(): dump single tank.
*/
void

View File

@ -6,8 +6,7 @@
static void
_setup(void)
{
u3m_init(1 << 22);
u3m_pave(c3y);
u3m_boot_lite(1 << 22);
}
/* _test_ames(): spot check ames helpers

View File

@ -0,0 +1,251 @@
#include "all.h"
#include "noun/events.h"
/* _setup(): prepare for tests.
*/
static void
_setup(void)
{
// NB: no loom
//
u3P.pag_w = u3a_pages;
}
static c3_w
_check_north_clean(void)
{
c3_w i_w, pag_w, blk_w, bit_w;
for ( i_w = 0; i_w < u3P.pag_w; i_w++ ) {
pag_w = i_w;
blk_w = pag_w >> 5;
bit_w = pag_w & 31;
if ( u3P.dit_w[blk_w] & (1 << bit_w) ) {
break;
}
}
return i_w;
}
static c3_w
_check_north_dirty(c3_w pgs_w, c3_w max_w)
{
c3_w i_w, pag_w, blk_w, bit_w;
for ( i_w = 0; i_w < max_w; i_w++ ) {
pag_w = i_w + pgs_w;
blk_w = pag_w >> 5;
bit_w = pag_w & 31;
if ( !(u3P.dit_w[blk_w] & (1 << bit_w)) ) {
break;
}
}
return i_w;
}
static c3_w
_check_south_clean(void)
{
c3_w i_w, pag_w, blk_w, bit_w;
for ( i_w = 0; i_w < u3P.pag_w; i_w++ ) {
pag_w = u3P.pag_w - (i_w + 1);
blk_w = pag_w >> 5;
bit_w = pag_w & 31;
if ( u3P.dit_w[blk_w] & (1 << bit_w) ) {
break;
}
}
return i_w;
}
static c3_w
_check_south_dirty(c3_w pgs_w, c3_w max_w)
{
c3_w i_w, pag_w, blk_w, bit_w;
for ( i_w = 0; i_w < max_w; i_w++ ) {
pag_w = u3P.pag_w - (i_w + pgs_w + 1);
blk_w = pag_w >> 5;
bit_w = pag_w & 31;
if ( !(u3P.dit_w[blk_w] & (1 << bit_w)) ) {
break;
}
}
return i_w;
}
void
_ce_loom_track_north(c3_w pgs_w, c3_w dif_w);
void
_ce_loom_track_south(c3_w pgs_w, c3_w dif_w);
static c3_i
_test_tracking(void)
{
c3_w ret_w;
_ce_loom_track_north(0, u3P.pag_w);
if ( u3P.pag_w != (ret_w = _check_north_dirty(0, u3P.pag_w)) ) {
fprintf(stderr, "test events track north dirty all %u\r\n", ret_w);
return 0;
}
if ( 0 != (ret_w = _check_north_clean()) ) {
fprintf(stderr, "test events track north init %u\r\n", ret_w);
return 0;
}
if ( 0 != (ret_w = _check_south_clean()) ) {
fprintf(stderr, "test events track south init %u\r\n", ret_w);
return 0;
}
_ce_loom_track_north(100, 0);
_ce_loom_track_south(1, 0);
if ( 100 != (ret_w = _check_north_clean()) ) {
fprintf(stderr, "test events track north clean a %u\r\n", ret_w);
return 0;
}
if ( 1 != (ret_w = _check_south_clean()) ) {
fprintf(stderr, "test events track south clean a %u\r\n", ret_w);
return 0;
}
_ce_loom_track_north(75, 25);
_ce_loom_track_south(2, 0);
if ( 75 != (ret_w = _check_north_clean()) ) {
fprintf(stderr, "test events track north clean b %u\r\n", ret_w);
return 0;
}
if ( 25 != (ret_w = _check_north_dirty(75, 25)) ) {
fprintf(stderr, "test events track north dirty b %u\r\n", ret_w);
return 0;
}
if ( 2 != (ret_w = _check_south_clean()) ) {
fprintf(stderr, "test events track south clean b %u\r\n", ret_w);
return 0;
}
_ce_loom_track_north(55, 20);
_ce_loom_track_south(1, 1);
if ( 55 != (ret_w = _check_north_clean()) ) {
fprintf(stderr, "test events track north clean c %u\r\n", ret_w);
return 0;
}
if ( 20 != (ret_w = _check_north_dirty(55, 20)) ) {
fprintf(stderr, "test events track north dirty c %u\r\n", ret_w);
return 0;
}
if ( 1 != (ret_w = _check_south_clean()) ) {
fprintf(stderr, "test events track south clean c %u\r\n", ret_w);
return 0;
}
if ( 1 != (ret_w = _check_south_dirty(1, 1)) ) {
fprintf(stderr, "test events track north dirty c %u\r\n", ret_w);
return 0;
}
_ce_loom_track_north(255, 0);
_ce_loom_track_south(48, 0);
if ( 255 != (ret_w = _check_north_clean()) ) {
fprintf(stderr, "test events track north clean d %u\r\n", ret_w);
return 0;
}
if ( 48 != (ret_w = _check_south_clean()) ) {
fprintf(stderr, "test events track south clean d %u\r\n", ret_w);
return 0;
}
_ce_loom_track_north(213, 42);
_ce_loom_track_south(15, 33);
if ( 213 != (ret_w = _check_north_clean()) ) {
fprintf(stderr, "test events track north clean e %u\r\n", ret_w);
return 0;
}
if ( 42 != (ret_w = _check_north_dirty(213, 42)) ) {
fprintf(stderr, "test events track north dirty e %u\r\n", ret_w);
return 0;
}
if ( 15 != (ret_w = _check_south_clean()) ) {
fprintf(stderr, "test events track south clean e %u\r\n", ret_w);
return 0;
}
if ( 33 != (ret_w = _check_south_dirty(15, 33)) ) {
fprintf(stderr, "test events track north dirty e %u\r\n", ret_w);
return 0;
}
_ce_loom_track_north(200, 13);
_ce_loom_track_south(10, 5);
if ( 200 != (ret_w = _check_north_clean()) ) {
fprintf(stderr, "test events track north clean f %u\r\n", ret_w);
return 0;
}
if ( 13 != (ret_w = _check_north_dirty(200, 13)) ) {
fprintf(stderr, "test events track north dirty f %u\r\n", ret_w);
return 0;
}
if ( 10 != (ret_w = _check_south_clean()) ) {
fprintf(stderr, "test events track south clean f %u\r\n", ret_w);
return 0;
}
if ( 5 != (ret_w = _check_south_dirty(10, 5)) ) {
fprintf(stderr, "test events track north dirty f %u\r\n", ret_w);
return 0;
}
_ce_loom_track_north(0, u3P.pag_w);
if ( u3P.pag_w != (ret_w = _check_north_dirty(0, u3P.pag_w)) ) {
fprintf(stderr, "test events track north dirty all %u\r\n", ret_w);
return 0;
}
return 1;
}
/* main(): run all test cases.
*/
int
main(int argc, char* argv[])
{
_setup();
if ( !_test_tracking() ) {
fprintf(stderr, "test_events: tracking: failed\r\n");
exit(1);
}
fprintf(stderr, "test_events: ok\n");
return 0;
}

View File

@ -9,8 +9,7 @@ c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w);
static void
_setup(void)
{
u3m_init(1 << 26);
u3m_pave(c3y);
u3m_boot_lite(1 << 26);
}
/* _test_bit_manipulation():

View File

@ -6,9 +6,7 @@
static void
_setup(void)
{
u3m_init(1 << 24);
u3m_pave(c3y);
u3e_init();
u3m_boot_lite(1 << 24);
}
static void

View File

@ -5,8 +5,7 @@
static void
_setup(void)
{
u3m_init(1 << 20);
u3m_pave(c3y);
u3m_boot_lite(1 << 20);
}
static inline c3_i

View File

@ -5,12 +5,7 @@
static void
_setup(void)
{
// XX at 1<<24, this succeeds on mac, but bail:exit's on linux.
// investigate possible u3n_prog corruption
//
u3m_init(1 << 25);
u3m_pave(c3y);
u3e_init();
u3m_boot_lite(1 << 24);
}
static u3_noun
@ -53,7 +48,7 @@ _test_nock_meme(void)
}
static c3_i
_test_nock(void)
_test_meme(void)
{
c3_i ret_i = 1;
@ -72,8 +67,8 @@ main(int argc, char* argv[])
{
_setup();
if ( !_test_nock() ) {
fprintf(stderr, "test nock: failed\r\n");
if ( !_test_meme() ) {
fprintf(stderr, "test meme: failed\r\n");
exit(1);
}
@ -81,6 +76,6 @@ main(int argc, char* argv[])
//
u3m_grab(u3_none);
fprintf(stderr, "test nock: ok\r\n");
fprintf(stderr, "test meme: ok\r\n");
return 0;
}

View File

@ -5,8 +5,7 @@
static void
_setup(void)
{
u3m_init(1 << 20);
u3m_pave(c3y);
u3m_boot_lite(1 << 20);
}
/* _test_mug(): spot check u3r_mug hashes.

View File

@ -6,8 +6,7 @@
static void
_setup(void)
{
u3m_init(1 << 20);
u3m_pave(c3y);
u3m_boot_lite(1 << 20);
}
/* _newt_encode(): synchronous serialization into a single buffer, for test purposes

View File

@ -8,8 +8,7 @@
static void
_setup(void)
{
u3m_init(1 << 20);
u3m_pave(c3y);
u3m_boot_lite(1 << 20);
}
/* _test_u3r_chop: "extract bit slices from atom"

View File

@ -225,6 +225,112 @@ u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d)
}
}
/* u3_lmdb_walk_init(): initialize db iterator.
*/
c3_o
u3_lmdb_walk_init(MDB_env* env_u,
u3_lmdb_walk* itr_u,
c3_d nex_d,
c3_d las_d)
{
// XX assumes little-endian
//
MDB_val key_u = { .mv_size = sizeof(c3_d), .mv_data = &nex_d };
MDB_val val_u;
c3_w ops_w, ret_w;
itr_u->red_o = c3n;
itr_u->nex_d = nex_d;
itr_u->las_d = las_d;
// create a read-only transaction.
//
ops_w = MDB_RDONLY;
if ( (ret_w = mdb_txn_begin(env_u, 0, ops_w, &itr_u->txn_u)) ) {
mdb_logerror(stderr, ret_w, "lmdb: read txn_begin fail");
return c3n;
}
// open the database in the transaction
//
ops_w = MDB_CREATE | MDB_INTEGERKEY;
if ( (ret_w = mdb_dbi_open(itr_u->txn_u, "EVENTS", ops_w, &itr_u->mdb_u)) ) {
mdb_logerror(stderr, ret_w, "lmdb: read: dbi_open fail");
// XX confirm
//
mdb_txn_abort(itr_u->txn_u);
return c3n;
}
// creates a cursor to iterate over keys starting at [eve_d]
//
if ( (ret_w = mdb_cursor_open(itr_u->txn_u, itr_u->mdb_u, &itr_u->cur_u)) ) {
mdb_logerror(stderr, ret_w, "lmdb: read: cursor_open fail");
// XX confirm
//
mdb_txn_abort(itr_u->txn_u);
return c3n;
}
// set the cursor to the position of [eve_d]
//
ops_w = MDB_SET_KEY;
if ( (ret_w = mdb_cursor_get(itr_u->cur_u, &key_u, &val_u, ops_w)) ) {
mdb_logerror(stderr, ret_w, "lmdb: read: initial cursor_get failed");
fprintf(stderr, " at %" PRIu64 "\r\n", nex_d);
mdb_cursor_close(itr_u->cur_u);
// XX confirm
//
mdb_txn_abort(itr_u->txn_u);
return c3n;
}
return c3y;
}
/* u3_lmdb_walk_next(): synchronously read next event from iterator.
*/
c3_o
u3_lmdb_walk_next(u3_lmdb_walk* itr_u, size_t* len_i, void** buf_v)
{
MDB_val key_u, val_u;
c3_w ret_w, ops_w;
c3_assert( itr_u->nex_d <= itr_u->las_d );
ops_w = ( c3y == itr_u->red_o ) ? MDB_NEXT : MDB_GET_CURRENT;
if ( (ret_w = mdb_cursor_get(itr_u->cur_u, &key_u, &val_u, ops_w)) ) {
mdb_logerror(stderr, ret_w, "lmdb: walk error");
return c3n;
}
// sanity check: ensure contiguous event numbers
//
if ( *(c3_d*)key_u.mv_data != itr_u->nex_d ) {
fprintf(stderr, "lmdb: read gap: expected %" PRIu64
", received %" PRIu64 "\r\n",
itr_u->nex_d,
*(c3_d*)key_u.mv_data);
return c3n;
}
*len_i = val_u.mv_size;
*buf_v = val_u.mv_data;
itr_u->nex_d++;
itr_u->red_o = c3y;
return c3y;
}
/* u3_lmdb_walk_done(): close iterator.
*/
void
u3_lmdb_walk_done(u3_lmdb_walk* itr_u)
{
mdb_cursor_close(itr_u->cur_u);
mdb_txn_abort(itr_u->txn_u);
}
/* u3_lmdb_read(): read [len_d] events starting at [eve_d].
*/
c3_o

View File

@ -22,6 +22,12 @@ struct _cd_save {
struct _u3_disk* log_u;
};
struct _u3_disk_walk {
u3_lmdb_walk itr_u;
u3_disk* log_u;
c3_o liv_o;
};
#undef VERBOSE_DISK
#undef DISK_TRACE_JAM
#undef DISK_TRACE_CUE
@ -149,34 +155,47 @@ _disk_commit_start(struct _cd_save* req_u)
_disk_commit_after_cb);
}
/* _disk_serialize_v1(): serialize events in format v1.
/* u3_disk_etch(): serialize an event for persistence. RETAIN [eve]
*/
static c3_w
_disk_serialize_v1(u3_fact* tac_u, c3_y** out_y)
size_t
u3_disk_etch(u3_disk* log_u,
u3_noun eve,
c3_l mug_l,
c3_y** out_y)
{
size_t len_i;
c3_y* dat_y;
#ifdef DISK_TRACE_JAM
u3t_event_trace("king disk jam", 'B');
u3t_event_trace("disk etch", 'B');
#endif
// XX check version number in log_u
// XX needs api redesign to limit allocations
//
{
u3_atom mat = u3qe_jam(tac_u->job);
u3_atom mat = u3qe_jam(eve);
c3_w len_w = u3r_met(3, mat);
c3_y* dat_y = c3_malloc(4 + len_w);
dat_y[0] = tac_u->mug_l & 0xff;
dat_y[1] = (tac_u->mug_l >> 8) & 0xff;
dat_y[2] = (tac_u->mug_l >> 16) & 0xff;
dat_y[3] = (tac_u->mug_l >> 24) & 0xff;
len_i = 4 + len_w;
dat_y = c3_malloc(len_i);
dat_y[0] = mug_l & 0xff;
dat_y[1] = (mug_l >> 8) & 0xff;
dat_y[2] = (mug_l >> 16) & 0xff;
dat_y[3] = (mug_l >> 24) & 0xff;
u3r_bytes(0, len_w, dat_y + 4, mat);
u3z(mat);
}
#ifdef DISK_TRACE_JAM
u3t_event_trace("king disk jam", 'E');
u3t_event_trace("disk etch", 'E');
#endif
u3z(mat);
*out_y = dat_y;
return len_w + 4;
}
*out_y = dat_y;
return len_i;
}
/* _disk_batch(): create a write batch
@ -200,7 +219,8 @@ _disk_batch(u3_disk* log_u, c3_d len_d)
for ( c3_d i_d = 0ULL; i_d < len_d; ++i_d) {
c3_assert( (req_u->eve_d + i_d) == tac_u->eve_d );
req_u->siz_i[i_d] = _disk_serialize_v1(tac_u, &req_u->byt_y[i_d]);
req_u->siz_i[i_d] = u3_disk_etch(log_u, tac_u->job,
tac_u->mug_l, &req_u->byt_y[i_d]);
tac_u = tac_u->nex_u;
}
@ -358,6 +378,41 @@ _disk_read_done_cb(uv_timer_t* tim_u)
_disk_read_close(red_u);
}
/* u3_disk_sift(): parse a persisted event buffer.
*/
c3_o
u3_disk_sift(u3_disk* log_u,
size_t len_i,
c3_y* dat_y,
c3_l* mug_l,
u3_noun* job)
{
if ( 4 >= len_i ) {
return c3n;
}
#ifdef DISK_TRACE_CUE
u3t_event_trace("disk sift", 'B');
#endif
// XX check version in log_u
//
*mug_l = dat_y[0]
^ (dat_y[1] << 8)
^ (dat_y[2] << 16)
^ (dat_y[3] << 24);
// XX u3m_soft?
//
*job = u3ke_cue(u3i_bytes(len_i - 4, dat_y + 4));
#ifdef DISK_TRACE_CUE
u3t_event_trace("disk sift", 'E');
#endif
return c3y;
}
/* _disk_read_one_cb(): lmdb read callback, invoked for each event in order
*/
static c3_o
@ -367,29 +422,13 @@ _disk_read_one_cb(void* ptr_v, c3_d eve_d, size_t val_i, void* val_p)
u3_disk* log_u = red_u->log_u;
u3_fact* tac_u;
if ( 4 >= val_i ) {
return c3n;
}
{
u3_noun job;
c3_y* dat_y = val_p;
c3_l mug_l = dat_y[0]
^ (dat_y[1] << 8)
^ (dat_y[2] << 16)
^ (dat_y[3] << 24);
c3_l mug_l;
#ifdef DISK_TRACE_CUE
u3t_event_trace("king disk cue", 'B');
#endif
// XX u3m_soft?
//
job = u3ke_cue(u3i_bytes(val_i - 4, dat_y + 4));
#ifdef DISK_TRACE_CUE
u3t_event_trace("king disk cue", 'E');
#endif
if ( c3n == u3_disk_sift(log_u, val_i, (c3_y*)val_p, &mug_l, &job) ) {
return c3n;
}
tac_u = u3_fact_init(eve_d, mug_l, job);
}
@ -461,6 +500,120 @@ u3_disk_read(u3_disk* log_u, c3_d eve_d, c3_d len_d)
uv_timer_start(&red_u->tim_u, _disk_read_start_cb, 0, 0);
}
struct _cd_list {
u3_disk* log_u;
u3_noun eve;
c3_l mug_l;
};
/* _disk_read_list_cb(): lmdb read callback, invoked for each event in order
*/
static c3_o
_disk_read_list_cb(void* ptr_v, c3_d eve_d, size_t val_i, void* val_p)
{
struct _cd_list* ven_u = ptr_v;
u3_disk* log_u = ven_u->log_u;
{
u3_noun job;
c3_l mug_l;
if ( c3n == u3_disk_sift(log_u, val_i, (c3_y*)val_p, &mug_l, &job) ) {
return c3n;
}
ven_u->mug_l = mug_l;
ven_u->eve = u3nc(job, ven_u->eve);
}
return c3y;
}
/* u3_disk_read_list(): synchronously read a cons list of events.
*/
u3_weak
u3_disk_read_list(u3_disk* log_u, c3_d eve_d, c3_d len_d, c3_l* mug_l)
{
struct _cd_list ven_u = { log_u, u3_nul, 0 };
if ( c3n == u3_lmdb_read(log_u->mdb_u, &ven_u,
eve_d, len_d, _disk_read_list_cb) )
{
return u3_none;
}
*mug_l = ven_u.mug_l;
return u3kb_flop(ven_u.eve);
}
/* u3_disk_walk_init(): init iterator.
*/
u3_disk_walk*
u3_disk_walk_init(u3_disk* log_u,
c3_d eve_d,
c3_d len_d)
{
u3_disk_walk* wok_u = c3_malloc(sizeof(*wok_u));
c3_d max_d = eve_d + len_d - 1;
wok_u->log_u = log_u;
wok_u->liv_o = u3_lmdb_walk_init(log_u->mdb_u,
&wok_u->itr_u,
eve_d,
c3_min(max_d, log_u->dun_d));
return wok_u;
}
/* u3_disk_walk_live(): check if live.
*/
c3_o
u3_disk_walk_live(u3_disk_walk* wok_u)
{
if ( wok_u->itr_u.nex_d > wok_u->itr_u.las_d ) {
wok_u->liv_o = c3n;
}
return wok_u->liv_o;
}
/* u3_disk_walk_step(): get next fact.
*/
c3_o
u3_disk_walk_step(u3_disk_walk* wok_u, u3_fact* tac_u)
{
u3_disk* log_u = wok_u->log_u;
size_t len_i;
void* buf_v;
tac_u->eve_d = wok_u->itr_u.nex_d;
if ( c3n == u3_lmdb_walk_next(&wok_u->itr_u, &len_i, &buf_v) ) {
fprintf(stderr, "disk: (%" PRIu64 "): read fail\r\n", tac_u->eve_d);
return wok_u->liv_o = c3n;
}
if ( c3n == u3_disk_sift(log_u, len_i,
(c3_y*)buf_v,
&tac_u->mug_l,
&tac_u->job) )
{
fprintf(stderr, "disk: (%" PRIu64 "): sift fail\r\n", tac_u->eve_d);
return wok_u->liv_o = c3n;
}
return c3y;
}
/* u3_disk_walk_done(): close iterator.
*/
void
u3_disk_walk_done(u3_disk_walk* wok_u)
{
u3_lmdb_walk_done(&wok_u->itr_u);
c3_free(wok_u);
}
/* _disk_save_meta(): serialize atom, save as metadata at [key_c].
*/
static c3_o

View File

@ -1504,6 +1504,61 @@ _http_serv_init_h2o(SSL_CTX* tls_u, c3_o log, c3_o red)
return h2o_u;
}
/* _http_serv_start_err(): handle errors in starting http server.
*/
static c3_i
_http_serv_start_err(const c3_c* cap_c, u3_http* htp_u, c3_i sas_i)
{
u3_pier* pir_u = htp_u->htd_u->car_u.pir_u;
if ( UV_EADDRNOTAVAIL == sas_i ) {
u3l_log("http: unavailable ip address %s\r\n", u3_Host.ops_u.bin_c);
u3_king_bail();
return 0;
}
// ports specified, no incrementing/retry
//
if ( c3y == htp_u->dis ) {
u3l_log("http: %s (%" PRIu16 "): %s\n",
cap_c, htp_u->por_s, uv_strerror(sas_i));
u3_king_bail();
return 0;
}
// increment and retry
//
if ( (UV_EADDRINUSE == sas_i) || (UV_EACCES == sas_i) ) {
if ( (c3y == htp_u->sec) && (443 == htp_u->por_s) ) {
htp_u->por_s = 8443;
}
else if ( (c3n == htp_u->sec) && (80 == htp_u->por_s) ) {
htp_u->por_s = 8080;
}
else {
htp_u->por_s++;
// XX
//
if ( c3n == htp_u->lop ) {
if ( c3y == htp_u->sec ) {
pir_u->pes_s = htp_u->por_s;
}
else {
pir_u->per_s = htp_u->por_s;
}
}
}
return 1;
}
// total failure XX bail?
//
u3l_log("http: %s: %s\n", cap_c, uv_strerror(sas_i));
_http_serv_free(htp_u);
return 0;
}
/* _http_serv_start(): start http server.
*/
static void
@ -1519,10 +1574,12 @@ _http_serv_start(u3_http* htp_u)
INADDR_ANY;
if ( 0 != u3_Host.ops_u.bin_c && c3n == htp_u->lop ) {
// already validated in arguments parser
//
inet_pton(AF_INET, u3_Host.ops_u.bin_c, &adr_u.sin_addr);
}
uv_tcp_init(u3L, &htp_u->wax_u);
c3_assert( !uv_tcp_init(u3L, &htp_u->wax_u) );
/* Try ascending ports.
*/
@ -1532,46 +1589,25 @@ _http_serv_start(u3_http* htp_u)
adr_u.sin_port = htons(htp_u->por_s);
if ( 0 != (sas_i = uv_tcp_bind(&htp_u->wax_u,
(const struct sockaddr*)&adr_u, 0)) ||
0 != (sas_i = uv_listen((uv_stream_t*)&htp_u->wax_u,
TCP_BACKLOG, _http_serv_listen_cb)) ) {
if ( UV_EADDRNOTAVAIL == sas_i ) {
u3l_log("http: ip address not available\n");
u3_king_bail();
}
if ( c3y == htp_u->dis ) {
u3l_log("http: listen (%" PRIu16 "): %s\n", htp_u->por_s,
uv_strerror(sas_i));
u3_king_bail();
}
if ( (UV_EADDRINUSE == sas_i) || (UV_EACCES == sas_i) ) {
if ( (c3y == htp_u->sec) && (443 == htp_u->por_s) ) {
htp_u->por_s = 8443;
}
else if ( (c3n == htp_u->sec) && (80 == htp_u->por_s) ) {
htp_u->por_s = 8080;
}
else {
htp_u->por_s++;
// XX
//
if ( c3n == htp_u->lop ) {
if ( c3y == htp_u->sec ) {
pir_u->pes_s = htp_u->por_s;
}
else {
pir_u->per_s = htp_u->por_s;
}
}
}
(const struct sockaddr*)&adr_u, 0)) )
{
if ( _http_serv_start_err("bind", htp_u, sas_i) ) {
continue;
}
else {
return;
}
}
u3l_log("http: listen: %s\n", uv_strerror(sas_i));
_http_serv_free(htp_u);
return;
if ( 0 != (sas_i = uv_listen((uv_stream_t*)&htp_u->wax_u,
TCP_BACKLOG, _http_serv_listen_cb)) )
{
if ( _http_serv_start_err("listen", htp_u, sas_i) ) {
continue;
}
else {
return;
}
}
u3l_log("http: %s live on %s://localhost:%d\n",
@ -1677,24 +1713,30 @@ _http_init_tls(uv_buf_t key_u, uv_buf_t cer_u)
static void
_http_write_ports_file(u3_httd* htd_u, c3_c *pax_c)
{
c3_c* nam_c = ".http.ports";
c3_w len_w = 1 + strlen(pax_c) + 1 + strlen(nam_c);
c3_c* paf_c = c3_malloc(len_w);
snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c);
c3_i por_i = c3_open(paf_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_free(paf_c);
u3_http* htp_u = htd_u->htp_u;
u3_pier* pir_u = htd_u->car_u.pir_u;
size_t off_i = 0;
c3_i por_i;
{
c3_c* nam_c = ".http.ports";
c3_w len_w = 1 + strlen(pax_c) + 1 + strlen(nam_c);
c3_c* paf_c = c3_malloc(len_w);
snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c);
por_i = c3_open(paf_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_free(paf_c);
}
c3_c temp[32];
while ( 0 != htp_u ) {
if ( 0 < htp_u->por_s ) {
u3_write_fd(por_i, temp, snprintf(temp, 32, "%u %s %s\n", htp_u->por_s,
(c3y == htp_u->sec) ? "secure" : "insecure",
(c3y == htp_u->lop) ? "loopback" : "public"));
c3_c tmp_c[32];
c3_i len_i = snprintf(tmp_c, 32, "%u %s %s\n",
htp_u->por_s,
(c3y == htp_u->sec) ? "secure" : "insecure",
(c3y == htp_u->lop) ? "loopback" : "public");
c3_assert( 0 < len_i);
c3_assert( c3_pwrite(por_i, tmp_c, len_i, off_i) == len_i );
off_i += len_i;
}
htp_u = htp_u->nex_u;
@ -1710,13 +1752,12 @@ static void
_http_release_ports_file(c3_c *pax_c)
{
c3_c* nam_c = ".http.ports";
c3_w len_w = 1 + strlen(pax_c) + 1 + strlen(nam_c);
c3_w len_w = 1 + strlen(pax_c) + 1 + strlen(nam_c);
c3_c* paf_c = c3_malloc(len_w);
c3_i wit_i;
wit_i = snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c);
c3_assert(wit_i > 0);
c3_assert(len_w == (c3_w)wit_i + 1);
c3_assert( len_w == (c3_w)wit_i + 1 );
c3_unlink(paf_c);
c3_free(paf_c);

View File

@ -17,48 +17,6 @@ static void _term_read_cb(uv_stream_t* tcp_u,
ssize_t siz_i,
const uv_buf_t* buf_u);
/* u3_write_fd(): retry interrupts, continue partial writes, assert errors.
*/
void
u3_write_fd(c3_i fid_i, const void* buf_v, size_t len_i)
{
ssize_t ret_i;
while ( len_i > 0 ) {
c3_w lop_w = 0;
// retry interrupt/async errors
//
do {
// abort pathological retry loop
//
if ( 100 == ++lop_w ) {
fprintf(stderr, "term: write loop: %s\r\n", strerror(errno));
return;
}
ret_i = write(fid_i, buf_v, len_i);
}
while ( (ret_i < 0)
&& ( (errno == EINTR)
|| (errno == EAGAIN)
|| (errno == EWOULDBLOCK) ));
// assert on true errors
//
// NB: can't call u3l_log here or we would re-enter u3_write_fd()
//
if ( ret_i < 0 ) {
fprintf(stderr, "term: write failed %s\r\n", strerror(errno));
c3_assert(0);
}
// continue partial writes
//
else {
len_i -= ret_i;
buf_v += ret_i;
}
}
}
/* _term_msc_out_host(): unix microseconds from current host time.
*/
static c3_d
@ -255,7 +213,7 @@ u3_term_log_exit(void)
if ( c3n == uty_u->sto_f(uty_u) ) {
c3_assert(!"exit-tcsetattr");
}
u3_write_fd(uty_u->fid_i, "\r\n", 2);
c3_assert(c3_write(uty_u->fid_i, "\r\n", 2) == 2);
}
}
@ -864,7 +822,7 @@ _term_spin_step(u3_utty* uty_u)
c3_w i_w;
for ( i_w = bac_w; i_w < sol_w; i_w++ ) {
if ( lef_u.len != write(fid_i, lef_u.base, lef_u.len) ) {
if ( c3_write(fid_i, lef_u.base, lef_u.len) < 0 ) {
return;
}
}
@ -874,7 +832,7 @@ _term_spin_step(u3_utty* uty_u)
{
c3_w len_w = cur_c - buf_c;
if ( len_w != write(fid_i, buf_c, len_w) ) {
if ( c3_write(fid_i, buf_c, len_w) < 0 ) {
return;
}
}
@ -882,7 +840,7 @@ _term_spin_step(u3_utty* uty_u)
// Cursor stays on spinner.
//
while ( sol_w-- ) {
if ( lef_u.len != write(fid_i, lef_u.base, lef_u.len) ) {
if ( c3_write(fid_i, lef_u.base, lef_u.len) < 0 ) {
return;
}
}
@ -1044,7 +1002,9 @@ u3_term_ef_ctlc(void)
_term_ovum_plan(uty_u->car_u, wir, cad);
}
_term_it_refresh_line(uty_u);
if ( c3n == u3_Host.ops_u.tem ) {
_term_it_refresh_line(uty_u);
}
}
/* _term_it_put_value(): put numeric color value on lin_w.
@ -1382,10 +1342,10 @@ u3_term_io_hija(void)
if ( c3y != uty_u->hij_f(uty_u) ) {
c3_assert(!"hija-tcsetattr");
}
u3_write_fd(uty_u->fid_i, "\r", 1);
c3_assert(c3_write(uty_u->fid_i, "\r", 1) == 1);
{
uv_buf_t* buf_u = &uty_u->ufo_u.out.el_u;
u3_write_fd(uty_u->fid_i, buf_u->base, buf_u->len);
c3_assert(c3_write(uty_u->fid_i, buf_u->base, buf_u->len) == buf_u->len);
}
}
}

View File

@ -342,11 +342,11 @@ u3_unix_save(c3_c* pax_c, u3_atom pad)
pad_y = c3_malloc(fln_w);
u3r_bytes(0, fln_w, pad_y, pad);
u3z(pad);
rit_w = write(fid_i, pad_y, fln_w);
ssize_t rit_i = c3_pwrite(fid_i, pad_y, fln_w, 0);
close(fid_i);
c3_free(pad_y);
if ( rit_w != fln_w ) {
if ( rit_i < 0 ) {
u3l_log("%s: %s\n", ful_c, strerror(errno));
c3_free(ful_c);
u3m_bail(c3__fail);
@ -427,7 +427,7 @@ static c3_w
_unix_write_file_hard(c3_c* pax_c, u3_noun mim)
{
c3_i fid_i = c3_open(pax_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_w len_w, rit_w, siz_w, mug_w = 0;
c3_w len_w, siz_w, mug_w = 0;
c3_y* dat_y;
u3_noun dat = u3t(u3t(mim));
@ -446,11 +446,10 @@ _unix_write_file_hard(c3_c* pax_c, u3_noun mim)
u3r_bytes(0, len_w, dat_y, dat);
u3z(mim);
rit_w = write(fid_i, dat_y, siz_w);
ssize_t rit_i = c3_pwrite(fid_i, dat_y, siz_w, 0);
if ( rit_w != siz_w ) {
u3l_log("error writing %s: %s\r\n",
pax_c, strerror(errno));
if ( rit_i < 0 ) {
u3l_log("error writing %s: %s\r\n", pax_c, strerror(errno));
mug_w = 0;
}
else {
@ -470,7 +469,7 @@ _unix_write_file_soft(u3_ufil* fil_u, u3_noun mim)
{
struct stat buf_u;
c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644);
c3_ws len_ws, red_ws;
c3_ws len_ws;
c3_w old_w;
c3_y* old_y;
@ -489,21 +488,21 @@ _unix_write_file_soft(u3_ufil* fil_u, u3_noun mim)
len_ws = buf_u.st_size;
old_y = c3_malloc(len_ws);
red_ws = read(fid_i, old_y, len_ws);
ssize_t red_i = c3_pread(fid_i, old_y, len_ws, 0);
if ( close(fid_i) < 0 ) {
u3l_log("error closing file (soft) %s: %s\r\n",
fil_u->pax_c, strerror(errno));
}
if ( len_ws != red_ws ) {
if ( red_ws < 0 ) {
if ( red_i != len_ws ) {
if ( red_i < 0 ) {
u3l_log("error reading file (soft) %s: %s\r\n",
fil_u->pax_c, strerror(errno));
fil_u->pax_c, strerror(-red_i));
}
else {
u3l_log("wrong # of bytes read in file %s: %d %d\r\n",
fil_u->pax_c, len_ws, red_ws);
u3l_log("wrong # of bytes read in file %s: %u %zu\r\n",
fil_u->pax_c, len_ws, red_i);
}
c3_free(old_y);
u3z(mim);
@ -893,7 +892,7 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u)
struct stat buf_u;
c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644);
c3_ws len_ws, red_ws;
c3_ws len_ws;
c3_y* dat_y;
if ( fid_i < 0 || fstat(fid_i, &buf_u) < 0 ) {
@ -910,21 +909,21 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u)
len_ws = buf_u.st_size;
dat_y = c3_malloc(len_ws);
red_ws = read(fid_i, dat_y, len_ws);
ssize_t red_i = c3_pread(fid_i, dat_y, len_ws, 0);
if ( close(fid_i) < 0 ) {
u3l_log("error closing file %s: %s\r\n",
fil_u->pax_c, strerror(errno));
}
if ( len_ws != red_ws ) {
if ( red_ws < 0 ) {
if ( red_i != len_ws ) {
if ( red_i < 0 ) {
u3l_log("error reading file %s: %s\r\n",
fil_u->pax_c, strerror(errno));
fil_u->pax_c, strerror(-red_i));
}
else {
u3l_log("wrong # of bytes read in file %s: %d %d\r\n",
fil_u->pax_c, len_ws, red_ws);
u3l_log("wrong # of bytes read in file %s: %u %zu\r\n",
fil_u->pax_c, len_ws, red_i);
}
c3_free(dat_y);
return u3_nul;
@ -1159,7 +1158,7 @@ _unix_initial_update_file(c3_c* pax_c, c3_c* bas_c)
{
struct stat buf_u;
c3_i fid_i = c3_open(pax_c, O_RDONLY, 0644);
c3_ws len_ws, red_ws;
c3_ws len_ws;
c3_y* dat_y;
if ( fid_i < 0 || fstat(fid_i, &buf_u) < 0 ) {
@ -1176,21 +1175,21 @@ _unix_initial_update_file(c3_c* pax_c, c3_c* bas_c)
len_ws = buf_u.st_size;
dat_y = c3_malloc(len_ws);
red_ws = read(fid_i, dat_y, len_ws);
ssize_t red_i = c3_pread(fid_i, dat_y, len_ws, 0);
if ( close(fid_i) < 0 ) {
u3l_log("error closing initial file %s: %s\r\n",
pax_c, strerror(errno));
}
if ( len_ws != red_ws ) {
if ( red_ws < 0 ) {
if ( red_i != len_ws ) {
if ( red_i < 0 ) {
u3l_log("error reading initial file %s: %s\r\n",
pax_c, strerror(errno));
pax_c, strerror(-red_i));
}
else {
u3l_log("wrong # of bytes read in initial file %s: %d %d\r\n",
pax_c, len_ws, red_ws);
u3l_log("wrong # of bytes read in initial file %s: %u %zu\r\n",
pax_c, len_ws, red_i);
}
c3_free(dat_y);
return u3_nul;

View File

@ -307,7 +307,7 @@ _king_get_pace(void)
{
struct stat buf_u;
c3_c* pat_c;
c3_w red_w, len_w;
c3_w len_w;
c3_i ret_i, fid_i;
ret_i = asprintf(&pat_c, "%s/.bin/pace", u3_Host.dir_c);
@ -324,10 +324,10 @@ _king_get_pace(void)
len_w = buf_u.st_size;
pat_c = c3_malloc(len_w + 1);
red_w = read(fid_i, pat_c, len_w);
ssize_t red_i = c3_pread(fid_i, pat_c, len_w, 0);
close(fid_i);
if ( len_w != red_w ) {
if ( red_i != len_w ) {
c3_free(pat_c);
u3l_log("unable to read pace file, "
"falling back to default (\"live\")\n");
@ -1038,9 +1038,6 @@ _king_make_pace(c3_c* pac_c)
return 0;
}
static c3_i
_king_write_raw(c3_i fid_i, c3_y* buf_y, size_t len_i);
/* _king_init_pace(): save pace file if not present
*/
static c3_i
@ -1064,8 +1061,11 @@ _king_init_pace(c3_c* pac_c)
}
}
if ( _king_write_raw(fid_i, (c3_y*)pac_c, strlen(pac_c)) ) {
u3l_log("dock: init pace (%s): write %s\n", pac_c, strerror(errno));
size_t len_i = strlen(pac_c);
ssize_t wit_i = c3_pwrite(fid_i, pac_c, len_i, 0);
if ( wit_i != len_i ) {
u3l_log("dock: init pace (%s) write failed: %s\n",
pac_c, strerror(errno));
close(fid_i);
c3_free(bin_c);
return -1;
@ -1239,62 +1239,24 @@ _king_do_upgrade(c3_c* pac_c, c3_c* ver_c)
// XX print restart instructions
}
/* _king_read_raw: read (up to) [len_i] from [fid_i] to [buf_y]
*/
static ssize_t
_king_read_raw(c3_i fid_i, c3_y* buf_y, size_t len_i)
{
ssize_t ret_i;
do {
ret_i = read(fid_i, buf_y, len_i);
}
while ( (ret_i < 0) && (errno == EINTR) );
return ret_i;
}
/* _king_read_raw: write [len_i] from [buf_y] to [fid_i].
*/
static c3_i
_king_write_raw(c3_i fid_i, c3_y* buf_y, size_t len_i)
{
ssize_t ret_i;
while ( len_i ) {
do {
ret_i = write(fid_i, buf_y, len_i);
}
while ( (ret_i < 0) && (errno == EINTR) );
if ( ret_i < 0 ) {
return -1;
}
else {
len_i -= ret_i;
buf_y += ret_i;
}
}
return 0;
}
static c3_i
_king_copy_raw(c3_i src_i, c3_i dst_i, c3_y* buf_y, size_t pag_i)
{
ssize_t red_i;
size_t off_i = 0;
ssize_t ret_i;
do {
if ( 0 > (red_i = _king_read_raw(src_i, buf_y, pag_i)) ) {
return -1;
if ( 0 > (ret_i = c3_pread(src_i, buf_y, pag_i, off_i)) ) {
return ret_i;
}
if ( _king_write_raw(dst_i, buf_y, (size_t)red_i) ) {
return -1;
if ( 0 > (ret_i = c3_pwrite(dst_i, buf_y, (size_t)ret_i, off_i)) ) {
return ret_i;
}
off_i += (size_t)ret_i;
}
while ( red_i );
while ( ret_i );
return 0;
}
@ -1337,6 +1299,8 @@ _king_copy_file(c3_c* src_c, c3_c* dst_c)
goto done1;
}
// XX O_TRUNC?
//
if ( -1 == (dst_i = open(dst_c, O_RDWR | O_CREAT, 0755)) ) {
err_i = errno;
ret_i = -1;
@ -1403,8 +1367,12 @@ _king_copy_file(c3_c* src_c, c3_c* dst_c)
{
size_t pag_i = 1 << 14;;
c3_y* buf_y = c3_malloc(pag_i);
ret_i = _king_copy_raw(src_i, dst_i, buf_y, pag_i);
err_i = errno;
if ( 0 > (ret_i = _king_copy_raw(src_i, dst_i, buf_y, pag_i)) ) {
err_i = errno;
ret_i = -1;
}
c3_free(buf_y);
}

View File

@ -1051,7 +1051,7 @@ _lord_on_serf_err_cb(uv_stream_t* pyp_u,
// serf used to write to 2 directly
// this can't be any worse than that
//
u3_write_fd(2, buf_u->base, siz_i);
c3_assert(c3_write(STDERR_FILENO, buf_u->base, siz_i) == siz_i);
} else {
uv_read_stop(pyp_u);

View File

@ -1 +1 @@
1.13
1.14-rc3

267
pkg/urbit/worker/mars.c Normal file
View File

@ -0,0 +1,267 @@
/* worker/mars.c
**
** the main loop of a mars process.
*/
#include "all.h"
#include <vere/vere.h>
#include <vere/mars.h>
/* _mars_step_trace(): initialize or rotate trace file.
*/
static void
_mars_step_trace(const c3_c* dir_c)
{
if ( u3C.wag_w & u3o_trace ) {
if ( u3_Host.tra_u.con_w == 0 && u3_Host.tra_u.fun_w == 0 ) {
u3t_trace_open(dir_c);
}
else if ( u3_Host.tra_u.con_w >= 100000 ) {
u3t_trace_close();
u3t_trace_open(dir_c);
}
}
}
/* _mars_poke_play(): replay an event.
*/
static u3_weak
_mars_poke_play(u3_mars* mar_u, c3_d eve_d, u3_noun job)
{
u3_noun vir;
if ( c3n == u3v_poke_sure(0, job, &vir) ) {
return vir;
}
u3z(vir);
return u3_none;
}
typedef enum {
_play_yes_e, // success
_play_mem_e, // %meme
_play_int_e, // %intr
_play_log_e, // event log fail
_play_mug_e, // mug mismatch
_play_bad_e // total failure
} _mars_play_e;
/* _mars_play_batch(): replay a batch of events.
*/
static _mars_play_e
_mars_play_batch(u3_mars* mar_u, c3_o mug_o, c3_w bat_w)
{
u3_disk* log_u = mar_u->log_u;
u3_disk_walk* wok_u = u3_disk_walk_init(log_u, mar_u->dun_d + 1, bat_w);
u3_fact tac_u;
u3_noun dud;
while ( c3y == u3_disk_walk_live(wok_u) ) {
if ( c3n == u3_disk_walk_step(wok_u, &tac_u) ) {
u3_disk_walk_done(wok_u);
return _play_log_e;
}
c3_assert( ++mar_u->sen_d == tac_u.eve_d );
if ( u3_none != (dud = _mars_poke_play(mar_u, tac_u.eve_d, tac_u.job)) ) {
c3_m mot_m;
mar_u->sen_d = mar_u->dun_d;
u3_disk_walk_done(wok_u);
c3_assert( c3y == u3r_safe_word(u3h(dud), &mot_m) );
switch ( mot_m ) {
case c3__meme: {
fprintf(stderr, "play (%" PRIu64 "): %%meme\r\n", tac_u.eve_d);
u3z(dud);
return _play_mem_e;
}
case c3__intr: {
fprintf(stderr, "play (%" PRIu64 "): %%intr\r\n", tac_u.eve_d);
u3z(dud);
return _play_int_e;
}
default: {
fprintf(stderr, "play (%" PRIu64 "): failed\r\n", tac_u.eve_d);
u3_pier_punt_goof("play", dud);
// XX say something uplifting
//
return _play_bad_e;
}
}
}
mar_u->mug_l = u3r_mug(u3A->roc);
if ( tac_u.mug_l && (mar_u->mug_l != tac_u.mug_l) ) {
fprintf(stderr, "play (%" PRIu64 "): mug mismatch "
"expected %08x, actual %08x\r\n",
tac_u.eve_d, tac_u.mug_l, mar_u->mug_l);
if ( c3y == mug_o ) {
mar_u->sen_d = mar_u->dun_d;
u3_disk_walk_done(wok_u);
return _play_mug_e;
}
}
mar_u->dun_d = mar_u->sen_d;
}
u3_disk_walk_done(wok_u);
return _play_yes_e;
}
static c3_o
_mars_do_boot(u3_disk* log_u, c3_d eve_d)
{
u3_weak eve;
c3_l mug_l;
if ( u3_none == (eve = u3_disk_read_list(log_u, 1, eve_d, &mug_l)) ) {
fprintf(stderr, "boot: read failed\r\n");
return c3n;
}
u3l_log("--------------- bootstrap starting ----------------\r\n");
u3l_log("boot: 1-%u\r\n", u3qb_lent(eve));
if ( c3n == u3v_boot(eve) ) {
return c3n;
}
u3l_log("--------------- bootstrap complete ----------------\r\n");
return c3y;
}
/* u3_mars_play(): replay logged events up to [eve_d].
*/
void
u3_mars_play(u3_mars* mar_u, c3_d eve_d)
{
u3_disk* log_u = mar_u->log_u;
if ( !eve_d ) {
eve_d = log_u->dun_d;
}
else if ( eve_d <= mar_u->dun_d ) {
u3l_log("mars: already computed %" PRIu64 "\r\n", eve_d);
u3l_log(" state=%" PRIu64 ", log=%" PRIu64 "\r\n",
mar_u->dun_d, log_u->dun_d);
return;
}
else {
eve_d = c3_min(eve_d, log_u->dun_d);
}
if ( !mar_u->dun_d ) {
c3_w lif_w;
if ( c3n == u3_disk_read_meta(log_u, 0, 0, &lif_w) ) {
fprintf(stderr, "mars: disk read meta fail\r\n");
// XX exit code, cb
//
exit(1);
}
if ( c3n == _mars_do_boot(mar_u->log_u, lif_w) ) {
fprintf(stderr, "mars: boot fail\r\n");
// XX exit code, cb
//
exit(1);
}
mar_u->sen_d = mar_u->dun_d = lif_w;
}
if ( mar_u->dun_d == log_u->dun_d ) {
u3l_log("mars: nothing to do!\r\n");
return;
}
u3l_log("---------------- playback starting ----------------\r\n");
if ( (1ULL + eve_d) == log_u->dun_d ) {
u3l_log("play: event %" PRIu64 "\r\n", log_u->dun_d);
}
else if ( eve_d != log_u->dun_d ) {
u3l_log("play: events %" PRIu64 "-%" PRIu64 " of %" PRIu64 "\r\n",
(c3_d)(1ULL + mar_u->dun_d),
eve_d,
log_u->dun_d);
}
else {
u3l_log("play: events %" PRIu64 "-%" PRIu64 "\r\n",
(c3_d)(1ULL + mar_u->dun_d),
eve_d);
}
{
c3_d mem_d = 0; // last event to meme
c3_w try_w = 0; // [mem_d] retry count
while ( mar_u->dun_d < eve_d ) {
_mars_step_trace(mar_u->dir_c);
// XX get batch from args
//
switch ( _mars_play_batch(mar_u, c3y, 1024) ) {
case _play_yes_e: {
u3l_log("play (%" PRIu64 "): done\r\n", mar_u->dun_d);
u3m_reclaim();
// XX save a snapshot every N events?
//
} break;
case _play_mem_e: {
if ( mem_d != mar_u->dun_d ) {
mem_d = mar_u->dun_d;
try_w = 0;
}
else if ( 3 == ++try_w ) {
fprintf(stderr, "play (%" PRIu64 "): failed\r\n", mar_u->dun_d + 1);
u3m_save();
// XX check loom size, suggest --loom X
// XX exit code, cb
//
u3_disk_exit(log_u);
exit(1);
}
// XX pack before meld?
//
if ( u3C.wag_w & u3o_auto_meld ) {
u3a_print_memory(stderr, "mars: meld: gained", u3u_meld());
}
else {
u3a_print_memory(stderr, "mars: pack: gained", u3m_pack());
}
} break;
// XX handle any specifically?
//
case _play_int_e:
case _play_log_e:
case _play_mug_e:
case _play_bad_e: {
fprintf(stderr, "play (%" PRIu64 "): failed\r\n", mar_u->dun_d + 1);
u3m_save();
// XX exit code, cb
//
u3_disk_exit(log_u);
exit(1);
}
}
}
}
u3l_log("---------------- playback complete ----------------\r\n");
u3m_save();
}

View File

@ -49,137 +49,6 @@
--
*/
/* _serf_space(): print n spaces.
*/
static void
_serf_space(FILE* fil_u, c3_w n)
{
for (; n > 0; n--)
(fprintf(fil_u," "));
}
/* _serf_print_memory(): print memory amount.
**
** Helper for _serf_prof(), just an un-captioned u3a_print_memory().
*/
static void
_serf_print_memory(FILE* fil_u, c3_w wor_w)
{
c3_w byt_w = (wor_w * 4);
c3_w gib_w = (byt_w / 1000000000);
c3_w mib_w = (byt_w % 1000000000) / 1000000;
c3_w kib_w = (byt_w % 1000000) / 1000;
c3_w bib_w = (byt_w % 1000);
if ( gib_w ) {
(fprintf(fil_u, "GB/%d.%03d.%03d.%03d\r\n",
gib_w, mib_w, kib_w, bib_w));
}
else if ( mib_w ) {
(fprintf(fil_u, "MB/%d.%03d.%03d\r\n", mib_w, kib_w, bib_w));
}
else if ( kib_w ) {
(fprintf(fil_u, "KB/%d.%03d\r\n", kib_w, bib_w));
}
else {
(fprintf(fil_u, "B/%d\r\n", bib_w));
}
}
/* _serf_prof(): print memory profile. RETAIN.
*/
c3_w
_serf_prof(FILE* fil_u, c3_w den, u3_noun mas)
{
c3_w tot_w = 0;
u3_noun h_mas, t_mas;
if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) {
_serf_space(fil_u, den);
fprintf(fil_u, "mistyped mass\r\n");
return tot_w;
}
else if ( _(u3du(h_mas)) ) {
_serf_space(fil_u, den);
fprintf(fil_u, "mistyped mass head\r\n");
{
c3_c* lab_c = u3m_pretty(h_mas);
fprintf(fil_u, "h_mas: %s", lab_c);
c3_free(lab_c);
}
return tot_w;
}
else {
_serf_space(fil_u, den);
{
c3_c* lab_c = u3m_pretty(h_mas);
fprintf(fil_u, "%s: ", lab_c);
c3_free(lab_c);
}
u3_noun it_mas, tt_mas;
if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) {
fprintf(fil_u, "mistyped mass tail\r\n");
return tot_w;
}
else if ( c3y == it_mas ) {
tot_w += u3a_mark_noun(tt_mas);
_serf_print_memory(fil_u, tot_w);
#if 1
/* The basic issue here is that tt_mas is included in .sac
* (the whole profile), so they can't both be roots in the
* normal sense. When we mark .sac later on, we want tt_mas
* to appear unmarked, but its children should be already
* marked.
*/
if ( _(u3a_is_dog(tt_mas)) ) {
u3a_box* box_u = u3a_botox(u3a_to_ptr(tt_mas));
#ifdef U3_MEMORY_DEBUG
if ( 1 == box_u->eus_w ) {
box_u->eus_w = 0xffffffff;
}
else {
box_u->eus_w -= 1;
}
#else
if ( -1 == (c3_w)box_u->use_w ) {
box_u->use_w = 0x80000000;
}
else {
box_u->use_w += 1;
}
#endif
}
#endif
return tot_w;
}
else if ( c3n == it_mas ) {
fprintf(fil_u, "\r\n");
while ( _(u3du(tt_mas)) ) {
tot_w += _serf_prof(fil_u, den+2, u3h(tt_mas));
tt_mas = u3t(tt_mas);
}
_serf_space(fil_u, den);
fprintf(fil_u, "--");
_serf_print_memory(fil_u, tot_w);
return tot_w;
}
else {
_serf_space(fil_u, den);
fprintf(fil_u, "mistyped (strange) mass tail\r\n");
return tot_w;
}
}
}
/* _serf_grab(): garbage collect, checking for profiling. RETAIN.
*/
static void
@ -200,7 +69,7 @@ _serf_grab(u3_noun sac)
c3_c* wen_c = u3r_string(wen);
c3_c nam_c[2048];
snprintf(nam_c, 2048, "%s/.urb/put/mass", u3P.dir_c);
snprintf(nam_c, 2048, "%s/.urb/put/mass", u3C.dir_c);
struct stat st;
if ( -1 == stat(nam_c, &st) ) {
@ -225,7 +94,7 @@ _serf_grab(u3_noun sac)
c3_assert( u3R == &(u3H->rod_u) );
fprintf(fil_u, "\r\n");
tot_w += u3a_maid(fil_u, "total userspace", _serf_prof(fil_u, 0, sac));
tot_w += u3a_maid(fil_u, "total userspace", u3a_prof(fil_u, 0, sac));
tot_w += u3m_mark(fil_u);
tot_w += u3a_maid(fil_u, "space profile", u3a_mark_noun(sac));
@ -839,7 +708,7 @@ _serf_writ_live_exit(u3_serf* sef_u, c3_w cod_w)
c3_c* wen_c = u3r_string(wen);
c3_c nam_c[2048];
snprintf(nam_c, 2048, "%s/.urb/put/profile", u3P.dir_c);
snprintf(nam_c, 2048, "%s/.urb/put/profile", u3C.dir_c);
struct stat st;
if ( -1 == stat(nam_c, &st) ) {
@ -883,7 +752,7 @@ _serf_writ_live_save(u3_serf* sef_u, c3_d eve_d)
exit(1);
}
u3e_save();
u3m_save();
}
/* u3_serf_live(): apply %live command [com], producing *ret on c3y.
@ -954,7 +823,7 @@ u3_serf_live(u3_serf* sef_u, u3_noun com, u3_noun* ret)
return c3n;
}
u3e_save();
u3m_save();
u3_serf_grab();
*ret = u3nc(c3__live, u3_nul);
@ -981,7 +850,7 @@ u3_serf_live(u3_serf* sef_u, u3_noun com, u3_noun* ret)
}
else {
u3z(com);
u3u_meld();
u3a_print_memory(stderr, "serf: meld: gained", u3u_meld());
*ret = u3nc(c3__live, u3_nul);
return c3y;
}