Compare commits

...
17 Commits
Author SHA1 Message Date
hyung-hwan f652443ad2 openvms porting 2026-09-20 03:47:09 +09:00
hyung-hwan cfc8171b46 added tryCritical to Mutex and the vm primitive sem-trywait for it 2026-09-19 21:33:13 +09:00
hyung-hwan 8c2f034082 a little code clean-up 2026-09-19 02:29:50 +09:00
hyung-hwan fe7d4c9da1 fixed the segfault for the ownership issue of the stack context with core.fork 2026-09-18 20:44:22 +09:00
hyung-hwan 1d17f1e708 fixed the mssing stack finalization is multiple process manipulation primitive functions 2026-09-15 20:29:09 +09:00
hyung-hwan f99a8c87f0 updated the Semaphore methods to relay the return value of primitive calls 2026-09-12 11:49:10 +09:00
hyung-hwan 7be5d0fe61 code simplification by using MUXEVT_FD in more places 2026-09-12 11:33:51 +09:00
hyung-hwan baa01b22e3 relocated signal primitives to the sys module 2026-09-11 23:12:40 +09:00
hyung-hwan 58d1234020 added ticker to bin/main.go 2026-09-11 16:01:36 +09:00
hyung-hwan bcdc7d8d36 ported the same command line options to the go code 2026-09-11 14:36:51 +09:00
hyung-hwan 1a8cc6ef43 split HAK_OPT_MODLIBDIRS and HAK_OPT_INCDIRS to BCSTR/UCSTR 2026-09-11 12:33:30 +09:00
hyung-hwan 15b42bc269 make the style of option enumerators more uniform 2026-09-11 12:02:12 +09:00
hyung-hwan 992b1344a8 update hak.go with modlibdirs and incdirs... still not complete 2026-09-11 10:58:28 +09:00
hyung-hwan 27115ca792 added HAK_OPT_INCDIRS 2026-09-11 10:44:58 +09:00
hyung-hwan 05b7e3f728 added the option.incdirs field 2026-09-10 06:00:04 +00:00
hyung-hwan e63dc2c2a0 relocated some primitive functions(process,semaphore,etc) to the core module 2026-09-10 14:30:51 +09:00
hyung-hwan 92caa7e8db creating Seamphore and SemaphoreGroup classes 2026-09-10 13:53:25 +09:00
56 changed files with 2710 additions and 837 deletions
+14 -1
View File
@@ -121,14 +121,27 @@ CGO_CFLAGS_EXTRA=""
CGO_LDFLAGS_EXTRA="" CGO_LDFLAGS_EXTRA=""
endif endif
if WIN32
# go does not infer the target from CC, so a cross build needs GOOS/GOARCH set
# explicitly - otherwise it runs the host toolchain against the mingw compiler.
# GOARCH is mapped from $(host_cpu) at recipe time. windows has no libdl, and
# libhak pulls in winsock, so the system libraries differ from the posix case.
CGO_TARGET_ENV = GOOS=windows CGO_ENABLED=1 GOARCH=`case "$(host_cpu)" in i?86) echo 386;; x86_64|amd64) echo amd64;; aarch64|arm64) echo arm64;; *) echo "$(host_cpu)";; esac`
CGO_SYS_LIBS = -lws2_32
else
CGO_TARGET_ENV =
CGO_SYS_LIBS = -ldl
endif
hakgo$(EXEEXT): ../lib/libhak.la $(hakgo_OBJECTS) hakgo$(EXEEXT): ../lib/libhak.la $(hakgo_OBJECTS)
##cp -pf $(top_srcdir)/go.mod $(builddir)/go.mod >/dev/null 2>&1 || true ##cp -pf $(top_srcdir)/go.mod $(builddir)/go.mod >/dev/null 2>&1 || true
##chmod u+w $(builddir)/go.mod ## with `make distcheck`, the echo's redirection to the file fails without this permission change ##chmod u+w $(builddir)/go.mod ## with `make distcheck`, the echo's redirection to the file fails without this permission change
[ -f $(srcdir)/go.sum ] && cp -pf $(srcdir)/go.sum $(builddir)/go.sum >/dev/null 2>&1 || true [ -f $(srcdir)/go.sum ] && cp -pf $(srcdir)/go.sum $(builddir)/go.sum >/dev/null 2>&1 || true
## --------------------------------------------------------------- ## ---------------------------------------------------------------
CC=$(CC) \ CC=$(CC) \
$(CGO_TARGET_ENV) \
CGO_CFLAGS="-I$(abs_top_srcdir)/lib -I$(abs_top_builddir)/lib $(CFLAGS) $(CGO_CFLAGS_EXTRA)" \ CGO_CFLAGS="-I$(abs_top_srcdir)/lib -I$(abs_top_builddir)/lib $(CFLAGS) $(CGO_CFLAGS_EXTRA)" \
CGO_LDFLAGS="-L$(abs_top_builddir)/lib -L$(abs_top_builddir)/lib/.libs -lhak -ldl $(LIBM) $(CGO_LDFLAGS_EXTRA)" \ CGO_LDFLAGS="-L$(abs_top_builddir)/lib -L$(abs_top_builddir)/lib/.libs -lhak $(CGO_SYS_LIBS) $(LIBM) $(CGO_LDFLAGS_EXTRA)" \
go build -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -o $(abs_builddir)/$@ -modfile $(abs_top_srcdir)/go.mod $(abs_srcdir)/main.go go build -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -o $(abs_builddir)/$@ -modfile $(abs_top_srcdir)/go.mod $(abs_srcdir)/main.go
## --------------------------------------------------------------- ## ---------------------------------------------------------------
go clean -C $(srcdir) -x -modfile $(abs_top_srcdir)/go.mod go clean -C $(srcdir) -x -modfile $(abs_top_srcdir)/go.mod
+11 -1
View File
@@ -490,6 +490,15 @@ hak_DEPENDENCIES = ../lib/libhak.la $(am__append_5)
@ENABLE_HAKGO_TRUE@@ENABLE_STATIC_TRUE@CGO_CFLAGS_EXTRA = "-static" @ENABLE_HAKGO_TRUE@@ENABLE_STATIC_TRUE@CGO_CFLAGS_EXTRA = "-static"
@ENABLE_HAKGO_TRUE@@ENABLE_STATIC_FALSE@CGO_LDFLAGS_EXTRA = "" @ENABLE_HAKGO_TRUE@@ENABLE_STATIC_FALSE@CGO_LDFLAGS_EXTRA = ""
@ENABLE_HAKGO_TRUE@@ENABLE_STATIC_TRUE@CGO_LDFLAGS_EXTRA = "-static" @ENABLE_HAKGO_TRUE@@ENABLE_STATIC_TRUE@CGO_LDFLAGS_EXTRA = "-static"
@ENABLE_HAKGO_TRUE@@WIN32_FALSE@CGO_TARGET_ENV =
# go does not infer the target from CC, so a cross build needs GOOS/GOARCH set
# explicitly - otherwise it runs the host toolchain against the mingw compiler.
# GOARCH is mapped from $(host_cpu) at recipe time. windows has no libdl, and
# libhak pulls in winsock, so the system libraries differ from the posix case.
@ENABLE_HAKGO_TRUE@@WIN32_TRUE@CGO_TARGET_ENV = GOOS=windows CGO_ENABLED=1 GOARCH=`case "$(host_cpu)" in i?86) echo 386;; x86_64|amd64) echo amd64;; aarch64|arm64) echo arm64;; *) echo "$(host_cpu)";; esac`
@ENABLE_HAKGO_TRUE@@WIN32_FALSE@CGO_SYS_LIBS = -ldl
@ENABLE_HAKGO_TRUE@@WIN32_TRUE@CGO_SYS_LIBS = -lws2_32
all: all-am all: all-am
.SUFFIXES: .SUFFIXES:
@@ -981,8 +990,9 @@ uninstall-am: uninstall-binPROGRAMS
@ENABLE_HAKGO_TRUE@hakgo$(EXEEXT): ../lib/libhak.la $(hakgo_OBJECTS) @ENABLE_HAKGO_TRUE@hakgo$(EXEEXT): ../lib/libhak.la $(hakgo_OBJECTS)
@ENABLE_HAKGO_TRUE@ [ -f $(srcdir)/go.sum ] && cp -pf $(srcdir)/go.sum $(builddir)/go.sum >/dev/null 2>&1 || true @ENABLE_HAKGO_TRUE@ [ -f $(srcdir)/go.sum ] && cp -pf $(srcdir)/go.sum $(builddir)/go.sum >/dev/null 2>&1 || true
@ENABLE_HAKGO_TRUE@ CC=$(CC) \ @ENABLE_HAKGO_TRUE@ CC=$(CC) \
@ENABLE_HAKGO_TRUE@ $(CGO_TARGET_ENV) \
@ENABLE_HAKGO_TRUE@ CGO_CFLAGS="-I$(abs_top_srcdir)/lib -I$(abs_top_builddir)/lib $(CFLAGS) $(CGO_CFLAGS_EXTRA)" \ @ENABLE_HAKGO_TRUE@ CGO_CFLAGS="-I$(abs_top_srcdir)/lib -I$(abs_top_builddir)/lib $(CFLAGS) $(CGO_CFLAGS_EXTRA)" \
@ENABLE_HAKGO_TRUE@ CGO_LDFLAGS="-L$(abs_top_builddir)/lib -L$(abs_top_builddir)/lib/.libs -lhak -ldl $(LIBM) $(CGO_LDFLAGS_EXTRA)" \ @ENABLE_HAKGO_TRUE@ CGO_LDFLAGS="-L$(abs_top_builddir)/lib -L$(abs_top_builddir)/lib/.libs -lhak $(CGO_SYS_LIBS) $(LIBM) $(CGO_LDFLAGS_EXTRA)" \
@ENABLE_HAKGO_TRUE@ go build -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -o $(abs_builddir)/$@ -modfile $(abs_top_srcdir)/go.mod $(abs_srcdir)/main.go @ENABLE_HAKGO_TRUE@ go build -C $(srcdir) -ldflags "-X 'main.BINDIR=$(bindir)' -X 'main.SBINDIR=$(sbindir)' -X 'main.LIBDIR=$(libdir)' -X 'main.SYSCONFDIR=$(sysconfdir)'" -x -o $(abs_builddir)/$@ -modfile $(abs_top_srcdir)/go.mod $(abs_srcdir)/main.go
@ENABLE_HAKGO_TRUE@ go clean -C $(srcdir) -x -modfile $(abs_top_srcdir)/go.mod @ENABLE_HAKGO_TRUE@ go clean -C $(srcdir) -x -modfile $(abs_top_srcdir)/go.mod
+51 -49
View File
@@ -249,8 +249,8 @@ static int handle_logopt (hak_t* hak, const hak_bch_t* logstr)
} }
fname.ptr = (hak_bch_t*)logstr; fname.ptr = (hak_bch_t*)logstr;
hak_setoption (hak, HAK_LOG_TARGET_BCS, &fname); hak_setoption (hak, HAK_OPT_LOG_TARGET_BCS, &fname);
hak_setoption (hak, HAK_LOG_MASK, &logmask); hak_setoption (hak, HAK_OPT_LOG_MASK, &logmask);
return 0; return 0;
} }
@@ -280,9 +280,9 @@ static int handle_dbgopt (hak_t* hak, const hak_bch_t* str)
} }
while (cm); while (cm);
hak_getoption(hak, HAK_TRAIT, &trait); hak_getoption(hak, HAK_OPT_TRAIT, &trait);
trait |= dbgopt; trait |= dbgopt;
hak_setoption(hak, HAK_TRAIT, &trait); hak_setoption(hak, HAK_OPT_TRAIT, &trait);
return 0; return 0;
} }
#endif #endif
@@ -303,19 +303,19 @@ typedef void(*signal_handler_t)(int);
#if defined(_WIN32) || defined(__DOS__) || defined(__OS2__) #if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
static void handle_sigint (int sig) static void handle_sigint (int sig)
{ {
if (g_hak) hak_abort (g_hak); if (g_hak) hak_abort(g_hak);
} }
#elif defined(macintosh) #elif defined(macintosh)
/* TODO */ /* TODO */
#elif defined(SA_SIGINFO) #elif defined(SA_SIGINFO)
static void handle_sigint (int sig, siginfo_t* siginfo, void* ctx) static void handle_sigint (int sig, siginfo_t* siginfo, void* ctx)
{ {
if (g_hak) hak_abort (g_hak); if (g_hak) hak_abort(g_hak);
} }
#else #else
static void handle_sigint (int sig) static void handle_sigint (int sig)
{ {
if (g_hak) hak_abort (g_hak); if (g_hak) hak_abort(g_hak);
} }
#endif #endif
@@ -328,7 +328,7 @@ static void set_signal (int sig, signal_handler_t handler)
#else #else
struct sigaction sa; struct sigaction sa;
memset (&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
/*sa.sa_handler = handler;*/ /*sa.sa_handler = handler;*/
#if defined(SA_SIGINFO) #if defined(SA_SIGINFO)
sa.sa_flags = SA_SIGINFO; sa.sa_flags = SA_SIGINFO;
@@ -336,16 +336,16 @@ static void set_signal (int sig, signal_handler_t handler)
#else #else
sa.sa_handler = handler; sa.sa_handler = handler;
#endif #endif
sigemptyset (&sa.sa_mask); sigemptyset(&sa.sa_mask);
sigaction (sig, &sa, NULL); sigaction(sig, &sa, NULL);
#endif #endif
} }
static void set_signal_to_default (int sig) static void set_signal_to_default (int sig)
{ {
#if defined(_WIN32) || defined(__DOS__) || defined(__OS2__) #if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
signal (sig, SIG_DFL); signal(sig, SIG_DFL);
#elif defined(macintosh) #elif defined(macintosh)
/* TODO: implement this */ /* TODO: implement this */
#else #else
@@ -354,27 +354,27 @@ static void set_signal_to_default (int sig)
memset (&sa, 0, sizeof(sa)); memset (&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
sa.sa_flags = 0; sa.sa_flags = 0;
sigemptyset (&sa.sa_mask); sigemptyset(&sa.sa_mask);
sigaction (sig, &sa, NULL); sigaction(sig, &sa, NULL);
#endif #endif
} }
static void set_signal_to_ignore (int sig) static void set_signal_to_ignore (int sig)
{ {
#if defined(_WIN32) || defined(__DOS__) || defined(__OS2__) #if defined(_WIN32) || defined(__DOS__) || defined(__OS2__)
signal (sig, SIG_IGN); signal(sig, SIG_IGN);
#elif defined(macintosh) #elif defined(macintosh)
/* TODO: implement this */ /* TODO: implement this */
#else #else
struct sigaction sa; struct sigaction sa;
memset (&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN; sa.sa_handler = SIG_IGN;
sa.sa_flags = 0; sa.sa_flags = 0;
sigemptyset (&sa.sa_mask); sigemptyset (&sa.sa_mask);
sigaction (sig, &sa, NULL); sigaction(sig, &sa, NULL);
#endif #endif
} }
@@ -689,7 +689,7 @@ static int feed_loop (hak_t* hak, xtn_t* xtn, int verbose)
FILE* fp = HAK_NULL; FILE* fp = HAK_NULL;
int is_tty; int is_tty;
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) #if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) && (__STDC_WANT_SECURE_LIB__ > 0)
errno_t err = fopen_s(&fp, xtn->cci_path, FOPEN_R_FLAGS); errno_t err = fopen_s(&fp, xtn->cci_path, FOPEN_R_FLAGS);
if (err != 0) if (err != 0)
{ {
@@ -865,6 +865,7 @@ int main (int argc, char* argv[])
{ ":debug", '\0' }, { ":debug", '\0' },
#endif #endif
{ ":heapsize", '\0' }, { ":heapsize", '\0' },
{ ":incdirs", 'I' },
{ ":log", 'l' }, { ":log", 'l' },
{ "info", '\0' }, { "info", '\0' },
{ ":modlibdirs", '\0' }, { ":modlibdirs", '\0' },
@@ -873,7 +874,7 @@ int main (int argc, char* argv[])
}; };
static hak_bopt_t opt = static hak_bopt_t opt =
{ {
"l:v", "I:l:v",
lopt lopt
}; };
@@ -882,6 +883,7 @@ int main (int argc, char* argv[])
int verbose = 0; int verbose = 0;
int show_info = 0; int show_info = 0;
const char* modlibdirs = HAK_NULL; const char* modlibdirs = HAK_NULL;
const char* incdirs = HAK_NULL;
#if defined(HAK_BUILD_DEBUG) #if defined(HAK_BUILD_DEBUG)
const char* dbgopt = HAK_NULL; const char* dbgopt = HAK_NULL;
@@ -895,10 +897,11 @@ int main (int argc, char* argv[])
print_usage: print_usage:
fprintf(stderr, "Usage: %s [options] script-filename [output-filename]\n", argv[0]); fprintf(stderr, "Usage: %s [options] script-filename [output-filename]\n", argv[0]);
fprintf(stderr, "Options are:\n"); fprintf(stderr, "Options are:\n");
fprintf(stderr, " --info show build information\n"); fprintf(stderr, " --info show build information\n");
fprintf(stderr, " -l, --log string specify the log file path and options\n"); fprintf(stderr, " -I, --incdirs string specify the list of include directories\n");
fprintf(stderr, " --modlibdirs string specify directories to load modules from\n"); fprintf(stderr, " -l, --log string specify the log file path and options\n");
fprintf(stderr, " -v show verbose messages\n"); fprintf(stderr, " --modlibdirs string specify directories to load modules from\n");
fprintf(stderr, " -v show verbose messages\n");
return -1; return -1;
} }
@@ -907,6 +910,10 @@ int main (int argc, char* argv[])
{ {
switch (c) switch (c)
{ {
case 'I':
incdirs = opt.arg;
break;
case 'l': case 'l':
logopt = opt.arg; logopt = opt.arg;
break; break;
@@ -980,15 +987,15 @@ int main (int argc, char* argv[])
{ {
hak_oow_t tab_size; hak_oow_t tab_size;
tab_size = HAK_DFL_SYMTAB_SIZE; tab_size = HAK_DFL_SYMTAB_SIZE;
hak_setoption (hak, HAK_SYMTAB_SIZE, &tab_size); hak_setoption (hak, HAK_OPT_SYMTAB_SIZE, &tab_size);
tab_size = HAK_DFL_SYSDIC_SIZE; tab_size = HAK_DFL_SYSDIC_SIZE;
hak_setoption (hak, HAK_SYSDIC_SIZE, &tab_size); hak_setoption (hak, HAK_OPT_SYSDIC_SIZE, &tab_size);
tab_size = HAK_DFL_PROCSTK_SIZE; /* TODO: choose a better stack size or make this user specifiable */ tab_size = HAK_DFL_PROCSTK_SIZE; /* TODO: choose a better stack size or make this user specifiable */
hak_setoption (hak, HAK_PROCSTK_SIZE, &tab_size); hak_setoption (hak, HAK_OPT_PROCSTK_SIZE, &tab_size);
tab_size = HAK_DFL_EXSTK_SIZE; /* TODO: choose a better stack size or make this user specifiable */ tab_size = HAK_DFL_EXSTK_SIZE; /* TODO: choose a better stack size or make this user specifiable */
hak_setoption (hak, HAK_EXSTK_SIZE, &tab_size); hak_setoption (hak, HAK_OPT_EXSTK_SIZE, &tab_size);
tab_size = HAK_DFL_CLSTK_SIZE; /* TODO: choose a better stack size or make this user specifiable */ tab_size = HAK_DFL_CLSTK_SIZE; /* TODO: choose a better stack size or make this user specifiable */
hak_setoption (hak, HAK_CLSTK_SIZE, &tab_size); hak_setoption (hak, HAK_OPT_CLSTK_SIZE, &tab_size);
} }
{ {
@@ -997,34 +1004,29 @@ int main (int argc, char* argv[])
/*trait |= HAK_TRAIT_NOGC;*/ /*trait |= HAK_TRAIT_NOGC;*/
trait |= HAK_TRAIT_AWAIT_PROCS; trait |= HAK_TRAIT_AWAIT_PROCS;
trait |= HAK_TRAIT_LANG_ENABLE_EOL; trait |= HAK_TRAIT_LANG_ENABLE_EOL;
hak_setoption (hak, HAK_TRAIT, &trait); hak_setoption (hak, HAK_OPT_TRAIT, &trait);
}
if (incdirs)
{
/* the option is stored in both encodings, so the byte form from
* the command line goes in as is - no conversion needed here. */
if (hak_setoption(hak, HAK_OPT_INCDIRS_BCSTR, incdirs) <= -1)
{
hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot set incdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
goto oops;
}
} }
if (modlibdirs) if (modlibdirs)
{ {
#if defined(HAK_OOCH_IS_UCH) /* the option is stored in both encodings, so the byte form from
hak_ooch_t* tmp; * the command line goes in as is - no conversion needed here. */
tmp = hak_dupbtoucstr(hak, modlibdirs, HAK_NULL); if (hak_setoption(hak, HAK_OPT_MODLIBDIRS_BCSTR, modlibdirs) <= -1)
if (HAK_UNLIKELY(!tmp))
{
hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot duplicate modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
goto oops;
}
if (hak_setoption(hak, HAK_MOD_LIBDIRS, tmp) <= -1)
{
hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot set modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
hak_freemem(hak, tmp);
goto oops;
}
hak_freemem(hak, tmp);
#else
if (hak_setoption(hak, HAK_MOD_LIBDIRS, modlibdirs) <= -1)
{ {
hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot set modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak)); hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot set modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
goto oops; goto oops;
} }
#endif
} }
memset (&hakcb, 0, HAK_SIZEOF(hakcb)); memset (&hakcb, 0, HAK_SIZEOF(hakcb));
@@ -1095,9 +1097,9 @@ int main (int argc, char* argv[])
// in the non-INTERACTIVE mode, the compiler generates MAKE_BLOCK for lambda functions. // in the non-INTERACTIVE mode, the compiler generates MAKE_BLOCK for lambda functions.
{ {
hak_bitmask_t trait; hak_bitmask_t trait;
hak_getoption(hak, HAK_TRAIT, &trait); hak_getoption(hak, HAK_OPT_TRAIT, &trait);
trait |= HAK_TRAIT_INTERACTIVE; trait |= HAK_TRAIT_INTERACTIVE;
hak_setoption(hak, HAK_TRAIT, &trait); hak_setoption(hak, HAK_OPT_TRAIT, &trait);
} }
#endif #endif
+8 -3
View File
@@ -395,20 +395,25 @@ static file_type_t os_get_filetype(const char* cpath) {
#define dir_cursor intptr_t #define dir_cursor intptr_t
#define dir_entry struct __finddata64_t /* [hak] _findfirsti64/_findnexti64 do not pair with struct __finddata64_t on
* mingw-w64: there they resolve to _findfirst32i64/_findnext32i64, which take
* a struct _finddata32i64_t. the plain _findfirst/_findnext and _finddata_t
* are macro-mapped to each other consistently by both msvc and mingw-w64, and
* only entry->name is ever read here, so the 64-bit file size is not needed. */
#define dir_entry struct _finddata_t
static bool os_findfirst(alloc_t* mem, const char* path, dir_cursor* d, dir_entry* entry) { static bool os_findfirst(alloc_t* mem, const char* path, dir_cursor* d, dir_entry* entry) {
stringbuf_t* spath = sbuf_new(mem); stringbuf_t* spath = sbuf_new(mem);
if (spath == NULL) return false; if (spath == NULL) return false;
sbuf_append(spath, path); sbuf_append(spath, path);
sbuf_append(spath, "\\*"); sbuf_append(spath, "\\*");
*d = _findfirsti64(sbuf_string(spath), entry); *d = _findfirst(sbuf_string(spath), entry);
mem_free(mem,spath); mem_free(mem,spath);
return (*d != -1); return (*d != -1);
} }
static bool os_findnext(dir_cursor d, dir_entry* entry) { static bool os_findnext(dir_cursor d, dir_entry* entry) {
return (_findnexti64(d, entry) == 0); return (_findnext(d, entry) == 0);
} }
static void os_findclose(dir_cursor d) { static void os_findclose(dir_cursor d) {
+1
View File
@@ -17,6 +17,7 @@
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
#include <io.h> // [hak] isatty() lives here on windows, not in <unistd.h>
#define STDOUT_FILENO 1 #define STDOUT_FILENO 1
#else #else
#include <unistd.h> #include <unistd.h>
+217 -16
View File
@@ -4,8 +4,10 @@ import (
"flag" "flag"
"fmt" "fmt"
"hak" "hak"
"io"
"os" "os"
//"strings" "strings"
"time"
) )
/* /*
@@ -18,6 +20,9 @@ import (
`)) `))
*/ */
/* 0 means no pre-allocated heap, as in bin/hak.c */
const DEFAULT_HEAPSIZE uint = 0
/* to be set in build time */ /* to be set in build time */
var BINDIR = "." var BINDIR = "."
var SBINDIR = "." var SBINDIR = "."
@@ -25,10 +30,14 @@ var LIBDIR = "."
var SYSCONFDIR = "." var SYSCONFDIR = "."
type Param struct { type Param struct {
log_file string log_target string
log_mask hak.BitMask
input_file string input_file string
heapsize uint heapsize uint
modlibdirs string modlibdirs string
incdirs string
verbose bool
show_info bool
fs_usage func() fs_usage func()
} }
@@ -36,6 +45,93 @@ func empty_usage() {
} }
/* the filter names accepted after the comma in --log, mirroring the xtab
* table in handle_logopt() of bin/hak.c. 'and' marks the entries that clear
* bits instead of setting them. */
type log_filter struct {
name string
and bool
mask hak.BitMask
}
var log_filters = []log_filter{
{"", false, 0},
{"app", false, hak.LOG_APP},
{"compiler", false, hak.LOG_COMPILER},
{"vm", false, hak.LOG_VM},
{"mnemonic", false, hak.LOG_MNEMONIC},
{"gc", false, hak.LOG_GC},
{"ic", false, hak.LOG_IC},
{"primitive", false, hak.LOG_PRIMITIVE},
/* a specific level */
{"fatal", false, hak.LOG_FATAL},
{"error", false, hak.LOG_ERROR},
{"warn", false, hak.LOG_WARN},
{"info", false, hak.LOG_INFO},
{"debug", false, hak.LOG_DEBUG},
/* a specific level or higher */
{"fatal+", false, hak.LOG_FATAL},
{"error+", false, hak.LOG_FATAL | hak.LOG_ERROR},
{"warn+", false, hak.LOG_FATAL | hak.LOG_ERROR | hak.LOG_WARN},
{"info+", false, hak.LOG_FATAL | hak.LOG_ERROR | hak.LOG_WARN | hak.LOG_INFO},
{"debug+", false, hak.LOG_FATAL | hak.LOG_ERROR | hak.LOG_WARN | hak.LOG_INFO | hak.LOG_DEBUG},
/* a specific level or lower */
{"fatal-", false, hak.LOG_FATAL | hak.LOG_ERROR | hak.LOG_WARN | hak.LOG_INFO | hak.LOG_DEBUG},
{"error-", false, hak.LOG_ERROR | hak.LOG_WARN | hak.LOG_INFO | hak.LOG_DEBUG},
{"warn-", false, hak.LOG_WARN | hak.LOG_INFO | hak.LOG_DEBUG},
{"info-", false, hak.LOG_INFO | hak.LOG_DEBUG},
{"debug-", false, hak.LOG_DEBUG},
/* exclude a specific level */
{"-fatal", true, ^hak.LOG_FATAL},
{"-error", true, ^hak.LOG_ERROR},
{"-warn", true, ^hak.LOG_WARN},
{"-info", true, ^hak.LOG_INFO},
{"-debug", true, ^hak.LOG_DEBUG},
}
/* split "path,filter,filter" into a target and a log mask. with no comma the
* whole string is the target and every level and type is enabled. */
func parse_logopt(logstr string) (string, hak.BitMask, error) {
var comma int = strings.Index(logstr, ",")
var mask hak.BitMask
if comma < 0 {
return logstr, hak.LOG_ALL_LEVELS | hak.LOG_ALL_TYPES, nil
}
for _, f := range strings.Split(logstr[comma+1:], ",") {
var i int
for i = 0; i < len(log_filters); i++ {
if log_filters[i].name == f {
if log_filters[i].and {
mask &= log_filters[i].mask
} else {
mask |= log_filters[i].mask
}
break
}
}
if i >= len(log_filters) {
return "", 0, fmt.Errorf("unrecognized log filter - %s - in %s", f, logstr)
}
}
/* nothing selected in a category means everything in that category */
if (mask & hak.LOG_ALL_TYPES) == 0 {
mask |= hak.LOG_ALL_TYPES
}
if (mask & hak.LOG_ALL_LEVELS) == 0 {
mask |= hak.LOG_ALL_LEVELS
}
return logstr[0:comma], mask, nil
}
func handle_arguments(param *Param) error { func handle_arguments(param *Param) error {
/* /*
var nargs int = len(os.Args) var nargs int = len(os.Args)
@@ -64,34 +160,110 @@ func handle_arguments(param *Param) error {
var fs *flag.FlagSet var fs *flag.FlagSet
var heapsize *uint var heapsize *uint
var modlibdirs *string var modlibdirs *string
var incdirs *string
var log *string var log *string
var verbose *bool
var show_info *bool
var err error var err error
fs = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
heapsize = fs.Uint("heapsize", 0, "specify heap size") /* the same set bin/hak.c accepts. the flag package treats -x and --x
modlibdirs = fs.String("modlibdirs", "", "specify module library directories") * alike, so registering both spellings of a short option is enough to
log = fs.String("log", "", "specify log file") * give -I and --incdirs the same destination. */
heapsize = fs.Uint("heapsize", DEFAULT_HEAPSIZE, "specify the heap size in bytes")
incdirs = fs.String("incdirs", "", "specify the list of include directories")
fs.StringVar(incdirs, "I", "", "specify the list of include directories")
log = fs.String("log", "", "specify the log file path and options")
fs.StringVar(log, "l", "", "specify the log file path and options")
modlibdirs = fs.String("modlibdirs", "", "specify directories to load modules from")
verbose = fs.Bool("v", false, "show verbose messages")
show_info = fs.Bool("info", false, "show build information")
param.fs_usage = fs.Usage param.fs_usage = fs.Usage
fs.Usage = empty_usage // i don't want fs.Parse() print the usage fs.Usage = empty_usage // i don't want fs.Parse() print the usage
fs.SetOutput(io.Discard) // nor its own copy of the error, which we report ourselves
err = fs.Parse(os.Args[1:]) err = fs.Parse(os.Args[1:])
fs.Usage = param.fs_usage // restore it fs.Usage = param.fs_usage // restore it
fs.SetOutput(os.Stderr) // so the restored usage still prints
if err != nil { if err != nil {
return fmt.Errorf("command line error - %s", err.Error()) return fmt.Errorf("command line error - %s", err.Error())
} }
param.heapsize = *heapsize
param.incdirs = *incdirs
param.modlibdirs = *modlibdirs
param.verbose = *verbose
param.show_info = *show_info
if *log != "" {
param.log_target, param.log_mask, err = parse_logopt(*log)
if err != nil {
return err
}
}
/* --info answers on its own and needs no script */
if param.show_info {
return nil
}
if fs.NArg() < 1 { if fs.NArg() < 1 {
return fmt.Errorf("no input file specified") return fmt.Errorf("no input file specified")
} else if fs.NArg() > 1 { } else if fs.NArg() > 1 {
/* bin/hak.c also takes an optional output file as the second
* argument, but the go binding attaches the user data streams
* through handler objects rather than a path, so there is nothing
* to pass it to yet. */
return fmt.Errorf("too many input files specified") return fmt.Errorf("too many input files specified")
} }
param.input_file = fs.Arg(0); param.input_file = fs.Arg(0)
param.log_file = *log // TODO: parse the option part (e.g. --log /dev/stderr,debug+) return nil
param.heapsize = *heapsize // TODO: set this to hak }
param.modlibdirs = *modlibdirs // TODO: set this to hak
return nil; func start_ticker(x *hak.Hak) func() {
var ticker *time.Ticker
var ticker_stop chan bool
var ticker_done chan bool
var stopper func()
ticker = time.NewTicker(20 * time.Millisecond)
ticker_done = make(chan bool)
ticker_stop = make(chan bool)
go func() {
for {
select {
case <- ticker_stop:
goto done
case <- ticker.C:
x.RaiseTick()
}
}
done:
ticker.Stop()
ticker_done <- true
}()
x.RcvTick(true)
stopper = func() {
x.RcvTick(false)
ticker_stop <- true
<- ticker_done // wait for the ticker to stop
// if i don't close the the two channels below, the multiple calls to the
// returned stopper function wouldn't cause immediate panic for writing
// on a closed channel. but i would still close them as i don't want to
// cater for generic use of this function and this function wasn't
// written to be generic. i don't care to use any other more advanced
// mechanisms. the caller must ensure to call this stopper only once.
close(ticker_stop)
close(ticker_done)
}
return stopper
} }
func main() { func main() {
@@ -99,6 +271,7 @@ func main() {
var x *hak.Hak = nil var x *hak.Hak = nil
var err error = nil var err error = nil
var param Param var param Param
var stop_ticker func()
var rfh hak.CciFileHandler var rfh hak.CciFileHandler
var sfh hak.UdiFileHandler var sfh hak.UdiFileHandler
@@ -111,20 +284,39 @@ func main() {
os.Exit(1) os.Exit(1)
} }
if param.show_info {
fmt.Println(hak.BuildInfo())
os.Exit(0)
}
x, err = hak.New() x, err = hak.New()
if err != nil { if err != nil {
fmt.Printf("ERROR: failed to instantiate hak - %s\n", err.Error()) fmt.Printf("ERROR: failed to instantiate hak - %s\n", err.Error())
os.Exit(1) os.Exit(1)
} }
if param.log_file != "" { if param.log_target != "" {
x.SetLogMask(^hak.BitMask(0)) /* honour both halves of --log. the previous code discarded the path
x.SetLogTarget("/dev/stderr") * and always logged everything to /dev/stderr. */
x.SetLogMask(param.log_mask)
err = x.SetLogTarget(param.log_target)
if err != nil {
fmt.Printf("ERROR: failed to set log target - %s\n", err.Error())
os.Exit(1)
}
}
if param.incdirs != "" {
x.SetIncDirs(param.incdirs)
}
if param.modlibdirs != "" {
x.SetModLibDirs(param.modlibdirs)
} }
x.SetTrait(x.GetTrait() | hak.TRAIT_LANG_ENABLE_EOL) x.SetTrait(x.GetTrait() | hak.TRAIT_LANG_ENABLE_EOL)
err = x.Ignite(1000000) err = x.Ignite(uintptr(param.heapsize))
if err != nil { if err != nil {
fmt.Printf("ERROR: failed to ignite - %s\n", err.Error()) fmt.Printf("ERROR: failed to ignite - %s\n", err.Error())
goto oops goto oops
@@ -169,16 +361,25 @@ func main() {
goto oops goto oops
} }
/* Decode() writes the bytecode mnemonics through the log, so it only
* produces anything when --log selects the mnemonic type. the log mask
* is no longer cleared afterwards - doing that silenced --log for the
* whole of Execute(). */
x.Decode() x.Decode()
x.SetLogMask(0)
stop_ticker = start_ticker(x)
err = x.Execute() err = x.Execute()
stop_ticker()
if err != nil { if err != nil {
//fmt.Printf("ERROR: %s[%d:%d] - %s\n", herr.File, herr.Line, herr.Colm, herr.Msg) //fmt.Printf("ERROR: %s[%d:%d] - %s\n", herr.File, herr.Line, herr.Colm, herr.Msg)
fmt.Printf("ERROR: %s\n", err.Error()) fmt.Printf("ERROR: %s\n", err.Error())
goto oops goto oops
} }
if param.verbose {
fmt.Printf("EXECUTION OK - %s\n", param.input_file)
}
x.Close() x.Close()
os.Exit(0) os.Exit(0)
+47 -13
View File
@@ -12,6 +12,7 @@ import (
"io" "io"
"os" "os"
"path" "path"
"strings"
"path/filepath" "path/filepath"
"reflect" "reflect"
"sync" "sync"
@@ -96,6 +97,8 @@ func hak_go_cci_handler(c *C.hak_t, cmd C.hak_io_cmd_t, arg unsafe.Pointer) C.in
var ( var (
ioarg *C.hak_io_cciarg_t ioarg *C.hak_io_cciarg_t
name string name string
raw string
try_incdirs bool
fd int fd int
tptr unsafe.Pointer tptr unsafe.Pointer
tlen C.size_t tlen C.size_t
@@ -110,33 +113,64 @@ func hak_go_cci_handler(c *C.hak_t, cmd C.hak_io_cmd_t, arg unsafe.Pointer) C.in
// actual included stream // actual included stream
var includer_name string var includer_name string
name = string(ucstr_to_rune_slice(ioarg.name)) raw = string(ucstr_to_rune_slice(ioarg.name))
tptr = ioarg.includer.handle tptr = ioarg.includer.handle
tlen = *(*C.size_t)(unsafe.Pointer(uintptr(tptr) + unsafe.Sizeof(fd))) tlen = *(*C.size_t)(unsafe.Pointer(uintptr(tptr) + unsafe.Sizeof(fd)))
includer_name = C.GoStringN((*C.char)(unsafe.Pointer(uintptr(tptr)+unsafe.Sizeof(fd)+unsafe.Sizeof(tlen))), C.int(tlen)) includer_name = C.GoStringN((*C.char)(unsafe.Pointer(uintptr(tptr)+unsafe.Sizeof(fd)+unsafe.Sizeof(tlen))), C.int(tlen))
name = filepath.Join(path.Dir(includer_name), name) name = filepath.Join(path.Dir(includer_name), raw)
// a name anchored by the author - absolute, or explicitly ./ or
// ../ - is meant to resolve against the includer alone. anything
// else may fall back to the include directories. this mirrors
// what open_cci_stream() does in lib/std.c.
try_incdirs = !filepath.IsAbs(raw) &&
!strings.HasPrefix(raw, "./") && !strings.HasPrefix(raw, "../")
}
// [NOTE] the open has to happen before the allocation below, because
// the include-directory search can settle on a different (and
// longer) path than the one first tried, and the block is
// sized from the name it ends up storing.
if ioarg.includer == nil {
fd = -1
} else {
fd, err = g.io.cci.Open(g, name)
if err != nil && try_incdirs {
// walk the colon-separated include directories, as the C
// reader does. an empty entry means the current directory.
for _, dir := range strings.Split(g.GetIncDirs(), ":") {
var cand string = filepath.Join(dir, raw)
var fd2 int
var err2 error
fd2, err2 = g.io.cci.Open(g, cand)
if err2 == nil {
// the stored name becomes the includer path for
// anything this file includes in turn, so it has to
// be the path that actually opened
fd, err, name = fd2, nil, cand
break
}
}
}
if err != nil {
g.set_errmsg(C.HAK_EIOERR, err.Error())
return -1
}
} }
tlen = C.size_t(len(name)) // number of bytes in the string tlen = C.size_t(len(name)) // number of bytes in the string
tptr = C.hak_allocmem(c, C.size_t(unsafe.Sizeof(fd)) + C.size_t(unsafe.Sizeof(tlen)) + tlen) tptr = C.hak_allocmem(c, C.size_t(unsafe.Sizeof(fd)) + C.size_t(unsafe.Sizeof(tlen)) + tlen)
if tptr == nil { if tptr == nil {
if ioarg.includer != nil {
g.io.cci.Close(fd)
}
g.set_errmsg(C.HAK_ESYSMEM, "cci name allocation failure") g.set_errmsg(C.HAK_ESYSMEM, "cci name allocation failure")
return -1 return -1
} }
if ioarg.includer == nil {
fd = -1
} else {
fd, err = g.io.cci.Open(g, name)
if err != nil {
g.set_errmsg(C.HAK_EIOERR, err.Error())
C.hak_freemem(c, tptr)
return -1
}
}
// | fd | length | name bytes of the length | // | fd | length | name bytes of the length |
*(*int)(tptr) = fd; *(*int)(tptr) = fd;
*(*C.size_t)(unsafe.Pointer(uintptr(tptr)+unsafe.Sizeof(fd))) = tlen; *(*C.size_t)(unsafe.Pointer(uintptr(tptr)+unsafe.Sizeof(fd))) = tlen;
+102 -9
View File
@@ -76,6 +76,38 @@ type BitMask C.hak_bitmask_t
const TRAIT_LANG_ENABLE_EOL BitMask = C.HAK_TRAIT_LANG_ENABLE_EOL const TRAIT_LANG_ENABLE_EOL BitMask = C.HAK_TRAIT_LANG_ENABLE_EOL
/* log levels */
const (
LOG_DEBUG BitMask = C.HAK_LOG_DEBUG
LOG_INFO BitMask = C.HAK_LOG_INFO
LOG_WARN BitMask = C.HAK_LOG_WARN
LOG_ERROR BitMask = C.HAK_LOG_ERROR
LOG_FATAL BitMask = C.HAK_LOG_FATAL
)
/* log types */
const (
LOG_UNTYPED BitMask = C.HAK_LOG_UNTYPED
LOG_COMPILER BitMask = C.HAK_LOG_COMPILER
LOG_VM BitMask = C.HAK_LOG_VM
LOG_MNEMONIC BitMask = C.HAK_LOG_MNEMONIC
LOG_GC BitMask = C.HAK_LOG_GC
LOG_IC BitMask = C.HAK_LOG_IC
LOG_PRIMITIVE BitMask = C.HAK_LOG_PRIMITIVE
LOG_APP BitMask = C.HAK_LOG_APP
)
const (
LOG_ALL_LEVELS BitMask = C.HAK_LOG_ALL_LEVELS
LOG_ALL_TYPES BitMask = C.HAK_LOG_ALL_TYPES
)
/* BuildInfo answers how the underlying C library was configured. it mirrors
* what bin/hak.c prints for --info. */
func BuildInfo() string {
return fmt.Sprintf("Configured with: %s %s", C.HAK_CONFIGURE_CMD, C.HAK_CONFIGURE_ARGS)
}
func deregister_instance(g *Hak) { func deregister_instance(g *Hak) {
if g.inst_no >= 0 { if g.inst_no >= 0 {
inst_table.delete_instance(g.inst_no) inst_table.delete_instance(g.inst_no)
@@ -142,7 +174,7 @@ func (hak *Hak) GetTrait() BitMask {
var x C.int var x C.int
var log_mask BitMask = 0 var log_mask BitMask = 0
x = C.hak_getoption(hak.c, C.HAK_TRAIT, unsafe.Pointer(&log_mask)) x = C.hak_getoption(hak.c, C.HAK_OPT_TRAIT, unsafe.Pointer(&log_mask))
if x <= -1 { if x <= -1 {
// this must not happen // this must not happen
panic(fmt.Errorf("unable to get log mask - %s", hak.get_errmsg())) panic(fmt.Errorf("unable to get log mask - %s", hak.get_errmsg()))
@@ -154,7 +186,7 @@ func (hak *Hak) GetTrait() BitMask {
func (hak *Hak) SetTrait(log_mask BitMask) { func (hak *Hak) SetTrait(log_mask BitMask) {
var x C.int var x C.int
x = C.hak_setoption(hak.c, C.HAK_TRAIT, unsafe.Pointer(&log_mask)) x = C.hak_setoption(hak.c, C.HAK_OPT_TRAIT, unsafe.Pointer(&log_mask))
if x <= -1 { if x <= -1 {
// this must not happen // this must not happen
panic(fmt.Errorf("unable to set log mask - %s", hak.get_errmsg())) panic(fmt.Errorf("unable to set log mask - %s", hak.get_errmsg()))
@@ -165,7 +197,7 @@ func (hak *Hak) GetLogMask() BitMask {
var x C.int var x C.int
var log_mask BitMask = 0 var log_mask BitMask = 0
x = C.hak_getoption(hak.c, C.HAK_LOG_MASK, unsafe.Pointer(&log_mask)) x = C.hak_getoption(hak.c, C.HAK_OPT_LOG_MASK, unsafe.Pointer(&log_mask))
if x <= -1 { if x <= -1 {
// this must not happen // this must not happen
panic(fmt.Errorf("unable to get log mask - %s", hak.get_errmsg())) panic(fmt.Errorf("unable to get log mask - %s", hak.get_errmsg()))
@@ -177,7 +209,7 @@ func (hak *Hak) GetLogMask() BitMask {
func (hak *Hak) SetLogMask(log_mask BitMask) { func (hak *Hak) SetLogMask(log_mask BitMask) {
var x C.int var x C.int
x = C.hak_setoption(hak.c, C.HAK_LOG_MASK, unsafe.Pointer(&log_mask)) x = C.hak_setoption(hak.c, C.HAK_OPT_LOG_MASK, unsafe.Pointer(&log_mask))
if x <= -1 { if x <= -1 {
// this must not happen // this must not happen
panic(fmt.Errorf("unable to set log mask - %s", hak.get_errmsg())) panic(fmt.Errorf("unable to set log mask - %s", hak.get_errmsg()))
@@ -188,27 +220,78 @@ func (hak *Hak) GetLogTarget() string {
var x C.int var x C.int
var tgt *C.char var tgt *C.char
x = C.hak_getoption(hak.c, C.HAK_LOG_TARGET_BCSTR, unsafe.Pointer(&tgt)) x = C.hak_getoption(hak.c, C.HAK_OPT_LOG_TARGET_BCSTR, unsafe.Pointer(&tgt))
if x <= -1 { if x <= -1 {
// this must not happen // this must not happen
panic(fmt.Errorf("unable to set log target - %s", hak.get_errmsg())) panic(fmt.Errorf("unable to get log target - %s", hak.get_errmsg()))
} }
return C.GoString(tgt) return C.GoString(tgt)
} }
func (hak *Hak) SetLogTarget(target string) { func (hak *Hak) SetLogTarget(target string) error {
var x C.int var x C.int
var tgt *C.char var tgt *C.char
tgt = C.CString(target) // TODO: need error check? tgt = C.CString(target) // TODO: need error check?
defer C.free(unsafe.Pointer(tgt)) defer C.free(unsafe.Pointer(tgt))
x = C.hak_setoption(hak.c, C.HAK_LOG_TARGET_BCSTR, unsafe.Pointer(tgt)) x = C.hak_setoption(hak.c, C.HAK_OPT_LOG_TARGET_BCSTR, unsafe.Pointer(tgt))
if x <= -1 { return hak.make_errinfo() }
return nil
}
func (hak *Hak) GetIncDirs() string {
var x C.int
var tgt *C.char
x = C.hak_getoption(hak.c, C.HAK_OPT_INCDIRS_BCSTR, unsafe.Pointer(&tgt))
if x <= -1 { if x <= -1 {
// this must not happen // this must not happen
panic(fmt.Errorf("unable to set log target - %s", hak.get_errmsg())) panic(fmt.Errorf("unable to get include directories - %s", hak.get_errmsg()))
} }
return C.GoString(tgt)
}
func (hak *Hak) SetIncDirs(target string) error {
var x C.int
var tgt *C.char
tgt = C.CString(target) // TODO: need error check?
defer C.free(unsafe.Pointer(tgt))
x = C.hak_setoption(hak.c, C.HAK_OPT_INCDIRS_BCSTR, unsafe.Pointer(tgt))
if x <= -1 { return hak.make_errinfo() }
return nil
}
func (hak *Hak) GetModLibDirs() string {
var x C.int
var tgt *C.char
x = C.hak_getoption(hak.c, C.HAK_OPT_MODLIBDIRS_BCSTR, unsafe.Pointer(&tgt))
if x <= -1 {
// this must not happen
panic(fmt.Errorf("unable to get module library directories - %s", hak.get_errmsg()))
}
return C.GoString(tgt)
}
func (hak *Hak) SetModLibDirs(target string) error {
var x C.int
var tgt *C.char
tgt = C.CString(target) // TODO: need error check?
defer C.free(unsafe.Pointer(tgt))
x = C.hak_setoption(hak.c, C.HAK_OPT_MODLIBDIRS_BCSTR, unsafe.Pointer(tgt))
if x <= -1 { return hak.make_errinfo() }
return nil
} }
func (hak *Hak) Ignite(memsize uintptr) error { func (hak *Hak) Ignite(memsize uintptr) error {
@@ -399,6 +482,16 @@ func (hak *Hak) Decode() error {
return nil return nil
} }
func (hak *Hak) RcvTick(enabled bool) {
var i C.int
if enabled { i = 1 } else { i = 0 }
C.hak_rcvtick(hak.c, i)
}
func (hak *Hak) RaiseTick() {
C.hak_raisetick(hak.c)
}
func (hak *Hak) get_errmsg() string { func (hak *Hak) get_errmsg() string {
return C.GoString(C.hak_geterrbmsg(hak.c)) return C.GoString(C.hak_geterrbmsg(hak.c))
} }
+10
View File
@@ -31,6 +31,9 @@ LIBADD_LIB_COMMON += $(UNWIND_LIBS)
endif endif
if WIN32 if WIN32
# poll-msw.c and std.c call into winsock (WSAEventSelect, select, recv, ...)
LIBADD_LIB_COMMON += -lws2_32
# you must adjust the value of DEFAULT_MODPOSTFIX according # you must adjust the value of DEFAULT_MODPOSTFIX according
# to the first number in -version-info above # to the first number in -version-info above
CPPFLAGS_PFMOD = -DHAK_DEFAULT_PFMODPREFIX=\"libhak-\" -DHAK_DEFAULT_PFMODPOSTFIX=\"-1.dll\" CPPFLAGS_PFMOD = -DHAK_DEFAULT_PFMODPREFIX=\"libhak-\" -DHAK_DEFAULT_PFMODPOSTFIX=\"-1.dll\"
@@ -104,6 +107,13 @@ libhak_la_SOURCES = \
utl.c \ utl.c \
xchg.c \ xchg.c \
xma.c xma.c
if WIN32
# windows has no poll(). poll-msw.c implements it over WSAPoll/WaitForMultipleObjects.
libhak_la_SOURCES += \
poll-msw.c \
poll-msw.h
endif
libhak_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON) libhak_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON)
libhak_la_LDFLAGS = $(LDFLAGS_LIB_COMMON) libhak_la_LDFLAGS = $(LDFLAGS_LIB_COMMON)
libhak_la_LIBADD = $(LIBADD_LIB_COMMON) libhak_la_LIBADD = $(LIBADD_LIB_COMMON)
+56 -63
View File
@@ -92,13 +92,21 @@ host_triplet = @host@
@ENABLE_LIBLTDL_TRUE@am__append_1 = $(LTDL_LIBS) @ENABLE_LIBLTDL_TRUE@am__append_1 = $(LTDL_LIBS)
@ENABLE_LIBLTDL_FALSE@am__append_2 = $(DL_LIBS) @ENABLE_LIBLTDL_FALSE@am__append_2 = $(DL_LIBS)
@ENABLE_LIBUNWIND_TRUE@am__append_3 = $(UNWIND_LIBS) @ENABLE_LIBUNWIND_TRUE@am__append_3 = $(UNWIND_LIBS)
@MACOSX_TRUE@@WIN32_FALSE@am__append_4 = -DHAK_DEFAULT_PFMODPOSTFIX=\".dylib\"
@MACOSX_FALSE@@WIN32_FALSE@am__append_5 = -DHAK_DEFAULT_PFMODPOSTFIX=\".so\" # poll-msw.c and std.c call into winsock (WSAEventSelect, select, recv, ...)
@ENABLE_STATIC_MODULE_TRUE@am__append_6 = ../mod/libhak-core.la \ @WIN32_TRUE@am__append_4 = -lws2_32
@MACOSX_TRUE@@WIN32_FALSE@am__append_5 = -DHAK_DEFAULT_PFMODPOSTFIX=\".dylib\"
@MACOSX_FALSE@@WIN32_FALSE@am__append_6 = -DHAK_DEFAULT_PFMODPOSTFIX=\".so\"
# windows has no poll(). poll-msw.c implements it over WSAPoll/WaitForMultipleObjects.
@WIN32_TRUE@am__append_7 = \
@WIN32_TRUE@ poll-msw.c \
@WIN32_TRUE@ poll-msw.h
@ENABLE_STATIC_MODULE_TRUE@am__append_8 = ../mod/libhak-core.la \
@ENABLE_STATIC_MODULE_TRUE@ ../mod/libhak-dic.la \ @ENABLE_STATIC_MODULE_TRUE@ ../mod/libhak-dic.la \
@ENABLE_STATIC_MODULE_TRUE@ ../mod/libhak-sys.la @ENABLE_STATIC_MODULE_TRUE@ ../mod/libhak-sys.la
@ENABLE_HAKX_TRUE@am__append_7 = libhakx.la @ENABLE_HAKX_TRUE@am__append_9 = libhakx.la
@ENABLE_HAKX_TRUE@am__append_8 = hak-x.h hak-tmr.h hak-json.h @ENABLE_HAKX_TRUE@am__append_10 = hak-x.h hak-tmr.h hak-json.h
subdir = lib subdir = lib
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_sign.m4 \ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_sign.m4 \
@@ -148,8 +156,16 @@ am__DEPENDENCIES_1 =
@ENABLE_LIBLTDL_FALSE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) @ENABLE_LIBLTDL_FALSE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
@ENABLE_LIBUNWIND_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) @ENABLE_LIBUNWIND_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) \
libhak_la_DEPENDENCIES = $(am__DEPENDENCIES_5) $(am__append_6) $(am__DEPENDENCIES_1)
libhak_la_DEPENDENCIES = $(am__DEPENDENCIES_5) $(am__append_8)
am__libhak_la_SOURCES_DIST = hak-prv.h bigint.c chr.c cmgr.c cnode.c \
comp.c debug.c decode.c dic.c err.c exec.c fmt-imp.h fmt.c \
gc.c hak.c heap.c hnd.c htb.c mb8.c number.c obj.c opt-impl.h \
opt.c pio.c prim.c print.c rbt.c read.c std.c str.c sym.c \
uch-case.h uch-prop.h utf16.c utf8.c utl.c xchg.c xma.c \
poll-msw.c poll-msw.h
@WIN32_TRUE@am__objects_1 = libhak_la-poll-msw.lo
am_libhak_la_OBJECTS = libhak_la-bigint.lo libhak_la-chr.lo \ am_libhak_la_OBJECTS = libhak_la-bigint.lo libhak_la-chr.lo \
libhak_la-cmgr.lo libhak_la-cnode.lo libhak_la-comp.lo \ libhak_la-cmgr.lo libhak_la-cnode.lo libhak_la-comp.lo \
libhak_la-debug.lo libhak_la-decode.lo libhak_la-dic.lo \ libhak_la-debug.lo libhak_la-decode.lo libhak_la-dic.lo \
@@ -161,7 +177,7 @@ am_libhak_la_OBJECTS = libhak_la-bigint.lo libhak_la-chr.lo \
libhak_la-rbt.lo libhak_la-read.lo libhak_la-std.lo \ libhak_la-rbt.lo libhak_la-read.lo libhak_la-std.lo \
libhak_la-str.lo libhak_la-sym.lo libhak_la-utf16.lo \ libhak_la-str.lo libhak_la-sym.lo libhak_la-utf16.lo \
libhak_la-utf8.lo libhak_la-utl.lo libhak_la-xchg.lo \ libhak_la-utf8.lo libhak_la-utl.lo libhak_la-xchg.lo \
libhak_la-xma.lo libhak_la-xma.lo $(am__objects_1)
libhak_la_OBJECTS = $(am_libhak_la_OBJECTS) libhak_la_OBJECTS = $(am_libhak_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@) AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -210,14 +226,15 @@ am__depfiles_remade = ./$(DEPDIR)/libhak_la-bigint.Plo \
./$(DEPDIR)/libhak_la-hnd.Plo ./$(DEPDIR)/libhak_la-htb.Plo \ ./$(DEPDIR)/libhak_la-hnd.Plo ./$(DEPDIR)/libhak_la-htb.Plo \
./$(DEPDIR)/libhak_la-mb8.Plo ./$(DEPDIR)/libhak_la-number.Plo \ ./$(DEPDIR)/libhak_la-mb8.Plo ./$(DEPDIR)/libhak_la-number.Plo \
./$(DEPDIR)/libhak_la-obj.Plo ./$(DEPDIR)/libhak_la-opt.Plo \ ./$(DEPDIR)/libhak_la-obj.Plo ./$(DEPDIR)/libhak_la-opt.Plo \
./$(DEPDIR)/libhak_la-pio.Plo ./$(DEPDIR)/libhak_la-prim.Plo \ ./$(DEPDIR)/libhak_la-pio.Plo \
./$(DEPDIR)/libhak_la-print.Plo ./$(DEPDIR)/libhak_la-rbt.Plo \ ./$(DEPDIR)/libhak_la-poll-msw.Plo \
./$(DEPDIR)/libhak_la-read.Plo ./$(DEPDIR)/libhak_la-std.Plo \ ./$(DEPDIR)/libhak_la-prim.Plo ./$(DEPDIR)/libhak_la-print.Plo \
./$(DEPDIR)/libhak_la-str.Plo ./$(DEPDIR)/libhak_la-sym.Plo \ ./$(DEPDIR)/libhak_la-rbt.Plo ./$(DEPDIR)/libhak_la-read.Plo \
./$(DEPDIR)/libhak_la-utf16.Plo ./$(DEPDIR)/libhak_la-utf8.Plo \ ./$(DEPDIR)/libhak_la-std.Plo ./$(DEPDIR)/libhak_la-str.Plo \
./$(DEPDIR)/libhak_la-utl.Plo ./$(DEPDIR)/libhak_la-xchg.Plo \ ./$(DEPDIR)/libhak_la-sym.Plo ./$(DEPDIR)/libhak_la-utf16.Plo \
./$(DEPDIR)/libhak_la-xma.Plo ./$(DEPDIR)/libhakx_la-json.Plo \ ./$(DEPDIR)/libhak_la-utf8.Plo ./$(DEPDIR)/libhak_la-utl.Plo \
./$(DEPDIR)/libhakx_la-tmr.Plo \ ./$(DEPDIR)/libhak_la-xchg.Plo ./$(DEPDIR)/libhak_la-xma.Plo \
./$(DEPDIR)/libhakx_la-json.Plo ./$(DEPDIR)/libhakx_la-tmr.Plo \
./$(DEPDIR)/libhakx_la-x-client.Plo \ ./$(DEPDIR)/libhakx_la-x-client.Plo \
./$(DEPDIR)/libhakx_la-x-proto.Plo \ ./$(DEPDIR)/libhakx_la-x-proto.Plo \
./$(DEPDIR)/libhakx_la-x-server.Plo \ ./$(DEPDIR)/libhakx_la-x-server.Plo \
@@ -243,7 +260,8 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 = am__v_CCLD_1 =
SOURCES = $(libhak_la_SOURCES) $(libhakx_la_SOURCES) SOURCES = $(libhak_la_SOURCES) $(libhakx_la_SOURCES)
DIST_SOURCES = $(libhak_la_SOURCES) $(am__libhakx_la_SOURCES_DIST) DIST_SOURCES = $(am__libhak_la_SOURCES_DIST) \
$(am__libhakx_la_SOURCES_DIST)
am__can_run_installinfo = \ am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \ case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \ n|no|NO) false;; \
@@ -433,64 +451,29 @@ CPPFLAGS_ALL_COMMON = \
CPPFLAGS_LIB_COMMON = $(CPPFLAGS_ALL_COMMON) CPPFLAGS_LIB_COMMON = $(CPPFLAGS_ALL_COMMON)
LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -version-info 1:0:0 -no-undefined LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -version-info 1:0:0 -no-undefined
LIBADD_LIB_COMMON = $(LIBM) $(am__append_1) $(am__append_2) \ LIBADD_LIB_COMMON = $(LIBM) $(am__append_1) $(am__append_2) \
$(am__append_3) $(am__append_3) $(am__append_4)
@WIN32_FALSE@CPPFLAGS_PFMOD = \ @WIN32_FALSE@CPPFLAGS_PFMOD = \
@WIN32_FALSE@ -DHAK_DEFAULT_PFMODPREFIX=\"$(libdir)/libhak-\" \ @WIN32_FALSE@ -DHAK_DEFAULT_PFMODPREFIX=\"$(libdir)/libhak-\" \
@WIN32_FALSE@ $(am__append_4) $(am__append_5) @WIN32_FALSE@ $(am__append_5) $(am__append_6)
# you must adjust the value of DEFAULT_MODPOSTFIX according # you must adjust the value of DEFAULT_MODPOSTFIX according
# to the first number in -version-info above # to the first number in -version-info above
@WIN32_TRUE@CPPFLAGS_PFMOD = -DHAK_DEFAULT_PFMODPREFIX=\"libhak-\" \ @WIN32_TRUE@CPPFLAGS_PFMOD = -DHAK_DEFAULT_PFMODPREFIX=\"libhak-\" \
@WIN32_TRUE@ -DHAK_DEFAULT_PFMODPOSTFIX=\"-1.dll\" \ @WIN32_TRUE@ -DHAK_DEFAULT_PFMODPOSTFIX=\"-1.dll\" \
@WIN32_TRUE@ $(am__append_4) $(am__append_5) @WIN32_TRUE@ $(am__append_5) $(am__append_6)
pkginclude_HEADERS = hak.h hak-chr.h hak-cmgr.h hak-cmn.h hak-fmt.h \ pkginclude_HEADERS = hak.h hak-chr.h hak-cmgr.h hak-cmn.h hak-fmt.h \
hak-htb.h hak-opt.h hak-pac1.h hak-hnd.h hak-pio.h hak-spl.h \ hak-htb.h hak-opt.h hak-pac1.h hak-hnd.h hak-pio.h hak-spl.h \
hak-rbt.h hak-str.h hak-upac.h hak-utl.h hak-xma.h \ hak-rbt.h hak-str.h hak-upac.h hak-utl.h hak-xma.h \
$(am__append_8) $(am__append_10)
pkglib_LTLIBRARIES = libhak.la $(am__append_7) pkglib_LTLIBRARIES = libhak.la $(am__append_9)
libhak_la_SOURCES = \ libhak_la_SOURCES = hak-prv.h bigint.c chr.c cmgr.c cnode.c comp.c \
hak-prv.h \ debug.c decode.c dic.c err.c exec.c fmt-imp.h fmt.c gc.c hak.c \
bigint.c \ heap.c hnd.c htb.c mb8.c number.c obj.c opt-impl.h opt.c pio.c \
chr.c \ prim.c print.c rbt.c read.c std.c str.c sym.c uch-case.h \
cmgr.c \ uch-prop.h utf16.c utf8.c utl.c xchg.c xma.c $(am__append_7)
cnode.c \
comp.c \
debug.c \
decode.c \
dic.c \
err.c \
exec.c \
fmt-imp.h \
fmt.c \
gc.c \
hak.c \
heap.c \
hnd.c \
htb.c \
mb8.c \
number.c \
obj.c \
opt-impl.h \
opt.c \
pio.c \
prim.c \
print.c \
rbt.c \
read.c \
std.c \
str.c \
sym.c \
uch-case.h \
uch-prop.h \
utf16.c \
utf8.c \
utl.c \
xchg.c \
xma.c
libhak_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON) libhak_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON)
libhak_la_LDFLAGS = $(LDFLAGS_LIB_COMMON) libhak_la_LDFLAGS = $(LDFLAGS_LIB_COMMON)
libhak_la_LIBADD = $(LIBADD_LIB_COMMON) $(am__append_6) libhak_la_LIBADD = $(LIBADD_LIB_COMMON) $(am__append_8)
@ENABLE_HAKX_TRUE@libhakx_la_SOURCES = \ @ENABLE_HAKX_TRUE@libhakx_la_SOURCES = \
@ENABLE_HAKX_TRUE@ hak-json.h \ @ENABLE_HAKX_TRUE@ hak-json.h \
@ENABLE_HAKX_TRUE@ hak-tmr.h \ @ENABLE_HAKX_TRUE@ hak-tmr.h \
@@ -623,6 +606,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-obj.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-obj.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-opt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-opt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-pio.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-pio.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-poll-msw.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-prim.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-prim.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-print.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-print.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-rbt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhak_la-rbt.Plo@am__quote@ # am--include-marker
@@ -904,6 +888,13 @@ libhak_la-xma.lo: xma.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhak_la-xma.lo `test -f 'xma.c' || echo '$(srcdir)/'`xma.c @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhak_la-xma.lo `test -f 'xma.c' || echo '$(srcdir)/'`xma.c
libhak_la-poll-msw.lo: poll-msw.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhak_la-poll-msw.lo -MD -MP -MF $(DEPDIR)/libhak_la-poll-msw.Tpo -c -o libhak_la-poll-msw.lo `test -f 'poll-msw.c' || echo '$(srcdir)/'`poll-msw.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhak_la-poll-msw.Tpo $(DEPDIR)/libhak_la-poll-msw.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='poll-msw.c' object='libhak_la-poll-msw.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhak_la-poll-msw.lo `test -f 'poll-msw.c' || echo '$(srcdir)/'`poll-msw.c
libhakx_la-json.lo: json.c libhakx_la-json.lo: json.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhakx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhakx_la-json.lo -MD -MP -MF $(DEPDIR)/libhakx_la-json.Tpo -c -o libhakx_la-json.lo `test -f 'json.c' || echo '$(srcdir)/'`json.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhakx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhakx_la-json.lo -MD -MP -MF $(DEPDIR)/libhakx_la-json.Tpo -c -o libhakx_la-json.lo `test -f 'json.c' || echo '$(srcdir)/'`json.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhakx_la-json.Tpo $(DEPDIR)/libhakx_la-json.Plo @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhakx_la-json.Tpo $(DEPDIR)/libhakx_la-json.Plo
@@ -1129,6 +1120,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libhak_la-obj.Plo -rm -f ./$(DEPDIR)/libhak_la-obj.Plo
-rm -f ./$(DEPDIR)/libhak_la-opt.Plo -rm -f ./$(DEPDIR)/libhak_la-opt.Plo
-rm -f ./$(DEPDIR)/libhak_la-pio.Plo -rm -f ./$(DEPDIR)/libhak_la-pio.Plo
-rm -f ./$(DEPDIR)/libhak_la-poll-msw.Plo
-rm -f ./$(DEPDIR)/libhak_la-prim.Plo -rm -f ./$(DEPDIR)/libhak_la-prim.Plo
-rm -f ./$(DEPDIR)/libhak_la-print.Plo -rm -f ./$(DEPDIR)/libhak_la-print.Plo
-rm -f ./$(DEPDIR)/libhak_la-rbt.Plo -rm -f ./$(DEPDIR)/libhak_la-rbt.Plo
@@ -1215,6 +1207,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libhak_la-obj.Plo -rm -f ./$(DEPDIR)/libhak_la-obj.Plo
-rm -f ./$(DEPDIR)/libhak_la-opt.Plo -rm -f ./$(DEPDIR)/libhak_la-opt.Plo
-rm -f ./$(DEPDIR)/libhak_la-pio.Plo -rm -f ./$(DEPDIR)/libhak_la-pio.Plo
-rm -f ./$(DEPDIR)/libhak_la-poll-msw.Plo
-rm -f ./$(DEPDIR)/libhak_la-prim.Plo -rm -f ./$(DEPDIR)/libhak_la-prim.Plo
-rm -f ./$(DEPDIR)/libhak_la-print.Plo -rm -f ./$(DEPDIR)/libhak_la-print.Plo
-rm -f ./$(DEPDIR)/libhak_la-rbt.Plo -rm -f ./$(DEPDIR)/libhak_la-rbt.Plo
+222 -101
View File
@@ -24,7 +24,12 @@
#include "hak-prv.h" #include "hak-prv.h"
#define ENABLE_SYSCMD /* exec_syscmd() is built on fork(), execve() and waitpid(). neither windows
* nor openvms has them. without this, calling a string or a symbol falls
* through to the ordinary "cannot call" runtime error. */
#if !defined(_WIN32) && !defined(__VMS)
# define ENABLE_SYSCMD
#endif
static const char* io_type_str[] = static const char* io_type_str[] =
{ {
@@ -389,6 +394,7 @@ static HAK_INLINE hak_oop_context_t make_context (hak_t* hak, hak_ooi_t ntmprs)
hak_oop_context_t ctx; hak_oop_context_t ctx;
HAK_ASSERT(hak, ntmprs >= 0); HAK_ASSERT(hak, ntmprs >= 0);
/*return (hak_oop_context_t)hak_allocoopobj(hak, HAK_BRAND_CONTEXT, HAK_CONTEXT_NAMED_INSTVARS + (hak_oow_t)ntmprs);*/ /*return (hak_oop_context_t)hak_allocoopobj(hak, HAK_BRAND_CONTEXT, HAK_CONTEXT_NAMED_INSTVARS + (hak_oow_t)ntmprs);*/
ctx = (hak_oop_context_t)hak_instantiate(hak, hak->c_block_context, HAK_NULL, ntmprs); ctx = (hak_oop_context_t)hak_instantiate(hak, hak->c_block_context, HAK_NULL, ntmprs);
@@ -401,15 +407,11 @@ static HAK_INLINE hak_oop_context_t make_context (hak_t* hak, hak_ooi_t ntmprs)
} }
#if defined(HAK_ENABLE_STACK_CONTEXT) #if defined(HAK_ENABLE_STACK_CONTEXT)
#define HAK_USE_STACK_CONTEXT_FOR_FUNCTION 1
#define HAK_USE_STACK_CONTEXT_FOR_BLOCK 1
static HAK_INLINE hak_oop_t* alloc_frame_slots (hak_t* hak, hak_oow_t nslots) static HAK_INLINE hak_oop_t* alloc_frame_slots (hak_t* hak, hak_oop_process_t proc, hak_oow_t nslots)
{ {
hak_oop_process_t proc;
hak_ooi_t sp, st; hak_ooi_t sp, st;
proc = hak->processor->active;
HAK_ASSERT(hak, proc != hak->nil_process); HAK_ASSERT(hak, proc != hak->nil_process);
sp = HAK_OOP_TO_SMOOI(proc->fsp); sp = HAK_OOP_TO_SMOOI(proc->fsp);
@@ -424,7 +426,7 @@ static HAK_INLINE hak_oop_t* alloc_frame_slots (hak_t* hak, hak_oow_t nslots)
return &proc->slot[sp + 1]; return &proc->slot[sp + 1];
} }
static HAK_INLINE hak_oop_context_t make_stack_context (hak_t* hak, hak_ooi_t ntmprs) static HAK_INLINE hak_oop_context_t make_stack_context (hak_t* hak, hak_oop_process_t proc, hak_ooi_t ntmprs)
{ {
hak_oop_t* base; hak_oop_t* base;
hak_stack_context_t* sctx; hak_stack_context_t* sctx;
@@ -433,8 +435,8 @@ static HAK_INLINE hak_oop_context_t make_stack_context (hak_t* hak, hak_ooi_t nt
HAK_ASSERT(hak, ntmprs >= 0); HAK_ASSERT(hak, ntmprs >= 0);
frame_base = HAK_OOP_TO_SMOOI(hak->processor->active->fsp); frame_base = HAK_OOP_TO_SMOOI(proc->fsp);
base = alloc_frame_slots(hak, HAK_STACK_CONTEXT_NAMED_SLOTS + (hak_oow_t)ntmprs); base = alloc_frame_slots(hak, proc, HAK_STACK_CONTEXT_NAMED_SLOTS + (hak_oow_t)ntmprs);
if (HAK_UNLIKELY(!base)) return HAK_NULL; if (HAK_UNLIKELY(!base)) return HAK_NULL;
sctx = (hak_stack_context_t*)base; sctx = (hak_stack_context_t*)base;
@@ -457,30 +459,18 @@ static HAK_INLINE hak_oop_context_t make_stack_context (hak_t* hak, hak_ooi_t nt
sctx->slot_count = HAK_SMOOI_TO_OOP(ntmprs); sctx->slot_count = HAK_SMOOI_TO_OOP(ntmprs);
sctx->stack_base = HAK_SMOOI_TO_OOP(hak->sp); sctx->stack_base = HAK_SMOOI_TO_OOP(hak->sp);
sctx->frame_base = HAK_SMOOI_TO_OOP(frame_base); sctx->frame_base = HAK_SMOOI_TO_OOP(frame_base);
sctx->heap_ctx = hak->_nil; sctx->heap_ctx = hak->_nil; /* not reified yet. set to nil */
for (i = 0; i < ntmprs; i++) sctx->slot_base[i] = hak->_nil; for (i = 0; i < ntmprs; i++) sctx->slot[i] = hak->_nil;
/* end of extra fields */ /* end of extra fields */
return (hak_oop_context_t)HAK_SMPTR_TO_OOP(sctx); return (hak_oop_context_t)HAK_SMPTR_TO_OOP(sctx);
} }
static HAK_INLINE hak_oop_context_t make_context_for_activation (hak_t* hak, hak_ooi_t ntmprs, int use_stack)
{
if (use_stack)
{
hak_oop_context_t ctx = make_stack_context(hak, ntmprs);
if (HAK_UNLIKELY(!ctx)) return HAK_NULL;
return ctx;
}
return make_context(hak, ntmprs);
}
static HAK_INLINE hak_oop_context_t reify_context_ref (hak_t* hak, hak_oop_t ctx) static HAK_INLINE hak_oop_context_t reify_context_ref (hak_t* hak, hak_oop_t ctx)
{ {
if ((hak_oop_t)ctx == hak->_nil) return (hak_oop_context_t)ctx; if ((hak_oop_t)ctx == hak->_nil) return (hak_oop_context_t)ctx;
if (!HAK_CTX_IS_STACK(ctx)) return (hak_oop_context_t)ctx; if (!HAK_CTX_IS_STACK(ctx)) return (hak_oop_context_t)ctx;
return hak_reify_stack_context(hak, HAK_CTX_TO_STACK(ctx)); return hak_reifystackcontext(hak, HAK_CTX_TO_STACK(ctx));
} }
static HAK_INLINE void release_stack_context (hak_t* hak, hak_oop_t ctx) static HAK_INLINE void release_stack_context (hak_t* hak, hak_oop_t ctx)
@@ -492,13 +482,14 @@ static HAK_INLINE void release_stack_context (hak_t* hak, hak_oop_t ctx)
} }
} }
hak_oop_context_t hak_reify_stack_context (hak_t* hak, hak_stack_context_t* sctx) hak_oop_context_t hak_reifystackcontext (hak_t* hak, hak_stack_context_t* sctx)
{ {
hak_oop_context_t ctx; hak_oop_context_t ctx;
hak_oop_t heap_ctx; hak_oop_t heap_ctx;
hak_ooi_t slot_count; hak_ooi_t slot_count;
hak_ooi_t i; hak_ooi_t i;
/* check if already reified */
heap_ctx = sctx->heap_ctx; heap_ctx = sctx->heap_ctx;
if ((hak_oop_t)heap_ctx != hak->_nil) return (hak_oop_context_t)heap_ctx; if ((hak_oop_t)heap_ctx != hak->_nil) return (hak_oop_context_t)heap_ctx;
@@ -506,6 +497,7 @@ hak_oop_context_t hak_reify_stack_context (hak_t* hak, hak_stack_context_t* sctx
ctx = make_context(hak, slot_count); ctx = make_context(hak, slot_count);
if (HAK_UNLIKELY(!ctx)) return HAK_NULL; if (HAK_UNLIKELY(!ctx)) return HAK_NULL;
/* cache it */
sctx->heap_ctx = (hak_oop_t)ctx; sctx->heap_ctx = (hak_oop_t)ctx;
/* main fields */ /* main fields */
@@ -528,26 +520,10 @@ hak_oop_context_t hak_reify_stack_context (hak_t* hak, hak_stack_context_t* sctx
if (HAK_UNLIKELY(!ctx->mthhome)) return HAK_NULL; if (HAK_UNLIKELY(!ctx->mthhome)) return HAK_NULL;
/* end of main fields */ /* end of main fields */
for (i = 0; i < slot_count; i++) ctx->slot[i] = sctx->slot_base[i]; for (i = 0; i < slot_count; i++) ctx->slot[i] = sctx->slot[i];
return ctx; return ctx;
} }
#else
#define HAK_USE_STACK_CONTEXT_FOR_FUNCTION 0
#define HAK_USE_STACK_CONTEXT_FOR_BLOCK 0
static HAK_INLINE hak_oop_context_t make_context_for_activation (hak_t* hak, hak_ooi_t ntmprs, int use_stack)
{
(void)use_stack;
return make_context(hak, ntmprs);
}
static HAK_INLINE void release_stack_context (hak_t* hak, hak_oop_t ctx)
{
(void)hak;
(void)ctx;
}
#endif #endif
static HAK_INLINE hak_oop_function_t make_function (hak_t* hak, hak_oow_t lfsize, const hak_oob_t* bptr, hak_oow_t blen, hak_dbgi_t* dbgi) static HAK_INLINE hak_oop_function_t make_function (hak_t* hak, hak_oow_t lfsize, const hak_oob_t* bptr, hak_oow_t blen, hak_dbgi_t* dbgi)
@@ -699,7 +675,7 @@ static HAK_INLINE void free_pid (hak_t* hak, hak_oop_process_t proc)
hak->proc_map_used--; hak->proc_map_used--;
} }
static hak_oop_process_t make_process (hak_t* hak, hak_oop_context_t c) static hak_oop_process_t make_process (hak_t* hak, hak_oop_context_t ctx)
{ {
hak_oop_process_t proc; hak_oop_process_t proc;
hak_oow_t stksize, exstksize, clstksize, fstksize, maxsize; hak_oow_t stksize, exstksize, clstksize, fstksize, maxsize;
@@ -734,17 +710,20 @@ static hak_oop_process_t make_process (hak_t* hak, hak_oop_context_t c)
if (clstksize > maxsize) clstksize = maxsize; if (clstksize > maxsize) clstksize = maxsize;
else if (clstksize < HAK_MIN_CLSTK_SIZE) clstksize = HAK_MIN_CLSTK_SIZE; else if (clstksize < HAK_MIN_CLSTK_SIZE) clstksize = HAK_MIN_CLSTK_SIZE;
#if defined(HAK_ENABLE_STACK_CONTEXT)
if (fstksize > maxsize) fstksize = maxsize; if (fstksize > maxsize) fstksize = maxsize;
else if (fstksize < HAK_MIN_FSTK_SIZE) fstksize = HAK_MIN_FSTK_SIZE; else if (fstksize < HAK_MIN_FSTK_SIZE) fstksize = HAK_MIN_FSTK_SIZE;
#else
fstksize = 0;
#endif
hak_pushvolat(hak, (hak_oop_t*)&c); hak_pushvolat(hak, (hak_oop_t*)&ctx);
proc = (hak_oop_process_t)hak_instantiate(hak, hak->c_process, HAK_NULL, stksize + exstksize + clstksize + fstksize); proc = (hak_oop_process_t)hak_instantiate(hak, hak->c_process, HAK_NULL, stksize + exstksize + clstksize + fstksize);
hak_popvolat(hak); hak_popvolat(hak);
if (HAK_UNLIKELY(!proc)) if (HAK_UNLIKELY(!proc))
{ {
const hak_ooch_t* oldmsg = hak_backuperrmsg(hak); const hak_ooch_t* oldmsg = hak_backuperrmsg(hak);
hak_seterrbfmt(hak, hak->errnum, hak_seterrbfmt(hak, hak->errnum, "unable to instantiate %O - %js", hak->c_process->name, oldmsg);
"unable to instantiate %O - %js", hak->c_process->name, oldmsg);
return HAK_NULL; return HAK_NULL;
} }
@@ -754,8 +733,11 @@ static hak_oop_process_t make_process (hak_t* hak, hak_oop_context_t c)
/* assign a process id to the process */ /* assign a process id to the process */
alloc_pid(hak, proc); alloc_pid(hak, proc);
proc->initial_context = c; /* [NIL CONTEXT]
proc->current_context = c; * if you pass hak->_nil for ctx since you don't have the context ready,
* you must patch it after this function is over */
proc->initial_context = ctx;
proc->current_context = proc->initial_context;
/* stack */ /* stack */
proc->sp = HAK_SMOOI_TO_OOP(-1); /* no item */ proc->sp = HAK_SMOOI_TO_OOP(-1); /* no item */
@@ -772,8 +754,14 @@ static hak_oop_process_t make_process (hak_t* hak, hak_oop_context_t c)
/* frame stack */ /* frame stack */
proc->fsp = proc->clst; /* no item pushed yet */ proc->fsp = proc->clst; /* no item pushed yet */
proc->fst = HAK_SMOOI_TO_OOP(stksize + exstksize + clstksize + fstksize - 1); proc->fst = HAK_SMOOI_TO_OOP(stksize + exstksize + clstksize + fstksize - 1);
/* the frame stack is not used when HAK_ENABLE_STACK_CONTEXT not defined.
* but initialize it without the guard. fstksize is 0 anyways. */
HAK_ASSERT(hak, (hak_oop_t)HAK_CTX_GET_SENDER(hak, c) == hak->_nil); /* [NIL CONTEXT]
* this function allows hak->_nil for ctx but it puts the process object
* in inconsistent state. the caller must patch the initial_context and
* current_context fields as soon as possible */
HAK_ASSERT(hak, (hak_oop_t)ctx == hak->_nil || (hak_oop_t)HAK_CTX_GET_SENDER(hak, ctx) == hak->_nil);
#if defined(HAK_DEBUG_VM_PROCESSOR) #if defined(HAK_DEBUG_VM_PROCESSOR)
HAK_LOG2(hak, HAK_LOG_IC | HAK_LOG_DEBUG, "Processor - process[%zd] **CREATED**->%hs\n", HAK_OOP_TO_SMOOI(proc->id), proc_state_to_string(HAK_OOP_TO_SMOOI(proc->state))); HAK_LOG2(hak, HAK_LOG_IC | HAK_LOG_DEBUG, "Processor - process[%zd] **CREATED**->%hs\n", HAK_OOP_TO_SMOOI(proc->id), proc_state_to_string(HAK_OOP_TO_SMOOI(proc->state)));
@@ -835,7 +823,7 @@ static void switch_to_process (hak_t* hak, hak_oop_process_t proc, int new_state
/* the new process must be in the runnable state */ /* the new process must be in the runnable state */
HAK_ASSERT(hak, proc->state == HAK_SMOOI_TO_OOP(HAK_PROCESS_STATE_RUNNABLE) || HAK_ASSERT(hak, proc->state == HAK_SMOOI_TO_OOP(HAK_PROCESS_STATE_RUNNABLE) ||
proc->state == HAK_SMOOI_TO_OOP(HAK_PROCESS_STATE_WAITING)); proc->state == HAK_SMOOI_TO_OOP(HAK_PROCESS_STATE_WAITING));
sleep_active_process(hak, new_state_for_old_active); sleep_active_process(hak, new_state_for_old_active);
wake_process(hak, proc); wake_process(hak, proc);
@@ -1106,7 +1094,8 @@ static HAK_INLINE void reset_process_stack_pointers (hak_t* hak, hak_oop_process
proc->sp = HAK_SMOOI_TO_OOP(-1); /* invalidate the process stack */ proc->sp = HAK_SMOOI_TO_OOP(-1); /* invalidate the process stack */
proc->exsp = proc->st; proc->exsp = proc->st;
proc->clsp = proc->clst; proc->clsp = proc->exst;
proc->fsp = proc->clst;
} }
static void terminate_process (hak_t* hak, hak_oop_process_t proc) static void terminate_process (hak_t* hak, hak_oop_process_t proc)
@@ -1341,7 +1330,6 @@ static void yield_process (hak_t* hak, hak_oop_process_t proc)
} }
} }
static int async_signal_semaphore (hak_t* hak, hak_oop_semaphore_t sem) static int async_signal_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
{ {
#if 0 #if 0
@@ -1497,9 +1485,11 @@ static HAK_INLINE void drop_unawaited_io_signal_count_in_semaphore (hak_t* hak,
hak->sem_io_tuple[index].unawaited[io_type]--; hak->sem_io_tuple[index].unawaited[io_type]--;
} }
static HAK_INLINE void await_semaphore (hak_t* hak, hak_oop_semaphore_t sem) /* attempt to acquire a semaphore without ever blocking. returns 1 if it has
* been acquired, 0 if acquiring it would have required waiting. the caller
* must ensure the semaphore doesn't belong to a group. */
static HAK_INLINE int try_acquire_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
{ {
hak_oop_process_t proc;
hak_ooi_t count; hak_ooi_t count;
hak_oop_semaphore_group_t semgrp; hak_oop_semaphore_group_t semgrp;
@@ -1509,45 +1499,51 @@ static HAK_INLINE void await_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
HAK_ASSERT(hak, (hak_oop_t)semgrp == hak->_nil); HAK_ASSERT(hak, (hak_oop_t)semgrp == hak->_nil);
count = HAK_OOP_TO_SMOOI(sem->count); count = HAK_OOP_TO_SMOOI(sem->count);
if (count > 0) if (count <= 0) return 0; /* not signaled. the caller waits or gives up */
/* it's already signaled */
count--;
sem->count = HAK_SMOOI_TO_OOP(count);
drop_unawaited_io_signal_count_in_semaphore(hak, sem);
if ((hak_oop_t)semgrp != hak->_nil && count == 0)
{ {
/* it's already signaled */ int sems_idx;
count--; /* TODO: if i disallow individual wait on a semaphore in a group,
sem->count = HAK_SMOOI_TO_OOP(count); * this membership manipulation is redundant */
drop_unawaited_io_signal_count_in_semaphore(hak, sem); HAK_DELETE_FROM_OOP_LIST(hak, &semgrp->sems[HAK_SEMAPHORE_GROUP_SEMS_SIG], sem, grm);
sems_idx = count > 0? HAK_SEMAPHORE_GROUP_SEMS_SIG: HAK_SEMAPHORE_GROUP_SEMS_UNSIG;
if ((hak_oop_t)semgrp != hak->_nil && count == 0) HAK_APPEND_TO_OOP_LIST(hak, &semgrp->sems[sems_idx], hak_oop_semaphore_t, sem, grm);
{
int sems_idx;
/* TODO: if i disallow individual wait on a semaphore in a group,
* this membership manipulation is redundant */
HAK_DELETE_FROM_OOP_LIST(hak, &semgrp->sems[HAK_SEMAPHORE_GROUP_SEMS_SIG], sem, grm);
sems_idx = count > 0? HAK_SEMAPHORE_GROUP_SEMS_SIG: HAK_SEMAPHORE_GROUP_SEMS_UNSIG;
HAK_APPEND_TO_OOP_LIST(hak, &semgrp->sems[sems_idx], hak_oop_semaphore_t, sem, grm);
}
} }
else
return 1;
}
static HAK_INLINE void await_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
{
hak_oop_process_t proc;
if (try_acquire_semaphore(hak, sem)) return; /* signaled already. no waiting needed */
/* not signaled. need to wait */
proc = hak->processor->active;
/* suspend the active process */
suspend_process(hak, proc);
/* link the suspended process to the semaphore's process list */
chain_into_semaphore(hak, proc, sem);
HAK_ASSERT(hak, sem->waiting.last == proc);
if (sem->subtype == HAK_SMOOI_TO_OOP(HAK_SEMAPHORE_SUBTYPE_IO))
{ {
/* not signaled. need to wait */ hak->sem_io_wait_count++;
proc = hak->processor->active; HAK_DEBUG3 (hak, "await_semaphore - raised sem_io_wait_count to %zu for IO semaphore at index %zd handle %zd\n",
hak->sem_io_wait_count, HAK_OOP_TO_SMOOI(sem->u.io.index), HAK_OOP_TO_SMOOI(sem->u.io.handle));
/* suspend the active process */
suspend_process(hak, proc);
/* link the suspended process to the semaphore's process list */
chain_into_semaphore(hak, proc, sem);
HAK_ASSERT(hak, sem->waiting.last == proc);
if (sem->subtype == HAK_SMOOI_TO_OOP(HAK_SEMAPHORE_SUBTYPE_IO))
{
hak->sem_io_wait_count++;
HAK_DEBUG3 (hak, "await_semaphore - raised sem_io_wait_count to %zu for IO semaphore at index %zd handle %zd\n",
hak->sem_io_wait_count, HAK_OOP_TO_SMOOI(sem->u.io.index), HAK_OOP_TO_SMOOI(sem->u.io.handle));
}
HAK_ASSERT(hak, hak->processor->active != proc);
} }
HAK_ASSERT(hak, hak->processor->active != proc);
} }
static HAK_INLINE hak_oop_t await_semaphore_group (hak_t* hak, hak_oop_semaphore_group_t semgrp) static HAK_INLINE hak_oop_t await_semaphore_group (hak_t* hak, hak_oop_semaphore_group_t semgrp)
@@ -2154,7 +2150,7 @@ void hak_releaseiohandle (hak_t* hak, hak_ooi_t io_handle)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static int prepare_new_context (hak_t* hak, hak_oop_block_t op_blk, hak_ooi_t nargs, int nargs_offset, hak_ooi_t req_nrvars, int copy_args, int is_msgsend, hak_ooi_t msg_ivaroff, hak_oop_context_t* pnewctx) static int prepare_new_context (hak_t* hak, hak_oop_process_t proc, hak_oop_block_t op_blk, hak_ooi_t nargs, int nargs_offset, hak_ooi_t req_nrvars, int copy_args, int is_msgsend, hak_ooi_t msg_ivaroff, hak_oop_context_t* pnewctx)
{ {
/* prepare a new block context for activation. /* prepare a new block context for activation.
* the passed block context becomes the base for a new block context. */ * the passed block context becomes the base for a new block context. */
@@ -2195,7 +2191,11 @@ static int prepare_new_context (hak_t* hak, hak_oop_block_t op_blk, hak_ooi_t na
/* create a new block context to clone op_blk */ /* create a new block context to clone op_blk */
hak_pushvolat(hak, (hak_oop_t*)&op_blk); hak_pushvolat(hak, (hak_oop_t*)&op_blk);
blkctx = make_context_for_activation(hak, fixed_nargs + fblk_nrvars + fblk_nlvars + excess_nargs, HAK_USE_STACK_CONTEXT_FOR_BLOCK); #if defined(HAK_ENABLE_STACK_CONTEXT)
blkctx = make_stack_context(hak, proc, fixed_nargs + fblk_nrvars + fblk_nlvars + excess_nargs);
#else
blkctx = make_context(hak, fixed_nargs + fblk_nrvars + fblk_nlvars + excess_nargs);
#endif
hak_popvolat(hak); hak_popvolat(hak);
if (HAK_UNLIKELY(!blkctx)) return -1; if (HAK_UNLIKELY(!blkctx)) return -1;
@@ -2263,6 +2263,7 @@ static HAK_INLINE int __activate_block (hak_t* hak, hak_oop_block_t op_blk, hak_
x = prepare_new_context( x = prepare_new_context(
hak, hak,
hak->processor->active,
op_blk, op_blk,
nargs, /* nargs */ nargs, /* nargs */
0, /* nargs_offset */ 0, /* nargs_offset */
@@ -2334,7 +2335,11 @@ static int __activate_function (hak_t* hak, hak_oop_function_t op_func, hak_ooi_
/* create a new block context to clone op_func */ /* create a new block context to clone op_func */
hak_pushvolat(hak, (hak_oop_t*)&op_func); hak_pushvolat(hak, (hak_oop_t*)&op_func);
functx = make_context_for_activation(hak, fixed_nargs + nrvars + nlvars + excess_nargs, HAK_USE_STACK_CONTEXT_FOR_FUNCTION); #if defined(HAK_ENABLE_STACK_CONTEXT)
functx = make_stack_context(hak, hak->processor->active, fixed_nargs + nrvars + nlvars + excess_nargs);
#else
functx = make_context(hak, fixed_nargs + nrvars + nlvars + excess_nargs);
#endif
hak_popvolat(hak); hak_popvolat(hak);
if (HAK_UNLIKELY(!functx)) return -1; if (HAK_UNLIKELY(!functx)) return -1;
@@ -2722,9 +2727,11 @@ static HAK_INLINE int do_throw (hak_t* hak, hak_oop_t val, hak_ooi_t ip)
/* the below code is similar to do_return_from_block() */ /* the below code is similar to do_return_from_block() */
hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */ hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */
#if defined(HAK_ENABLE_STACK_CONTEXT)
/* rewind the context stack */
{ {
hak_oop_context_t xctx; hak_oop_context_t xctx;
xctx = hak->active_context; xctx = hak->active_context;
while ((hak_oop_t)xctx != (hak_oop_t)catch_ctx && (hak_oop_t)xctx != hak->_nil) while ((hak_oop_t)xctx != (hak_oop_t)catch_ctx && (hak_oop_t)xctx != hak->_nil)
{ {
@@ -2732,6 +2739,8 @@ static HAK_INLINE int do_throw (hak_t* hak, hak_oop_t val, hak_ooi_t ip)
xctx = (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, xctx); xctx = (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, xctx);
} }
} }
#endif
SWITCH_ACTIVE_CONTEXT(hak, catch_ctx); SWITCH_ACTIVE_CONTEXT(hak, catch_ctx);
hak->ip = catch_ip; /* override the instruction pointer */ hak->ip = catch_ip; /* override the instruction pointer */
@@ -3437,7 +3446,9 @@ static HAK_INLINE int do_return_from_block (hak_t* hak)
/* it is a normal block return as the active block context /* it is a normal block return as the active block context
* is not the initial context of a process */ * is not the initial context of a process */
hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */ hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */
#if defined(HAK_ENABLE_STACK_CONTEXT)
release_stack_context(hak, (hak_oop_t)hak->active_context); release_stack_context(hak, (hak_oop_t)hak->active_context);
#endif
SWITCH_ACTIVE_CONTEXT(hak, (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, hak->active_context)); SWITCH_ACTIVE_CONTEXT(hak, (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, hak->active_context));
return 0; /* normal return */ return 0; /* normal return */
} }
@@ -3603,7 +3614,9 @@ static HAK_INLINE int do_return_from_home (hak_t* hak, hak_oop_t return_value, h
while ((hak_oop_t)hak->active_context != (hak_oop_t)home) while ((hak_oop_t)hak->active_context != (hak_oop_t)home)
{ {
hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */ hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */
#if defined(HAK_ENABLE_STACK_CONTEXT)
release_stack_context(hak, (hak_oop_t)hak->active_context); release_stack_context(hak, (hak_oop_t)hak->active_context);
#endif
SWITCH_ACTIVE_CONTEXT(hak, (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, hak->active_context)); SWITCH_ACTIVE_CONTEXT(hak, (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, hak->active_context));
} }
@@ -3632,7 +3645,9 @@ static HAK_INLINE int do_return_from_home (hak_t* hak, hak_oop_t return_value, h
HAK_ASSERT(hak, (hak_oop_t)HAK_CTX_GET_SENDER(hak, hak->active_context) == (hak_oop_t)sender); HAK_ASSERT(hak, (hak_oop_t)HAK_CTX_GET_SENDER(hak, hak->active_context) == (hak_oop_t)sender);
hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */ hak->ip = -1; /* mark context dead. saved into hak->active_context->ip in SWITCH_ACTIVE_CONTEXT */
#if defined(HAK_ENABLE_STACK_CONTEXT)
release_stack_context(hak, (hak_oop_t)hak->active_context); release_stack_context(hak, (hak_oop_t)hak->active_context);
#endif
SWITCH_ACTIVE_CONTEXT(hak, (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, hak->active_context)); SWITCH_ACTIVE_CONTEXT(hak, (hak_oop_context_t)HAK_CTX_GET_SENDER(hak, hak->active_context));
HAK_STACK_PUSH(hak, return_value); HAK_STACK_PUSH(hak, return_value);
} }
@@ -4945,6 +4960,7 @@ hak_logbfmt(hak, HAK_LOG_STDERR, ">>>%O c->sc=%O sc=%O b2=%d b3=%d nivars=%d ncv
case HAK_CODE_PUSH_CONTEXT: case HAK_CODE_PUSH_CONTEXT:
LOG_INST_0(hak, "push_context"); LOG_INST_0(hak, "push_context");
/* TODO: error check? on HAK_CTX_TO_OOP? */
HAK_STACK_PUSH(hak, (hak_oop_t)HAK_CTX_TO_OOP(hak, hak->active_context)); HAK_STACK_PUSH(hak, (hak_oop_t)HAK_CTX_TO_OOP(hak, hak->active_context));
break; break;
@@ -5365,7 +5381,7 @@ hak_logbfmt(hak, HAK_LOG_STDERR, ">>>%O c->sc=%O sc=%O b2=%d b3=%d nivars=%d ncv
if (HAK_CTX_IS_STACK(homectx)) if (HAK_CTX_IS_STACK(homectx))
{ {
hak_pushvolat(hak, (hak_oop_t*)&funcobj); hak_pushvolat(hak, (hak_oop_t*)&funcobj);
homectx = hak_reify_stack_context(hak, HAK_CTX_TO_STACK(homectx)); homectx = hak_reifystackcontext(hak, HAK_CTX_TO_STACK(homectx));
hak_popvolat(hak); hak_popvolat(hak);
if (HAK_UNLIKELY(!homectx)) goto oops; if (HAK_UNLIKELY(!homectx)) goto oops;
hak->active_context = homectx; /* because homectx is reified of hak->active_context */ hak->active_context = homectx; /* because homectx is reified of hak->active_context */
@@ -5418,10 +5434,10 @@ hak_logbfmt(hak, HAK_LOG_STDERR, ">>>%O c->sc=%O sc=%O b2=%d b3=%d nivars=%d ncv
if (HAK_CTX_IS_STACK(homectx)) if (HAK_CTX_IS_STACK(homectx))
{ {
hak_pushvolat(hak, (hak_oop_t*)&blkobj); hak_pushvolat(hak, (hak_oop_t*)&blkobj);
homectx = hak_reify_stack_context(hak, HAK_CTX_TO_STACK(homectx)); homectx = hak_reifystackcontext(hak, HAK_CTX_TO_STACK(homectx));
hak_popvolat(hak); hak_popvolat(hak);
if (HAK_UNLIKELY(!homectx)) goto oops; if (HAK_UNLIKELY(!homectx)) goto oops;
hak->active_context = homectx; /* because homectx is reified of hak->active_context) */ hak->active_context = homectx; /* because homectx is reified of hak->active_context */
hak->processor->active->current_context = homectx; hak->processor->active->current_context = homectx;
} }
#endif #endif
@@ -5597,6 +5613,46 @@ hak_pfrc_t hak_pf_process_fork (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
return HAK_PF_FAILURE; return HAK_PF_FAILURE;
} }
#if defined(HAK_ENABLE_STACK_CONTEXT)
/* a process requires a context to start with but create a new process first
* to have a new context on the frame stack of the new process */
newprc = make_process(hak, (hak_oop_context_t)hak->_nil);
if (HAK_UNLIKELY(!newprc)) return HAK_PF_FAILURE;
hak_pushvolat(hak, (hak_oop_t*)&newprc);
x = prepare_new_context(
hak,
newprc,
blk,
nargs, /* nargs */
1, /* nargs_offset */
0, /* number of return variables expected */
1, /* copy_args */
0, /* is_msgsend */
0, /* msg_ivaroff */
&newctx);
hak_popvolat(hak);
if (HAK_UNLIKELY(x <= -1))
{
/* is it safe to terminate the process which doesn't have a proper context value
* in initial_context and current_context? */
terminate_process(hak, newprc);
return HAK_PF_FAILURE;
}
HAK_ASSERT(hak, (hak_oop_t)HAK_CTX_GET_SENDER(hak, newctx) == hak->_nil);
HAK_CTX_SET_HOME(hak, newctx, (hak_oop_t)hak->_nil); /* the new context is the initial context in the new process. so reset it to nil */
HAK_ASSERT(hak, (hak_oop_t)newprc->initial_context == hak->_nil);
HAK_ASSERT(hak, newprc->initial_context == newprc->current_context);
newprc->initial_context = newctx;
newprc->current_context = newctx;
#else
/* when stack context is disabled, create the context before
* the process. so we put the process in consitent state
* upon creation and also avoid the chance of making the process
* stuck in some suspended state. */
/* (defun x(a b) ...) /* (defun x(a b) ...)
* (fork x 1 2) * (fork x 1 2)
* among three arguments to fork, the first is the function block. * among three arguments to fork, the first is the function block.
@@ -5605,6 +5661,7 @@ hak_pfrc_t hak_pf_process_fork (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
*/ */
x = prepare_new_context( x = prepare_new_context(
hak, hak,
hak->processor->active,
blk, blk,
nargs, /* nargs */ nargs, /* nargs */
1, /* nargs_offset */ 1, /* nargs_offset */
@@ -5622,6 +5679,7 @@ hak_pfrc_t hak_pf_process_fork (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
newprc = make_process(hak, newctx); newprc = make_process(hak, newctx);
hak_popvolat(hak); hak_popvolat(hak);
if (HAK_UNLIKELY(!newprc)) return HAK_PF_FAILURE; if (HAK_UNLIKELY(!newprc)) return HAK_PF_FAILURE;
#endif
chain_into_processor(hak, newprc, HAK_PROCESS_STATE_RUNNABLE); chain_into_processor(hak, newprc, HAK_PROCESS_STATE_RUNNABLE);
@@ -5640,8 +5698,13 @@ hak_pfrc_t hak_pf_process_resume (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
return HAK_PF_FAILURE; return HAK_PF_FAILURE;
} }
/* [SPECIAL CASE]
* resume_process changes the the active process.
* calling this after resume_process() pollutes a wrong stack. place it here */
HAK_STACK_SETRET(hak, nargs, (hak_oop_t)prc);
resume_process(hak, prc); resume_process(hak, prc);
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
hak_pfrc_t hak_pf_process_suspend (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_process_suspend (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
@@ -5662,8 +5725,13 @@ hak_pfrc_t hak_pf_process_suspend (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
prc = hak->processor->active; prc = hak->processor->active;
} }
/* [SPECIAL CASE]
* suspend_process changes the the active process.
* calling this after suspend_process() pollutes a wrong stack. place it here */
HAK_STACK_SETRET(hak, nargs, (hak_oop_t)prc);
suspend_process(hak, prc); suspend_process(hak, prc);
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
hak_pfrc_t hak_pf_process_terminate (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_process_terminate (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
@@ -5684,20 +5752,35 @@ hak_pfrc_t hak_pf_process_terminate (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs
prc = hak->processor->active; prc = hak->processor->active;
} }
/* [SPECIAL CASE]
* terminate_process changes the the active process.
* calling this after terminate_process() pollutes a wrong stack. place it here */
HAK_STACK_SETRET(hak, nargs, (hak_oop_t)prc);
terminate_process(hak, prc); terminate_process(hak, prc);
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
hak_pfrc_t hak_pf_process_terminate_all (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_process_terminate_all (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
/* [SPECIAL CASE]
* terminate_all_processes changes the the active process.
* calling this after terminate_all_processes() pollutes a wrong stack. place it here */
HAK_STACK_SETRET(hak, nargs, hak->_nil);
terminate_all_processes(hak); terminate_all_processes(hak);
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
hak_pfrc_t hak_pf_process_yield (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_process_yield (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
/* [SPECIAL CASE]
* yield_process changes the the active process.
* calling this after yield_process() pollutes a wrong stack. place it here */
HAK_STACK_SETRET(hak, nargs, hak->_nil);
yield_process(hak, hak->processor->active); yield_process(hak, hak->processor->active);
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
@@ -5715,7 +5798,22 @@ hak_pfrc_t hak_pf_semaphore_new (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
return HAK_PF_FAILURE; return HAK_PF_FAILURE;
} }
sem->count = HAK_SMOOI_TO_OOP(0); if (nargs >= 1)
{
hak_oop_t tmp;
tmp = HAK_STACK_GETARG(hak, nargs, 0);
if (!HAK_OOP_IS_SMOOI(tmp))
{
hak_seterrbfmt(hak, HAK_EINVAL, "invalid semaphore count - %O", tmp);
return HAK_PF_FAILURE;
}
sem->count = tmp;
}
else
{
sem->count = HAK_SMOOI_TO_OOP(0);
}
/* TODO: sem->signal_action? */ /* TODO: sem->signal_action? */
/* other fields are all set to nil */ /* other fields are all set to nil */
@@ -5950,6 +6048,29 @@ hak_pfrc_t hak_pf_semaphore_wait (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
hak_pfrc_t hak_pf_semaphore_trywait (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{
hak_oop_semaphore_t sem;
sem = (hak_oop_semaphore_t)HAK_STACK_GETARG(hak, nargs, 0);
if (!HAK_IS_SEMAPHORE(hak, sem))
{
hak_seterrbfmt(hak, HAK_EINVAL, "parameter not semaphore - %O", sem);
return HAK_PF_FAILURE;
}
if (!can_await_semaphore(hak, sem))
{
hak_seterrbfmt(hak, HAK_EPERM, "not allowed to wait on a semaphore that belongs to a semaphore group");
return HAK_PF_FAILURE;
}
/* unlike hak_pf_semaphore_wait(), this never suspends the caller, so the
* active process and its stack cannot change under us. it is therefore
* safe to set the return value after the attempt rather than before. */
HAK_STACK_SETRET(hak, nargs, try_acquire_semaphore(hak, sem)? hak->_true: hak->_false);
return HAK_PF_SUCCESS;
}
hak_pfrc_t hak_pf_semaphore_unsignal (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_semaphore_unsignal (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
+2
View File
@@ -880,10 +880,12 @@ static HAK_INLINE void gc_ms_scan_stack (hak_t* hak)
HAK_ASSERT(hak, ll < (hak_ooi_t)(HAK_OBJ_GET_SIZE(oop) - HAK_PROCESS_NAMED_INSTVARS)); HAK_ASSERT(hak, ll < (hak_ooi_t)(HAK_OBJ_GET_SIZE(oop) - HAK_PROCESS_NAMED_INSTVARS));
for (i = HAK_OOP_TO_SMOOI(proc->exst) + 1; i <= ll; i++) gc_ms_mark_object(hak, proc->slot[i]); for (i = HAK_OOP_TO_SMOOI(proc->exst) + 1; i <= ll; i++) gc_ms_mark_object(hak, proc->slot[i]);
#if defined(HAK_ENABLE_STACK_CONTEXT)
/* frame stack */ /* frame stack */
ll = HAK_OOP_TO_SMOOI(proc->fsp); ll = HAK_OOP_TO_SMOOI(proc->fsp);
HAK_ASSERT(hak, ll < (hak_ooi_t)(HAK_OBJ_GET_SIZE(oop) - HAK_PROCESS_NAMED_INSTVARS)); HAK_ASSERT(hak, ll < (hak_ooi_t)(HAK_OBJ_GET_SIZE(oop) - HAK_PROCESS_NAMED_INSTVARS));
for (i = HAK_OOP_TO_SMOOI(proc->clst) + 1; i <= ll; i++) gc_ms_mark_object(hak, proc->slot[i]); for (i = HAK_OOP_TO_SMOOI(proc->clst) + 1; i <= ll; i++) gc_ms_mark_object(hak, proc->slot[i]);
#endif
} }
else else
{ {
+5
View File
@@ -42,6 +42,8 @@
# include <hak-dos.h> # include <hak-dos.h>
#elif defined(macintosh) #elif defined(macintosh)
# include <hak-mac.h> /* classic mac os */ # include <hak-mac.h> /* classic mac os */
#elif defined(__VMS)
# include <hak-vms.h>
#else #else
# error UNSUPPORTED SYSTEM # error UNSUPPORTED SYSTEM
#endif #endif
@@ -690,6 +692,9 @@ typedef struct hak_obj_t* hak_oop_t;
#define HAK_MSEC_TO_NSEC(msec) ((msec) * HAK_NSECS_PER_MSEC) #define HAK_MSEC_TO_NSEC(msec) ((msec) * HAK_NSECS_PER_MSEC)
#define HAK_NSEC_TO_MSEC(nsec) ((nsec) / HAK_NSECS_PER_MSEC) #define HAK_NSEC_TO_MSEC(nsec) ((nsec) / HAK_NSECS_PER_MSEC)
#define HAK_MSEC_TO_USEC(msec) ((msec) * HAK_USECS_PER_MSEC)
#define HAK_USEC_TO_MSEC(usec) ((usec) / HAK_USECS_PER_MSEC)
#define HAK_SEC_TO_NSEC(sec) ((sec) * HAK_NSECS_PER_SEC) #define HAK_SEC_TO_NSEC(sec) ((sec) * HAK_NSECS_PER_SEC)
#define HAK_NSEC_TO_SEC(nsec) ((nsec) / HAK_NSECS_PER_SEC) #define HAK_NSEC_TO_SEC(nsec) ((nsec) / HAK_NSECS_PER_SEC)
+26 -21
View File
@@ -48,7 +48,9 @@
/* enable floating-pointer number support in the basic formatting functions */ /* enable floating-pointer number support in the basic formatting functions */
#define HAK_ENABLE_FLTFMT #define HAK_ENABLE_FLTFMT
#if !defined(HAK_DISABLE_STACK_CONTEXT)
#define HAK_ENABLE_STACK_CONTEXT #define HAK_ENABLE_STACK_CONTEXT
#endif
#if defined(HAK_ENABLE_STACK_CONTEXT) #if defined(HAK_ENABLE_STACK_CONTEXT)
@@ -57,6 +59,7 @@
typedef struct hak_stack_context_t hak_stack_context_t; typedef struct hak_stack_context_t hak_stack_context_t;
struct hak_stack_context_t struct hak_stack_context_t
{ {
/* mirrored fields of hak_context_t defined in hak.h */
hak_oop_t req_nrets; hak_oop_t req_nrets;
hak_oop_t attr_mask; hak_oop_t attr_mask;
hak_oop_t name; hak_oop_t name;
@@ -69,22 +72,24 @@ struct hak_stack_context_t
hak_oop_t ivaroff; hak_oop_t ivaroff;
hak_oop_t owner; hak_oop_t owner;
/* extra fields for house-keeping */
hak_oop_t slot_count; hak_oop_t slot_count;
hak_oop_t stack_base; hak_oop_t stack_base;
hak_oop_t frame_base; hak_oop_t frame_base;
hak_oop_t heap_ctx; hak_oop_t heap_ctx; /* set to non-nil if reified */
hak_oop_t slot_base[1]; /* space for arguments, local variables, return variables, etc after the fixed fields like in hak_context_t */
hak_oop_t slot[1];
}; };
/*#define HAK_STACK_CONTEXT_NAMED_SLOTS (HAK_SIZEOF(hak_stack_context_t) / HAK_SIZEOF(hak_oop_t))*/ /*#define HAK_STACK_CONTEXT_NAMED_SLOTS (HAK_SIZEOF(hak_stack_context_t) / HAK_SIZEOF(hak_oop_t))*/
#define HAK_STACK_CONTEXT_NAMED_SLOTS (15) /* excludes slot_base */ #define HAK_STACK_CONTEXT_NAMED_SLOTS (15) /* excludes slot */
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
hak_oop_context_t hak_reify_stack_context (hak_t* hak, hak_stack_context_t* sctx); hak_oop_context_t hak_reifystackcontext (hak_t* hak, hak_stack_context_t* sctx);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
@@ -92,33 +97,20 @@ hak_oop_context_t hak_reify_stack_context (hak_t* hak, hak_stack_context_t* sctx
#define HAK_CTX_IS_STACK(ctx) (HAK_OOP_IS_SMPTR(ctx)) #define HAK_CTX_IS_STACK(ctx) (HAK_OOP_IS_SMPTR(ctx))
#define HAK_CTX_TO_STACK(ctx) ((hak_stack_context_t*)HAK_OOP_TO_SMPTR(ctx)) #define HAK_CTX_TO_STACK(ctx) ((hak_stack_context_t*)HAK_OOP_TO_SMPTR(ctx))
#define HAK_CTX_TO_OOP(hak, ctx) (HAK_CTX_IS_STACK(ctx)? hak_reify_stack_context((hak), HAK_CTX_TO_STACK(ctx)): (hak_oop_context_t)(ctx)) #define HAK_CTX_TO_OOP(hak, ctx) (HAK_CTX_IS_STACK(ctx)? hak_reifystackcontext((hak), HAK_CTX_TO_STACK(ctx)): (hak_oop_context_t)(ctx))
#if 0 #define HAK_CTX_SLOT(hak, ctx) (HAK_CTX_IS_STACK(ctx)? HAK_CTX_TO_STACK(ctx)->slot: ((hak_oop_context_t)(ctx))->slot)
#define HAK_CTX_SLOT(hak, ctx) (HAK_CTX_IS_STACK(ctx)? (hak_oop_t*)HAK_OOP_TO_SMPTR(HAK_CTX_TO_STACK(ctx)->slot_base) : ((hak_oop_context_t)(ctx))->slot)
#define HAK_CTX_SLOT_AT(hak, ctx, idx) (HAK_CTX_IS_STACK(ctx)? ((hak_oop_t*)HAK_OOP_TO_SMPTR(HAK_CTX_TO_STACK(ctx)->slot_base))[idx] : ((hak_oop_context_t)(ctx))->slot[idx])
#define HAK_CTX_SLOT_AT_PUT(hak, ctx, idx, val) \
do { \
if (HAK_CTX_IS_STACK(ctx)) \
((hak_oop_t*)HAK_OOP_TO_SMPTR(HAK_CTX_TO_STACK(ctx)->slot_base))[idx] = (val); \
else \
((hak_oop_context_t)(ctx))->slot[idx] = (val); \
} while(0)
#else
#define HAK_CTX_SLOT(hak, ctx) (HAK_CTX_IS_STACK(ctx)? HAK_CTX_TO_STACK(ctx)->slot_base : ((hak_oop_context_t)(ctx))->slot)
#define HAK_CTX_SLOT_AT(hak, ctx, idx) \ #define HAK_CTX_SLOT_AT(hak, ctx, idx) \
(HAK_CTX_IS_STACK(ctx)? HAK_CTX_TO_STACK(ctx)->slot_base[idx]: ((hak_oop_context_t)(ctx))->slot[idx]) (HAK_CTX_IS_STACK(ctx)? HAK_CTX_TO_STACK(ctx)->slot[idx]: ((hak_oop_context_t)(ctx))->slot[idx])
#define HAK_CTX_SLOT_AT_PUT(hak, ctx, idx, val) \ #define HAK_CTX_SLOT_AT_PUT(hak, ctx, idx, val) \
do { \ do { \
if (HAK_CTX_IS_STACK(ctx)) \ if (HAK_CTX_IS_STACK(ctx)) \
HAK_CTX_TO_STACK(ctx)->slot_base[idx] = (val); \ HAK_CTX_TO_STACK(ctx)->slot[idx] = (val); \
else \ else \
((hak_oop_context_t)(ctx))->slot[idx] = (val); \ ((hak_oop_context_t)(ctx))->slot[idx] = (val); \
} while(0) } while(0)
#endif
#define HAK_CTX_GET_REQNRETS(hak, ctx) (HAK_CTX_IS_STACK(ctx)? HAK_CTX_TO_STACK(ctx)->req_nrets : ((hak_oop_context_t)(ctx))->req_nrets) #define HAK_CTX_GET_REQNRETS(hak, ctx) (HAK_CTX_IS_STACK(ctx)? HAK_CTX_TO_STACK(ctx)->req_nrets : ((hak_oop_context_t)(ctx))->req_nrets)
#define HAK_CTX_SET_REQNRETS(hak, ctx, v) do { if (HAK_CTX_IS_STACK(ctx)) HAK_CTX_TO_STACK(ctx)->req_nrets = (v); else ((hak_oop_context_t)(ctx))->req_nrets = (v); } while (0) #define HAK_CTX_SET_REQNRETS(hak, ctx, v) do { if (HAK_CTX_IS_STACK(ctx)) HAK_CTX_TO_STACK(ctx)->req_nrets = (v); else ((hak_oop_context_t)(ctx))->req_nrets = (v); } while (0)
@@ -517,6 +509,7 @@ enum hak_tok_type_t
HAK_TOK_EOL, /* end of line */ HAK_TOK_EOL, /* end of line */
HAK_TOK_INCLUDE, HAK_TOK_INCLUDE,
HAK_TOK_INCLUDE_ONCE,
HAK_TOK_PRAGMA HAK_TOK_PRAGMA
}; };
typedef enum hak_tok_type_t hak_tok_type_t; typedef enum hak_tok_type_t hak_tok_type_t;
@@ -2248,6 +2241,8 @@ hak_pfrc_t hak_pf_nqv (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_nql (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_nql (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_nqk (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_nqk (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_object_new (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_process_current (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_process_current (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_process_fork (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_process_fork (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_process_resume (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_process_resume (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
@@ -2258,6 +2253,7 @@ hak_pfrc_t hak_pf_process_yield (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_semaphore_new (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_semaphore_new (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_semaphore_wait (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_semaphore_wait (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_semaphore_trywait (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_semaphore_signal (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_semaphore_signal (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_semaphore_signal_timed (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_semaphore_signal_timed (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_semaphore_signal_on_input (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_semaphore_signal_on_input (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
@@ -2270,6 +2266,15 @@ hak_pfrc_t hak_pf_semaphore_group_add_semaphore (hak_t* hak, hak_mod_t* mod, hak
hak_pfrc_t hak_pf_semaphore_group_remove_semaphore (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_semaphore_group_remove_semaphore (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_semaphore_group_wait (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs); hak_pfrc_t hak_pf_semaphore_group_wait (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
/* the signal primitives live in prim.c but are registered by the sys module,
* which reaches them as sys.sig-getfd, sys.sig-get, sys.sig-set, sys.sig-catch
* and sys.sig-uncatch */
hak_pfrc_t hak_pf_system_get_sigfd (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_system_get_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_system_set_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_system_catch_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
hak_pfrc_t hak_pf_system_uncatch_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs);
/* ========================================================================= */ /* ========================================================================= */
/* std.c */ /* std.c */
/* ========================================================================= */ /* ========================================================================= */
+14
View File
@@ -28,6 +28,20 @@
#include <hak-cmn.h> #include <hak-cmn.h>
#if defined(_WIN32)
/* HAK_SPL_RELAX() below calls Sleep(). this header is included before
* <windows.h> in some translation units, so pull the declaration in here
* rather than relying on the includer. WIN32_LEAN_AND_MEAN keeps winsock.h
* out, so a later <winsock2.h> still works. */
# if !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0400
# endif
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
#endif
/** \file /** \file
* This file provides a spinlock. * This file provides a spinlock.
* *
+99
View File
@@ -0,0 +1,99 @@
/*
Copyright (c) 2016-2018 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* OpenVMS.
*
* the values below were probed on OpenVMS VAX V7.3 with Compaq C V6.4-005
* (__DECC_VER 60490005). alpha and itanium differ - most importantly they do
* have 64-bit integers - so those are selected separately further down. */
#if defined(__alpha) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(__x86_64) || defined(__x86_64__)
/* alpha, itanium and x86-64 openvms */
# define HAK_ENDIAN_LITTLE
# define HAK_SIZEOF_CHAR 1
# define HAK_SIZEOF_SHORT 2
# define HAK_SIZEOF_INT 4
# define HAK_SIZEOF_LONG 4
# define HAK_SIZEOF_LONG_LONG 8
# define HAK_SIZEOF_VOID_P 4 /* 32-bit pointers unless /POINTER_SIZE=64 */
# define HAK_SIZEOF_FLOAT 4
# define HAK_SIZEOF_DOUBLE 8
# define HAK_SIZEOF_LONG_DOUBLE 16
# define HAK_SIZEOF_WCHAR_T 4
# define HAK_SIZEOF___INT8 0
# define HAK_SIZEOF___INT16 0
# define HAK_SIZEOF___INT32 0
# define HAK_SIZEOF___INT64 8
# define HAK_SIZEOF___INT128 0
# define HAK_SIZEOF_OFF64_T 0
# define HAK_SIZEOF_OFF_T 4
# define HAK_SIZEOF_MBSTATE_T 24
# define HAK_MBLEN_MAX 8
/* these two have only to be large enough */
# define HAK_SIZEOF_STRUCT_SOCKADDR_IN 32
# define HAK_SIZEOF_STRUCT_SOCKADDR_IN6 64
# define HAK_SIZEOF_SOCKLEN_T 4
#else
/* vax.
*
* [IMPORTANT] the vax compiler rejects both 'long long' and '__int64'
* outright - it answers %CC-E-NOLONGLONG, 64-bit integral types are not
* supported on this platform. so every 64-bit width below must be 0 and
* the widest integer available is 32 bits. */
# define HAK_ENDIAN_LITTLE
# define HAK_SIZEOF_CHAR 1
# define HAK_SIZEOF_SHORT 2
# define HAK_SIZEOF_INT 4
# define HAK_SIZEOF_LONG 4
# define HAK_SIZEOF_LONG_LONG 0
# define HAK_SIZEOF_VOID_P 4
# define HAK_SIZEOF_FLOAT 4
# define HAK_SIZEOF_DOUBLE 8
# define HAK_SIZEOF_LONG_DOUBLE 8 /* same representation as double here */
# define HAK_SIZEOF_WCHAR_T 4
# define HAK_SIZEOF___INT8 0
# define HAK_SIZEOF___INT16 0
# define HAK_SIZEOF___INT32 0
# define HAK_SIZEOF___INT64 0
# define HAK_SIZEOF___INT128 0
# define HAK_SIZEOF_OFF64_T 0
# define HAK_SIZEOF_OFF_T 4
# define HAK_SIZEOF_MBSTATE_T 24
# define HAK_MBLEN_MAX 8
/* these two have only to be large enough */
# define HAK_SIZEOF_STRUCT_SOCKADDR_IN 32
# define HAK_SIZEOF_STRUCT_SOCKADDR_IN6 64
# define HAK_SIZEOF_SOCKLEN_T 4
#endif
+141 -35
View File
@@ -369,9 +369,39 @@ void hak_fini (hak_t* hak)
hak->option.log_target_b = HAK_NULL; hak->option.log_target_b = HAK_NULL;
} }
/* destroy dynamically allocated options */
for (i = 0; i < HAK_COUNTOF(hak->option.mod); i++) for (i = 0; i < HAK_COUNTOF(hak->option.mod); i++)
{ {
if (hak->option.mod[i].ptr) hak_freemem(hak, hak->option.mod[i].ptr); if (hak->option.mod[i].ptr)
{
hak_freemem(hak, hak->option.mod[i].ptr);
hak->option.mod[i].ptr = HAK_NULL;
hak->option.mod[i].len = 0;
}
}
if (hak->option.modlibdirs_b)
{
hak_freemem(hak, hak->option.modlibdirs_b);
hak->option.modlibdirs_b = HAK_NULL;
}
if (hak->option.modlibdirs_u)
{
hak_freemem(hak, hak->option.modlibdirs_u);
hak->option.modlibdirs_u = HAK_NULL;
}
if (hak->option.incdirs_b)
{
hak_freemem(hak, hak->option.incdirs_b);
hak->option.incdirs_b = HAK_NULL;
}
if (hak->option.incdirs_u)
{
hak_freemem(hak, hak->option.incdirs_u);
hak->option.incdirs_u = HAK_NULL;
} }
if (hak->inttostr.xbuf.ptr) if (hak->inttostr.xbuf.ptr)
@@ -449,28 +479,74 @@ static int dup_str_opt (hak_t* hak, const hak_ooch_t* value, hak_oocs_t* tmp)
return 0; return 0;
} }
/* Store a string option in both representations at once.
*
* The consumers of these options are byte oriented - dlopen() and fopen() -
* so the bch form is what gets used, and converting once here saves a
* conversion on every module load and every include attempt. The uch form is
* kept so getoption can answer in either encoding without allocating.
*
* Both conversions are done before either slot is replaced, so a failure
* leaves the previous value in place rather than half-updating it. */
static int set_dual_str_opt (hak_t* hak, const void* value, int value_is_bch, hak_bch_t** bp, hak_uch_t** up)
{
hak_bch_t* v_b;
hak_uch_t* v_u;
if (value_is_bch)
{
v_b = hak_dupbcstr(hak, (const hak_bch_t*)value, HAK_NULL);
if (HAK_UNLIKELY(!v_b)) return -1;
v_u = hak_dupbtoucstr(hak, (const hak_bch_t*)value, HAK_NULL);
if (HAK_UNLIKELY(!v_u))
{
hak_freemem(hak, v_b);
return -1;
}
}
else
{
v_u = hak_dupucstr(hak, (const hak_uch_t*)value, HAK_NULL);
if (HAK_UNLIKELY(!v_u)) return -1;
v_b = hak_duputobcstr(hak, (const hak_uch_t*)value, HAK_NULL);
if (HAK_UNLIKELY(!v_b))
{
hak_freemem(hak, v_u);
return -1;
}
}
if (*bp) hak_freemem(hak, *bp);
if (*up) hak_freemem(hak, *up);
*bp = v_b;
*up = v_u;
return 0;
}
int hak_setoption (hak_t* hak, hak_option_t id, const void* value) int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
{ {
hak_cb_t* cb; hak_cb_t* cb;
switch (id) switch (id)
{ {
case HAK_TRAIT: case HAK_OPT_TRAIT:
hak->option.trait = *(const hak_bitmask_t*)value; hak->option.trait = *(const hak_bitmask_t*)value;
#if defined(HAK_BUILD_DEBUG) #if defined(HAK_BUILD_DEBUG)
hak->option.karatsuba_cutoff = ((hak->option.trait & HAK_TRAIT_DEBUG_BIGINT)? HAK_KARATSUBA_CUTOFF_DEBUG: HAK_KARATSUBA_CUTOFF); hak->option.karatsuba_cutoff = ((hak->option.trait & HAK_TRAIT_DEBUG_BIGINT)? HAK_KARATSUBA_CUTOFF_DEBUG: HAK_KARATSUBA_CUTOFF);
#endif #endif
break; break;
case HAK_LOG_MASK: case HAK_OPT_LOG_MASK:
hak->option.log_mask = *(const hak_bitmask_t*)value; hak->option.log_mask = *(const hak_bitmask_t*)value;
break; break;
case HAK_LOG_MAXCAPA: case HAK_OPT_LOG_MAXCAPA:
hak->option.log_maxcapa = *(hak_oow_t*)value; hak->option.log_maxcapa = *(hak_oow_t*)value;
break; break;
case HAK_LOG_TARGET_BCSTR: case HAK_OPT_LOG_TARGET_BCSTR:
{ {
hak_bch_t* v1; hak_bch_t* v1;
hak_uch_t* v2; hak_uch_t* v2;
@@ -490,7 +566,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_LOG_TARGET_UCSTR: case HAK_OPT_LOG_TARGET_UCSTR:
{ {
hak_uch_t* v1; hak_uch_t* v1;
hak_bch_t* v2; hak_bch_t* v2;
@@ -510,7 +586,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_LOG_TARGET_BCS: case HAK_OPT_LOG_TARGET_BCS:
{ {
hak_bch_t* v1; hak_bch_t* v1;
hak_uch_t* v2; hak_uch_t* v2;
@@ -531,7 +607,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_LOG_TARGET_UCS: case HAK_OPT_LOG_TARGET_UCS:
{ {
hak_uch_t* v1; hak_uch_t* v1;
hak_bch_t* v2; hak_bch_t* v2;
@@ -552,7 +628,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_SYMTAB_SIZE: case HAK_OPT_SYMTAB_SIZE:
{ {
hak_oow_t w; hak_oow_t w;
@@ -563,7 +639,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_SYSDIC_SIZE: case HAK_OPT_SYSDIC_SIZE:
{ {
hak_oow_t w; hak_oow_t w;
@@ -574,7 +650,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_PROCSTK_SIZE: case HAK_OPT_PROCSTK_SIZE:
{ {
hak_oow_t w; hak_oow_t w;
@@ -585,7 +661,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_EXSTK_SIZE: case HAK_OPT_EXSTK_SIZE:
{ {
hak_oow_t w; hak_oow_t w;
@@ -596,7 +672,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_CLSTK_SIZE: case HAK_OPT_CLSTK_SIZE:
{ {
hak_oow_t w; hak_oow_t w;
@@ -607,26 +683,41 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break; break;
} }
case HAK_MOD_LIBDIRS: case HAK_OPT_MODLIBDIRS_BCSTR:
case HAK_MOD_PREFIX: if (set_dual_str_opt(hak, value, 1, &hak->option.modlibdirs_b, &hak->option.modlibdirs_u) <= -1) return -1;
case HAK_MOD_POSTFIX: break;
case HAK_OPT_MODLIBDIRS_UCSTR:
if (set_dual_str_opt(hak, value, 0, &hak->option.modlibdirs_b, &hak->option.modlibdirs_u) <= -1) return -1;
break;
case HAK_OPT_MODPREFIX:
case HAK_OPT_MODPOSTFIX:
{ {
hak_oocs_t tmp; hak_oocs_t tmp;
int idx; int idx;
if (dup_str_opt(hak, (const hak_ooch_t*)value, &tmp) <= -1) return -1; if (dup_str_opt(hak, (const hak_ooch_t*)value, &tmp) <= -1) return -1;
idx = id - HAK_MOD_LIBDIRS; idx = id - HAK_OPT_MODPREFIX;
if (hak->option.mod[idx].ptr) hak_freemem(hak, hak->option.mod[idx].ptr); if (hak->option.mod[idx].ptr) hak_freemem(hak, hak->option.mod[idx].ptr);
hak->option.mod[idx] = tmp; hak->option.mod[idx] = tmp;
return 0; return 0;
} }
case HAK_MOD_INCTX: case HAK_OPT_MODINCTX:
hak->option.mod_inctx = *(void**)value; hak->option.mod_inctx = *(void**)value;
break; break;
case HAK_OPT_INCDIRS_BCSTR:
if (set_dual_str_opt(hak, value, 1, &hak->option.incdirs_b, &hak->option.incdirs_u) <= -1) return -1;
break;
case HAK_OPT_INCDIRS_UCSTR:
if (set_dual_str_opt(hak, value, 0, &hak->option.incdirs_b, &hak->option.incdirs_u) <= -1) return -1;
break;
default: default:
goto einval; goto einval;
} }
@@ -647,65 +738,80 @@ int hak_getoption (hak_t* hak, hak_option_t id, void* value)
{ {
switch (id) switch (id)
{ {
case HAK_TRAIT: case HAK_OPT_TRAIT:
*(hak_bitmask_t*)value = hak->option.trait; *(hak_bitmask_t*)value = hak->option.trait;
return 0; return 0;
case HAK_LOG_MASK: case HAK_OPT_LOG_MASK:
*(hak_bitmask_t*)value = hak->option.log_mask; *(hak_bitmask_t*)value = hak->option.log_mask;
return 0; return 0;
case HAK_LOG_MAXCAPA: case HAK_OPT_LOG_MAXCAPA:
*(hak_oow_t*)value = hak->option.log_maxcapa; *(hak_oow_t*)value = hak->option.log_maxcapa;
return 0; return 0;
case HAK_LOG_TARGET_BCSTR: case HAK_OPT_LOG_TARGET_BCSTR:
*(hak_bch_t**)value = hak->option.log_target_b; *(hak_bch_t**)value = hak->option.log_target_b;
return 0; return 0;
case HAK_LOG_TARGET_UCSTR: case HAK_OPT_LOG_TARGET_UCSTR:
*(hak_uch_t**)value = hak->option.log_target_u; *(hak_uch_t**)value = hak->option.log_target_u;
return 0; return 0;
case HAK_LOG_TARGET_BCS: case HAK_OPT_LOG_TARGET_BCS:
((hak_bcs_t*)value)->ptr = hak->option.log_target_b; ((hak_bcs_t*)value)->ptr = hak->option.log_target_b;
((hak_bcs_t*)value)->len = hak_count_bcstr(hak->option.log_target_b); ((hak_bcs_t*)value)->len = hak_count_bcstr(hak->option.log_target_b);
return 0; return 0;
case HAK_LOG_TARGET_UCS: case HAK_OPT_LOG_TARGET_UCS:
((hak_ucs_t*)value)->ptr = hak->option.log_target_u; ((hak_ucs_t*)value)->ptr = hak->option.log_target_u;
((hak_ucs_t*)value)->len = hak_count_ucstr(hak->option.log_target_u); ((hak_ucs_t*)value)->len = hak_count_ucstr(hak->option.log_target_u);
return 0; return 0;
case HAK_SYMTAB_SIZE: case HAK_OPT_SYMTAB_SIZE:
*(hak_oow_t*)value = hak->option.dfl_symtab_size; *(hak_oow_t*)value = hak->option.dfl_symtab_size;
return 0; return 0;
case HAK_SYSDIC_SIZE: case HAK_OPT_SYSDIC_SIZE:
*(hak_oow_t*)value = hak->option.dfl_sysdic_size; *(hak_oow_t*)value = hak->option.dfl_sysdic_size;
return 0; return 0;
case HAK_PROCSTK_SIZE: case HAK_OPT_PROCSTK_SIZE:
*(hak_oow_t*)value = hak->option.dfl_procstk_size; *(hak_oow_t*)value = hak->option.dfl_procstk_size;
return 0; return 0;
case HAK_EXSTK_SIZE: case HAK_OPT_EXSTK_SIZE:
*(hak_oow_t*)value = hak->option.dfl_exstk_size; *(hak_oow_t*)value = hak->option.dfl_exstk_size;
return 0; return 0;
case HAK_CLSTK_SIZE: case HAK_OPT_CLSTK_SIZE:
*(hak_oow_t*)value = hak->option.dfl_clstk_size; *(hak_oow_t*)value = hak->option.dfl_clstk_size;
return 0; return 0;
case HAK_MOD_LIBDIRS: case HAK_OPT_MODLIBDIRS_BCSTR:
case HAK_MOD_PREFIX: *(const hak_bch_t**)value = hak->option.modlibdirs_b;
case HAK_MOD_POSTFIX:
*(const hak_ooch_t**)value = hak->option.mod[id - HAK_MOD_LIBDIRS].ptr;
return 0; return 0;
case HAK_MOD_INCTX: case HAK_OPT_MODLIBDIRS_UCSTR:
*(const hak_uch_t**)value = hak->option.modlibdirs_u;
return 0;
case HAK_OPT_MODPREFIX:
case HAK_OPT_MODPOSTFIX:
*(const hak_ooch_t**)value = hak->option.mod[id - HAK_OPT_MODPREFIX].ptr;
return 0;
case HAK_OPT_MODINCTX:
*(void**)value = hak->option.mod_inctx; *(void**)value = hak->option.mod_inctx;
return 0; return 0;
case HAK_OPT_INCDIRS_BCSTR:
*(const hak_bch_t**)value = hak->option.incdirs_b;
return 0;
case HAK_OPT_INCDIRS_UCSTR:
*(const hak_uch_t**)value = hak->option.incdirs_u;
return 0;
}; };
hak_seterrnum(hak, HAK_EINVAL); hak_seterrnum(hak, HAK_EINVAL);
+52 -24
View File
@@ -241,35 +241,50 @@ typedef hak_errbinf_t hak_errinf_t;
enum hak_option_t enum hak_option_t
{ {
HAK_TRAIT, HAK_OPT_TRAIT,
HAK_LOG_MASK, HAK_OPT_LOG_MASK,
HAK_LOG_MAXCAPA, HAK_OPT_LOG_MAXCAPA,
HAK_LOG_TARGET_BCSTR, HAK_OPT_LOG_TARGET_BCSTR,
HAK_LOG_TARGET_UCSTR, HAK_OPT_LOG_TARGET_UCSTR,
HAK_LOG_TARGET_BCS, HAK_OPT_LOG_TARGET_BCS,
HAK_LOG_TARGET_UCS, HAK_OPT_LOG_TARGET_UCS,
#if defined(HAK_OOCH_IS_UCH) #if defined(HAK_OOCH_IS_UCH)
# define HAK_LOG_TARGET HAK_LOG_TARGET_UCSTR # define HAK_OPT_LOG_TARGET HAK_OPT_LOG_TARGET_UCSTR
# define HAK_LOG_TARGET_OOCSTR HAK_LOG_TARGET_UCSTR # define HAK_OPT_LOG_TARGET_OOCSTR HAK_OPT_LOG_TARGET_UCSTR
# define HAK_LOG_TARGET_OOCS HAK_LOG_TARGET_UCS # define HAK_OPT_LOG_TARGET_OOCS HAK_OPT_LOG_TARGET_UCS
#else #else
# define HAK_LOG_TARGET HAK_LOG_TARGET_BCSTR # define HAK_OPT_LOG_TARGET HAK_OPT_LOG_TARGET_BCSTR
# define HAK_LOG_TARGET_OOCSTR HAK_LOG_TARGET_BCSTR # define HAK_OPT_LOG_TARGET_OOCSTR HAK_OPT_LOG_TARGET_BCSTR
# define HAK_LOG_TARGET_OOCS HAK_LOG_TARGET_BCS # define HAK_OPT_LOG_TARGET_OOCS HAK_OPT_LOG_TARGET_BCS
#endif #endif
HAK_SYMTAB_SIZE, /* default system table size */ HAK_OPT_SYMTAB_SIZE, /* default system table size */
HAK_SYSDIC_SIZE, /* default system dictionary size */ HAK_OPT_SYSDIC_SIZE, /* default system dictionary size */
HAK_PROCSTK_SIZE, /* default process stack size */ HAK_OPT_PROCSTK_SIZE, /* default process stack size */
HAK_EXSTK_SIZE, /* default exception stack size */ HAK_OPT_EXSTK_SIZE, /* default exception stack size */
HAK_CLSTK_SIZE, /* default class stack size */ HAK_OPT_CLSTK_SIZE, /* default class stack size */
HAK_MOD_LIBDIRS, HAK_OPT_MODLIBDIRS_BCSTR,
HAK_MOD_PREFIX, HAK_OPT_MODLIBDIRS_UCSTR,
HAK_MOD_POSTFIX, #if defined(HAK_OOCH_IS_UCH)
# define HAK_OPT_MODLIBDIRS HAK_OPT_MODLIBDIRS_UCSTR
#else
# define HAK_OPT_MODLIBDIRS HAK_OPT_MODLIBDIRS_BCSTR
#endif
HAK_MOD_INCTX HAK_OPT_MODPREFIX,
HAK_OPT_MODPOSTFIX,
HAK_OPT_MODINCTX,
HAK_OPT_INCDIRS_BCSTR,
HAK_OPT_INCDIRS_UCSTR
#if defined(HAK_OOCH_IS_UCH)
# define HAK_OPT_INCDIRS HAK_OPT_INCDIRS_UCSTR
#else
# define HAK_OPT_INCDIRS HAK_OPT_INCDIRS_BCSTR
#endif
}; };
typedef enum hak_option_t hak_option_t; typedef enum hak_option_t hak_option_t;
@@ -708,7 +723,7 @@ struct hak_block_t
/* the fields of hak_context_t must be mirroed to hak_stack_context_t /* the fields of hak_context_t must be mirroed to hak_stack_context_t
* in hak-prv.h. there are functions affected by the layout change * in hak-prv.h. there are functions affected by the layout change
* of these structures: * of these structures:
* - hak_reify_stack_context() in lib/exec. * - hak_reifystackcontext() in lib/exec.
* - make_stack_context() in lib/exec.c * - make_stack_context() in lib/exec.c
*/ */
struct hak_context_t struct hak_context_t
@@ -811,6 +826,8 @@ struct hak_process_t
hak_oop_t clsp; /* class stack pointer */ hak_oop_t clsp; /* class stack pointer */
hak_oop_t clst; /* class stack top */ hak_oop_t clst; /* class stack top */
/* frame stack store the context objects when the stack context feature is enabled.
* if both fsp and fst are to clst, the stack context feature is disabled */
hak_oop_t fsp; /* frame stack pointer */ hak_oop_t fsp; /* frame stack pointer */
hak_oop_t fst; /* frame stack top */ hak_oop_t fst; /* frame stack top */
@@ -1786,7 +1803,18 @@ struct hak_t
hak_oow_t dfl_clstk_size; hak_oow_t dfl_clstk_size;
void* mod_inctx; void* mod_inctx;
hak_oocs_t mod[3]; /* both representations are kept for the two options whose consumers
* are byte oriented: dl_open() feeds dlopen() and open_cci_stream()
* feeds fopen(), so the bch form is what actually gets used, while the
* uch form serves getoption and %js. converting once at set time beats
* converting on every module load and every include attempt. */
hak_bch_t* modlibdirs_b;
hak_uch_t* modlibdirs_u;
hak_bch_t* incdirs_b;
hak_uch_t* incdirs_u;
/* prefix and postfix only - indexed by (id - HAK_OPT_MODPREFIX) */
hak_oocs_t mod[2];
#if defined(HAK_BUILD_DEBUG) #if defined(HAK_BUILD_DEBUG)
/* set automatically when trait is set */ /* set automatically when trait is set */
+2 -2
View File
@@ -952,7 +952,7 @@ hak_json_t* hak_json_open (hak_mmgr_t* mmgr, hak_oow_t xtnsize, hak_json_prim_t*
/* the dummy hak is used for this json to perform primitive operations /* the dummy hak is used for this json to perform primitive operations
* such as getting system time or logging. so the heap size doesn't * such as getting system time or logging. so the heap size doesn't
* need to be changed from the tiny value set above. */ * need to be changed from the tiny value set above. */
hak_setoption(json->dummy_hak, HAK_LOG_MASK, &json->cfg.logmask); hak_setoption(json->dummy_hak, HAK_OPT_LOG_MASK, &json->cfg.logmask);
hak_setcmgr(json->dummy_hak, json->cmgr); hak_setcmgr(json->dummy_hak, json->cmgr);
@@ -987,7 +987,7 @@ int hak_json_setoption (hak_json_t* json, hak_json_option_t id, const void* valu
* existing hak instances inside worker threads won't get * existing hak instances inside worker threads won't get
* affected. new hak instances to be created later * affected. new hak instances to be created later
* is supposed to use the new value */ * is supposed to use the new value */
hak_setoption(json->dummy_hak, HAK_LOG_MASK, value); hak_setoption(json->dummy_hak, HAK_OPT_LOG_MASK, value);
} }
return 0; return 0;
} }
+17 -41
View File
@@ -1220,7 +1220,7 @@ static hak_pfrc_t pf_va_get (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
} }
static hak_pfrc_t pf_object_new (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_object_new (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
hak_oop_t obj; hak_oop_t obj;
hak_oop_t _class; hak_oop_t _class;
@@ -1256,7 +1256,7 @@ static hak_pfrc_t pf_object_new (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static hak_pfrc_t pf_system_get_sigfd (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_system_get_sigfd (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
hak_ooi_t fd; hak_ooi_t fd;
hak_hnd_t* hnd; hak_hnd_t* hnd;
@@ -1264,7 +1264,7 @@ static hak_pfrc_t pf_system_get_sigfd (hak_t* hak, hak_mod_t* mod, hak_ooi_t nar
fd = hak->vmprim.vm_getsigfd(hak); fd = hak->vmprim.vm_getsigfd(hak);
/* hand back a system handle id rather than the descriptor itself, so that /* hand back a system handle id rather than the descriptor itself, so that
* the result can be given to sem-signal-on-input - which resolves handle * the result can be given to core.sem-signal-on-input - which resolves handle
* ids, not descriptors. wrapped HAK_HND_OPEN_KEEPOPEN because the VM owns * ids, not descriptors. wrapped HAK_HND_OPEN_KEEPOPEN because the VM owns
* this descriptor and manages its blocking mode; the table must never * this descriptor and manages its blocking mode; the table must never
* close it. wrapfd_once() keeps the id stable across calls. */ * close it. wrapfd_once() keeps the id stable across calls. */
@@ -1275,7 +1275,7 @@ static hak_pfrc_t pf_system_get_sigfd (hak_t* hak, hak_mod_t* mod, hak_ooi_t nar
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
static hak_pfrc_t pf_system_get_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_system_get_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
hak_uint8_t sig; hak_uint8_t sig;
int n; int n;
@@ -1289,12 +1289,12 @@ static hak_pfrc_t pf_system_get_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
/* (system-catch-sig signo) - route an operating system signal into the /* (sys.sig-catch signo) - route an operating system signal into the signal
* signal descriptor, where hak code can wait for * descriptor, where hak code can wait for it with
* it with sem-signal-on-input * core.sem-signal-on-input
* (system-uncatch-sig signo) - release it again * (sys.sig-uncatch signo) - release it again
* *
* Note the difference from system-set-sig, which does not touch the operating * Note the difference from sys.sig-set, which does not touch the operating
* system at all: that one injects a number into the descriptor directly, as a * system at all: that one injects a number into the descriptor directly, as a
* way for hak code to post a synthetic signal to itself. * way for hak code to post a synthetic signal to itself.
*/ */
@@ -1323,17 +1323,17 @@ static hak_pfrc_t __system_catch_sig (hak_t* hak, hak_ooi_t nargs, int enable)
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
static hak_pfrc_t pf_system_catch_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_system_catch_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
return __system_catch_sig(hak, nargs, 1); return __system_catch_sig(hak, nargs, 1);
} }
static hak_pfrc_t pf_system_uncatch_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_system_uncatch_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
return __system_catch_sig(hak, nargs, 0); return __system_catch_sig(hak, nargs, 0);
} }
static hak_pfrc_t pf_system_set_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs) hak_pfrc_t hak_pf_system_set_sig (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
{ {
hak_oop_t tmp; hak_oop_t tmp;
hak_uint8_t sig; hak_uint8_t sig;
@@ -1366,11 +1366,10 @@ static pf_t builtin_prims[] =
{ 1, HAK_TYPE_MAX(hak_oow_t), pf_scanf, 5, { 's','c','a','n','f' } }, { 1, HAK_TYPE_MAX(hak_oow_t), pf_scanf, 5, { 's','c','a','n','f' } },
{ 1, HAK_TYPE_MAX(hak_oow_t), pf_sprintf, 7, { 's','p','r','i','n','t','f' } }, { 1, HAK_TYPE_MAX(hak_oow_t), pf_sprintf, 7, { 's','p','r','i','n','t','f' } },
{ 0, 0, pf_system_get_sigfd, 16, { 's','y','s','t','e','m','-','g','e','t','-','s','i','g','f','d' } }, /* the signal primitives are registered by the sys module instead - see
{ 0, 0, pf_system_get_sig, 14, { 's','y','s','t','e','m','-','g','e','t','-','s','i','g' } }, * pfinfos[] in mod/sys.c. they are reached as sys.sig-getfd, sys.sig-get,
{ 1, 1, pf_system_set_sig, 14, { 's','y','s','t','e','m','-','s','e','t','-','s','i','g' } }, * sys.sig-set, sys.sig-catch and sys.sig-uncatch. the implementations stay
{ 1, 1, pf_system_catch_sig, 16, { 's','y','s','t','e','m','-','c','a','t','c','h','-','s','i','g' } }, * here and are declared in lib/hak-prv.h. */
{ 1, 1, pf_system_uncatch_sig, 18, { 's','y','s','t','e','m','-','u','n','c','a','t','c','h','-','s','i','g' } },
{ 0, 0, pf_gc, 2, { 'g','c' } }, { 0, 0, pf_gc, 2, { 'g','c' } },
@@ -1435,30 +1434,7 @@ static pf_t builtin_prims[] =
{ 0, 0, pf_va_context, 10, { 'v','a','-','c','o','n','t','e','x','t' } }, { 0, 0, pf_va_context, 10, { 'v','a','-','c','o','n','t','e','x','t' } },
{ 0, 1, pf_va_count, 8, { 'v','a','-','c','o','u','n','t' } }, { 0, 1, pf_va_count, 8, { 'v','a','-','c','o','u','n','t' } },
{ 1, 2, pf_va_get, 6, { 'v','a','-','g','e','t' } }, { 1, 2, pf_va_get, 6, { 'v','a','-','g','e','t' } }
{ 1, 2, pf_object_new, 10, { 'o','b','j','e','c','t','-','n','e','w' } },
{ 0, 0, hak_pf_process_current, 15, { 'c','u','r','r','e','n','t','-','p','r','o','c','e','s','s'} },
{ 1, HAK_TYPE_MAX(hak_oow_t), hak_pf_process_fork, 4, { 'f','o','r','k'} },
{ 1, 1, hak_pf_process_resume, 6, { 'r','e','s','u','m','e' } },
{ 0, 1, hak_pf_process_suspend, 7, { 's','u','s','p','e','n','d' } },
{ 0, 1, hak_pf_process_terminate, 9, { 't','e','r','m','i','n','a','t','e' } },
{ 0, 0, hak_pf_process_terminate_all, 13, { 't','e','r','m','i','n','a','t','e','-','a','l','l' } },
{ 0, 0, hak_pf_process_yield, 5, { 'y','i','e','l','d'} },
{ 0, 0, hak_pf_semaphore_new, 7, { 's','e','m','-','n','e','w'} },
{ 1, 1, hak_pf_semaphore_wait, 8, { 's','e','m','-','w','a','i','t'} },
{ 1, 3, hak_pf_semaphore_signal, 10, { 's','e','m','-','s','i','g','n','a','l'} },
{ 2, 2, hak_pf_semaphore_signal_on_input, 19, { 's','e','m','-','s','i','g','n','a','l','-','o','n','-','i','n','p','u','t'} },
{ 2, 2, hak_pf_semaphore_signal_on_output, 20, { 's','e','m','-','s','i','g','n','a','l','-','o','n','-','o','u','t','p','u','t'} },
{ 1, 1, hak_pf_semaphore_unsignal, 12, { 's','e','m','-','u','n','s','i','g','n','a','l'} },
{ 0, 0, hak_pf_semaphore_group_new, 9, { 's','e','m','g','r','-','n','e','w'} },
{ 1, 2, hak_pf_semaphore_group_add_semaphore, 9, { 's','e','m','g','r','-','a','d','d'} },
{ 1, 2, hak_pf_semaphore_group_remove_semaphore, 12, { 's','e','m','g','r','-','r','e','m','o','v','e'} },
{ 1, 1, hak_pf_semaphore_group_wait, 10, { 's','e','m','g','r','-','w','a','i','t'} }
}; };
int hak_addbuiltinprims (hak_t* hak) int hak_addbuiltinprims (hak_t* hak)
+38 -9
View File
@@ -32,15 +32,20 @@
#define SALIT_BUFFER_ALIGN 128 #define SALIT_BUFFER_ALIGN 128
#define ARLIT_BUFFER_ALIGN 128 #define ARLIT_BUFFER_ALIGN 128
#define INCLUDE_FILE_NONE (0)
#define INCLUDE_FILE_NORMAL (1)
#define INCLUDE_FILE_ONCE (2)
static struct voca_t static struct voca_t
{ {
hak_oow_t len; hak_oow_t len;
hak_ooch_t str[11]; hak_ooch_t str[15];
} vocas[] = } vocas[] =
{ {
/* TODO: change $include and $pragma to #\include or #\pragma or use some other prefix like #^ -> $ to use really for variable reference or something... /* TODO: change $include and $pragma to #\include or #\pragma or use some other prefix like #^ -> $ to use really for variable reference or something...
* TODO: change #\ to something else... */ * TODO: change #\ to something else... */
{ 8, { '$','i','n','c','l','u','d','e' } }, { 8, { '$','i','n','c','l','u','d','e' } },
{ 13, { '$','i','n','c','l','u','d','e','-','o','n','c','e' } },
{ 7, { '$','p','r','a','g','m','a' } }, { 7, { '$','p','r','a','g','m','a' } },
{ 11, { '#','\\','b','a','c','k','s','p','a','c','e' } }, { 11, { '#','\\','b','a','c','k','s','p','a','c','e' } },
@@ -110,6 +115,7 @@ static struct voca_t
enum voca_id_t enum voca_id_t
{ {
VOCA_INCLUDE, VOCA_INCLUDE,
VOCA_INCLUDE_ONCE,
VOCA_PRAGMA, VOCA_PRAGMA,
VOCA_CHAR_BACKSPACE, VOCA_CHAR_BACKSPACE,
@@ -400,6 +406,11 @@ static int get_directive_token_type (hak_t* hak, hak_tok_type_t* tok_type)
*tok_type = HAK_TOK_INCLUDE; *tok_type = HAK_TOK_INCLUDE;
return 0; return 0;
} }
else if (does_token_name_match(hak, VOCA_INCLUDE_ONCE))
{
*tok_type = HAK_TOK_INCLUDE_ONCE;
return 0;
}
else if (does_token_name_match(hak, VOCA_PRAGMA)) else if (does_token_name_match(hak, VOCA_PRAGMA))
{ {
*tok_type = HAK_TOK_PRAGMA; *tok_type = HAK_TOK_PRAGMA;
@@ -1440,11 +1451,15 @@ static void init_feed (hak_t* hak)
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static int feed_begin_include (hak_t* hak) static int feed_begin_include (hak_t* hak, int once)
{ {
hak_io_cciarg_t* arg; hak_io_cciarg_t* arg;
const hak_ooch_t* io_name; const hak_ooch_t* io_name;
/* TODO: handle once... */
/* how to handle uniqueness of the io_name?
* purely based on this io_name????
* or the real path? or the name io_name, the real_path can still be different depending on the source... */
io_name = add_sr_name(hak, TOKEN_NAME(hak)); io_name = add_sr_name(hak, TOKEN_NAME(hak));
if (HAK_UNLIKELY(!io_name)) if (HAK_UNLIKELY(!io_name))
{ {
@@ -1453,6 +1468,14 @@ static int feed_begin_include (hak_t* hak)
return -1; return -1;
} }
/*
hak_logbfmt(hak, HAK_LOG_STDERR, "io_name = [%js]\n", io_name);
if (hak->c->curinp == &hak->c->cci_arg)
hak_logbfmt(hak, HAK_LOG_STDERR, "PAR = TOP\n");
else
hak_logbfmt(hak, HAK_LOG_STDERR, "PAR = [%js]\n", hak->c->curinp->name);
*/
arg = (hak_io_cciarg_t*)hak_callocmem(hak, HAK_SIZEOF(*arg)); arg = (hak_io_cciarg_t*)hak_callocmem(hak, HAK_SIZEOF(*arg));
if (HAK_UNLIKELY(!arg)) if (HAK_UNLIKELY(!arg))
{ {
@@ -1761,12 +1784,12 @@ static int feed_process_token (hak_t* hak)
goto oops; goto oops;
} }
frd->expect_include_file = 0;
/* indicate that the file inclusion should be performed soon. /* indicate that the file inclusion should be performed soon.
* don't perform actual inclusion here so that the return value of * don't perform actual inclusion here so that the return value of
* feed_char() advances the input pointers properly. */ * feed_char() advances the input pointers properly. */
frd->do_include_file = 1; frd->do_include_file = frd->expect_include_file;
frd->expect_include_file = INCLUDE_FILE_NONE;
goto ok; goto ok;
} }
@@ -1804,7 +1827,11 @@ static int feed_process_token (hak_t* hak)
case HAK_TOK_INCLUDE: case HAK_TOK_INCLUDE:
/* TODO: should i limit where #include can be specified? /* TODO: should i limit where #include can be specified?
* disallow it inside a list literal or an array literal? */ * disallow it inside a list literal or an array literal? */
frd->expect_include_file = 1; frd->expect_include_file = INCLUDE_FILE_NORMAL;
goto ok;
case HAK_TOK_INCLUDE_ONCE:
frd->expect_include_file = INCLUDE_FILE_ONCE;
goto ok; goto ok;
case HAK_TOK_PRAGMA: case HAK_TOK_PRAGMA:
@@ -3916,8 +3943,9 @@ static int feed_from_includee (hak_t* hak)
* directive, sets hak->c->feed.rd.do_include_file to 1 instead of attepmting * directive, sets hak->c->feed.rd.do_include_file to 1 instead of attepmting
* to include the file. the file inclusion is attempted here after the return * to include the file. the file inclusion is attempted here after the return
* value of feed_char() is used to advance the hak->c->curinp->b.pos pointer. */ * value of feed_char() is used to advance the hak->c->curinp->b.pos pointer. */
hak->c->feed.rd.do_include_file = 0; /* clear this regardless of inclusion result */ int incmod = hak->c->feed.rd.do_include_file;
if (feed_begin_include(hak) <= -1) goto oops; hak->c->feed.rd.do_include_file = INCLUDE_FILE_NONE; /* clear this regardless of inclusion result */
if (feed_begin_include(hak, incmod == INCLUDE_FILE_ONCE) <= -1) goto oops;
curinp = hak->c->curinp; curinp = hak->c->curinp;
} }
} }
@@ -4012,8 +4040,9 @@ int hak_feed (hak_t* hak, const hak_ooch_t* data, hak_oow_t len)
if (hak->c->feed.rd.do_include_file) if (hak->c->feed.rd.do_include_file)
{ {
hak->c->feed.rd.do_include_file = 0; /* done regardless of inclusion result */ int incmod = hak->c->feed.rd.do_include_file;
if (feed_begin_include(hak) <= -1) goto oops; hak->c->feed.rd.do_include_file = INCLUDE_FILE_NONE; /* done regardless of inclusion result */
if (feed_begin_include(hak, incmod == INCLUDE_FILE_ONCE) <= -1) goto oops;
} }
if (hak->c->curinp && hak->c->curinp != &hak->c->cci_arg && feed_from_includee(hak) <= -1) if (hak->c->curinp && hak->c->curinp != &hak->c->cci_arg && feed_from_includee(hak) <= -1)
+528 -127
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -212,7 +212,7 @@ hak_client_t* hak_client_open (hak_mmgr_t* mmgr, hak_oow_t xtnsize, hak_client_p
/* the dummy hak is used for this client to perform primitive operations /* the dummy hak is used for this client to perform primitive operations
* such as getting system time or logging. so the heap size doesn't * such as getting system time or logging. so the heap size doesn't
* need to be changed from the tiny value set above. */ * need to be changed from the tiny value set above. */
hak_setoption (client->dummy_hak, HAK_LOG_MASK, &client->cfg.logmask); hak_setoption (client->dummy_hak, HAK_OPT_LOG_MASK, &client->cfg.logmask);
hak_setcmgr (client->dummy_hak, client->_cmgr); hak_setcmgr (client->dummy_hak, client->_cmgr);
return client; return client;
@@ -258,7 +258,7 @@ int hak_client_setoption (hak_client_t* client, hak_client_option_t id, const vo
* existing hak instances inside worker threads won't get * existing hak instances inside worker threads won't get
* affected. new hak instances to be created later * affected. new hak instances to be created later
* is supposed to use the new value */ * is supposed to use the new value */
hak_setoption (client->dummy_hak, HAK_LOG_MASK, value); hak_setoption (client->dummy_hak, HAK_OPT_LOG_MASK, value);
} }
return 0; return 0;
} }
+10 -10
View File
@@ -1177,14 +1177,14 @@ hak_server_t* hak_server_open (hak_mmgr_t* mmgr, hak_oow_t xtnsize, hak_server_p
/* the dummy hak is used for this server to perform primitive operations /* the dummy hak is used for this server to perform primitive operations
* such as getting system time or logging. so the heap size doesn't * such as getting system time or logging. so the heap size doesn't
* need to be changed from the tiny value set above. */ * need to be changed from the tiny value set above. */
hak_setoption (server->dummy_hak, HAK_LOG_MASK, &server->cfg.logmask); hak_setoption (server->dummy_hak, HAK_OPT_LOG_MASK, &server->cfg.logmask);
hak_setcmgr (server->dummy_hak, hak_server_getcmgr(server)); hak_setcmgr (server->dummy_hak, hak_server_getcmgr(server));
hak_getoption (server->dummy_hak, HAK_TRAIT, &trait); hak_getoption (server->dummy_hak, HAK_OPT_TRAIT, &trait);
#if defined(HAK_BUILD_DEBUG) #if defined(HAK_BUILD_DEBUG)
if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_GC) trait |= HAK_TRAIT_DEBUG_GC; if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_GC) trait |= HAK_TRAIT_DEBUG_GC;
if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_BIGINT) trait |= HAK_TRAIT_DEBUG_BIGINT; if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_BIGINT) trait |= HAK_TRAIT_DEBUG_BIGINT;
#endif #endif
hak_setoption (server->dummy_hak, HAK_TRAIT, &trait); hak_setoption (server->dummy_hak, HAK_OPT_TRAIT, &trait);
return server; return server;
@@ -1517,17 +1517,17 @@ static int init_worker_hak (hak_server_worker_t* worker)
xtn = (worker_hak_xtn_t*)hak_getxtn(hak); xtn = (worker_hak_xtn_t*)hak_getxtn(hak);
xtn->worker = worker; xtn->worker = worker;
hak_setoption(hak, HAK_MOD_INCTX, &server->cfg.module_inctx); hak_setoption(hak, HAK_OPT_MODINCTX, &server->cfg.module_inctx);
hak_setoption(hak, HAK_LOG_MASK, &server->cfg.logmask); hak_setoption(hak, HAK_OPT_LOG_MASK, &server->cfg.logmask);
hak_setcmgr(hak, hak_server_getcmgr(server)); hak_setcmgr(hak, hak_server_getcmgr(server));
hak_getoption(hak, HAK_TRAIT, &trait); hak_getoption(hak, HAK_OPT_TRAIT, &trait);
#if defined(HAK_BUILD_DEBUG) #if defined(HAK_BUILD_DEBUG)
if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_GC) trait |= HAK_TRAIT_DEBUG_GC; if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_GC) trait |= HAK_TRAIT_DEBUG_GC;
if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_BIGINT) trait |= HAK_TRAIT_DEBUG_BIGINT; if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_BIGINT) trait |= HAK_TRAIT_DEBUG_BIGINT;
#endif #endif
trait |= HAK_TRAIT_LANG_ENABLE_EOL; trait |= HAK_TRAIT_LANG_ENABLE_EOL;
hak_setoption(hak, HAK_TRAIT, &trait); hak_setoption(hak, HAK_OPT_TRAIT, &trait);
HAK_MEMSET(&hakcb, 0, HAK_SIZEOF(hakcb)); HAK_MEMSET(&hakcb, 0, HAK_SIZEOF(hakcb));
/*hakcb.fini = fini_hak; /*hakcb.fini = fini_hak;
@@ -2050,12 +2050,12 @@ int hak_server_setoption (hak_server_t* server, hak_server_option_t id, const vo
* is supposed to use the new value */ * is supposed to use the new value */
hak_bitmask_t trait; hak_bitmask_t trait;
hak_getoption (server->dummy_hak, HAK_TRAIT, &trait); hak_getoption (server->dummy_hak, HAK_OPT_TRAIT, &trait);
#if defined(HAK_BUILD_DEBUG) #if defined(HAK_BUILD_DEBUG)
if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_GC) trait |= HAK_TRAIT_DEBUG_GC; if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_GC) trait |= HAK_TRAIT_DEBUG_GC;
if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_BIGINT) trait |= HAK_TRAIT_DEBUG_BIGINT; if (server->cfg.trait & HAK_SERVER_TRAIT_DEBUG_BIGINT) trait |= HAK_TRAIT_DEBUG_BIGINT;
#endif #endif
hak_setoption (server->dummy_hak, HAK_TRAIT, &trait); hak_setoption (server->dummy_hak, HAK_OPT_TRAIT, &trait);
} }
return 0; return 0;
@@ -2067,7 +2067,7 @@ int hak_server_setoption (hak_server_t* server, hak_server_option_t id, const vo
* existing hak instances inside worker threads won't get * existing hak instances inside worker threads won't get
* affected. new hak instances to be created later * affected. new hak instances to be created later
* is supposed to use the new value */ * is supposed to use the new value */
hak_setoption (server->dummy_hak, HAK_LOG_MASK, value); hak_setoption (server->dummy_hak, HAK_OPT_LOG_MASK, value);
} }
return 0; return 0;
+27
View File
@@ -584,6 +584,9 @@ static hak_pfinfo_t pfinfos[] =
/* TODO: add more builtin primitives here... */ /* TODO: add more builtin primitives here... */
{ "abs", { HAK_PFBASE_FUNC, hak_pf_number_abs, 1, 1 } }, { "abs", { HAK_PFBASE_FUNC, hak_pf_number_abs, 1, 1 } },
{ "active-process", { HAK_PFBASE_FUNC, hak_pf_process_current, 0, 0 } },
{ "basicAt", { HAK_PFBASE_FUNC, pf_core_basic_at, 2, 2 } }, { "basicAt", { HAK_PFBASE_FUNC, pf_core_basic_at, 2, 2 } },
{ "basicAtPut", { HAK_PFBASE_FUNC, pf_core_basic_at_put, 3, 3 } }, { "basicAtPut", { HAK_PFBASE_FUNC, pf_core_basic_at_put, 3, 3 } },
{ "basicNew", { HAK_PFBASE_FUNC, pf_core_basic_new, 1, 2 } }, { "basicNew", { HAK_PFBASE_FUNC, pf_core_basic_new, 1, 2 } },
@@ -609,17 +612,41 @@ static hak_pfinfo_t pfinfos[] =
{ "eql?", { HAK_PFBASE_FUNC, hak_pf_eql, 2, 2 } }, { "eql?", { HAK_PFBASE_FUNC, hak_pf_eql, 2, 2 } },
{ "eqv?", { HAK_PFBASE_FUNC, hak_pf_eqv, 2, 2 } }, { "eqv?", { HAK_PFBASE_FUNC, hak_pf_eqv, 2, 2 } },
{ "fork", { HAK_PFBASE_FUNC, hak_pf_process_fork, 1, HAK_TYPE_MAX(hak_oow_t) } },
{ "instRespondsTo", { HAK_PFBASE_FUNC, pf_core_inst_responds_to, 2, 2 } }, { "instRespondsTo", { HAK_PFBASE_FUNC, pf_core_inst_responds_to, 2, 2 } },
{ "nqk?", { HAK_PFBASE_FUNC, hak_pf_nqk, 2, 2 } }, { "nqk?", { HAK_PFBASE_FUNC, hak_pf_nqk, 2, 2 } },
{ "nql?", { HAK_PFBASE_FUNC, hak_pf_nql, 2, 2 } }, { "nql?", { HAK_PFBASE_FUNC, hak_pf_nql, 2, 2 } },
{ "nqv?", { HAK_PFBASE_FUNC, hak_pf_nqv, 2, 2 } }, { "nqv?", { HAK_PFBASE_FUNC, hak_pf_nqv, 2, 2 } },
{ "object-new", { HAK_PFBASE_FUNC, hak_pf_object_new, 1, 2 } },
{ "primAt", { HAK_PFBASE_FUNC, pf_core_prim_at, 2, 2 } }, { "primAt", { HAK_PFBASE_FUNC, pf_core_prim_at, 2, 2 } },
{ "primAtPut", { HAK_PFBASE_FUNC, pf_core_prim_at_put, 3, 3 } }, { "primAtPut", { HAK_PFBASE_FUNC, pf_core_prim_at_put, 3, 3 } },
{ "resume", { HAK_PFBASE_FUNC, hak_pf_process_resume, 1, 1 } },
{ "sem-new", { HAK_PFBASE_FUNC, hak_pf_semaphore_new, 0, 1 } },
{ "sem-signal", { HAK_PFBASE_FUNC, hak_pf_semaphore_signal, 1, 3 } },
{ "sem-signal-on-input", { HAK_PFBASE_FUNC, hak_pf_semaphore_signal_on_input, 2, 2 } },
{ "sem-signal-on-output", { HAK_PFBASE_FUNC, hak_pf_semaphore_signal_on_output, 2, 2 } },
{ "sem-trywait", { HAK_PFBASE_FUNC, hak_pf_semaphore_trywait, 1, 1 } },
{ "sem-unsignal", { HAK_PFBASE_FUNC, hak_pf_semaphore_unsignal, 1, 1 } },
{ "sem-wait", { HAK_PFBASE_FUNC, hak_pf_semaphore_wait, 1, 1 } },
{ "semgr-add", { HAK_PFBASE_FUNC, hak_pf_semaphore_group_add_semaphore, 1, 2 } },
{ "semgr-new", { HAK_PFBASE_FUNC, hak_pf_semaphore_group_new, 0, 0 } },
{ "semgr-remove", { HAK_PFBASE_FUNC, hak_pf_semaphore_group_remove_semaphore, 1, 2 } },
{ "semgr-wait", { HAK_PFBASE_FUNC, hak_pf_semaphore_group_wait, 1, 1 } },
{ "slice", { HAK_PFBASE_FUNC, pf_core_slice, 3, 3 } }, { "slice", { HAK_PFBASE_FUNC, pf_core_slice, 3, 3 } },
{ "smooiToChar", { HAK_PFBASE_FUNC, pf_core_smooi_to_char, 1, 1 } }, { "smooiToChar", { HAK_PFBASE_FUNC, pf_core_smooi_to_char, 1, 1 } },
{ "sqrt", { HAK_PFBASE_FUNC, hak_pf_number_sqrt, 1, 1 } }, { "sqrt", { HAK_PFBASE_FUNC, hak_pf_number_sqrt, 1, 1 } },
{ "suspend", { HAK_PFBASE_FUNC, hak_pf_process_suspend, 0, 1 } },
{ "terminate", { HAK_PFBASE_FUNC, hak_pf_process_terminate, 0, 1 } },
{ "terminate-all", { HAK_PFBASE_FUNC, hak_pf_process_terminate_all, 0, 0 } },
{ "yield", { HAK_PFBASE_FUNC, hak_pf_process_yield, 0, 0 } },
{ "~=", { HAK_PFBASE_FUNC, hak_pf_number_ne, 2, 2 } }, { "~=", { HAK_PFBASE_FUNC, hak_pf_number_ne, 2, 2 } },
}; };
+80 -42
View File
@@ -31,13 +31,22 @@
#endif #endif
#include "_sys.h" #include "_sys.h"
#include <hak-hnd.h> #include "../lib/hak-prv.h"
#include <hak-pio.h> #include <hak-pio.h>
#include <hak-str.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#if !defined(_WIN32) #if defined(_WIN32)
# if !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0400
# endif
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <io.h> /* close() */
# include <fcntl.h>
# include <errno.h>
# include <time.h>
#else
# include <sys/types.h> # include <sys/types.h>
# include <sys/stat.h> # include <sys/stat.h>
# include <unistd.h> # include <unistd.h>
@@ -111,6 +120,28 @@ static hak_pfrc_t pf_sys_stime (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
_dos_setdate(&dd); _dos_setdate(&dd);
_dos_settime(&dt); _dos_settime(&dt);
} }
#elif defined(_WIN32)
{
time_t tv = (time_t)ti;
struct tm* tm;
/* SetSystemTime() takes UTC, so break the epoch value down with
* gmtime() rather than localtime() */
tm = gmtime(&tv);
if (tm)
{
SYSTEMTIME st;
st.wYear = (WORD)(tm->tm_year + 1900);
st.wMonth = (WORD)(tm->tm_mon + 1); /* 1-12, unlike tm_mon */
st.wDayOfWeek = (WORD)tm->tm_wday;
st.wDay = (WORD)tm->tm_mday;
st.wHour = (WORD)tm->tm_hour;
st.wMinute = (WORD)tm->tm_min;
st.wSecond = (WORD)tm->tm_sec;
st.wMilliseconds = 0;
SetSystemTime(&st);
}
}
#else #else
{ {
time_t tv; time_t tv;
@@ -137,7 +168,7 @@ static hak_pfrc_t pf_sys_srandom (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
return HAK_PF_FAILURE; return HAK_PF_FAILURE;
} }
#if defined(__DOS__) #if defined(__DOS__) || defined(_WIN32)
srand (seedw); srand (seedw);
#else #else
srandom (seedw); srandom (seedw);
@@ -152,7 +183,7 @@ static hak_pfrc_t pf_sys_random (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
long int r; long int r;
hak_ooi_t rv; hak_ooi_t rv;
#if defined(__DOS__) #if defined(__DOS__) || defined(_WIN32)
r = rand(); r = rand();
#else #else
r = random(); r = random();
@@ -174,7 +205,7 @@ static hak_pfrc_t pf_sys_random (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
* sys.read and sys.write follow the non-blocking contract: they return the * sys.read and sys.write follow the non-blocking contract: they return the
* byte count, 0 at end of file, or -1 when the handle would have blocked. * byte count, 0 at end of file, or -1 when the handle would have blocked.
* -1 is an ordinary outcome - the caller is expected to wait on a semaphore * -1 is an ordinary outcome - the caller is expected to wait on a semaphore
* bound with sem-signal-on-input/-output and try again. Only a genuine * bound with core.sem-signal-on-input/-output and try again. Only a genuine
* failure raises. * failure raises.
* ------------------------------------------------------------------------ */ * ------------------------------------------------------------------------ */
@@ -735,88 +766,95 @@ static hak_pfrc_t pf_sys_pclose (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
static hak_pfinfo_t pfinfos[] = static hak_pfinfo_t pfinfos[] =
{ {
#if defined(SIGABRT) #if defined(SIGABRT)
{ "SIGABRT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGABRT }}, { "SIGABRT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGABRT }},
#endif #endif
#if defined(SIGALRM) #if defined(SIGALRM)
{ "SIGALRM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGALRM }}, { "SIGALRM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGALRM }},
#endif #endif
#if defined(SIGBUS) #if defined(SIGBUS)
{ "SIGBUS", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGBUS }}, { "SIGBUS", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGBUS }},
#endif #endif
#if defined(SIGCHLD) #if defined(SIGCHLD)
{ "SIGCHLD", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGCHLD }}, { "SIGCHLD", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGCHLD }},
#endif #endif
#if defined(SIGCONT) #if defined(SIGCONT)
{ "SIGCONT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGCONT }}, { "SIGCONT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGCONT }},
#endif #endif
#if defined(SIGFPE) #if defined(SIGFPE)
{ "SIGFPE", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGFPE }}, { "SIGFPE", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGFPE }},
#endif #endif
#if defined(SIGHUP) #if defined(SIGHUP)
{ "SIGHUP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGHUP }}, { "SIGHUP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGHUP }},
#endif #endif
#if defined(SIGILL) #if defined(SIGILL)
{ "SIGILL", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGILL }}, { "SIGILL", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGILL }},
#endif #endif
#if defined(SIGINT) #if defined(SIGINT)
{ "SIGINT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGINT }}, { "SIGINT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGINT }},
#endif #endif
#if defined(SIGKILL) #if defined(SIGKILL)
{ "SIGKILL", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGKILL }}, { "SIGKILL", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGKILL }},
#endif #endif
#if defined(SIGPIPE) #if defined(SIGPIPE)
{ "SIGPIPE", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGPIPE }}, { "SIGPIPE", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGPIPE }},
#endif #endif
#if defined(SIGQUIT) #if defined(SIGQUIT)
{ "SIGQUIT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGQUIT }}, { "SIGQUIT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGQUIT }},
#endif #endif
#if defined(SIGSEGV) #if defined(SIGSEGV)
{ "SIGSEGV", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGSEGV }}, { "SIGSEGV", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGSEGV }},
#endif #endif
#if defined(SIGSTOP) #if defined(SIGSTOP)
{ "SIGSTOP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGSTOP }}, { "SIGSTOP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGSTOP }},
#endif #endif
#if defined(SIGTERM) #if defined(SIGTERM)
{ "SIGTERM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTERM }}, { "SIGTERM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTERM }},
#endif #endif
#if defined(SIGTSTP) #if defined(SIGTSTP)
{ "SIGTSTP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTSTP }}, { "SIGTSTP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTSTP }},
#endif #endif
#if defined(SIGTTIN) #if defined(SIGTTIN)
{ "SIGTTIN", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTTIN }}, { "SIGTTIN", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTTIN }},
#endif #endif
#if defined(SIGTTOU) #if defined(SIGTTOU)
{ "SIGTTOU", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTTOU }}, { "SIGTTOU", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTTOU }},
#endif #endif
#if defined(SIGURG) #if defined(SIGURG)
{ "SIGURG", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGURG }}, { "SIGURG", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGURG }},
#endif #endif
#if defined(SIGUSR1) #if defined(SIGUSR1)
{ "SIGUSR1", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGUSR1 }}, { "SIGUSR1", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGUSR1 }},
#endif #endif
#if defined(SIGUSR2) #if defined(SIGUSR2)
{ "SIGUSR2", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGUSR2 }}, { "SIGUSR2", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGUSR2 }},
#endif #endif
#if defined(SIGVTALRM) #if defined(SIGVTALRM)
{ "SIGVTALRM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGVTALRM }}, { "SIGVTALRM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGVTALRM }},
#endif #endif
#if defined(SIGWINCH) #if defined(SIGWINCH)
{ "SIGWINCH", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGWINCH }}, { "SIGWINCH", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGWINCH }},
#endif #endif
{ "close", { HAK_PFBASE_FUNC, pf_sys_close, 1, 1 } }, { "close", { HAK_PFBASE_FUNC, pf_sys_close, 1, 1 } },
{ "open", { HAK_PFBASE_FUNC, pf_sys_open, 2, 3 } }, { "open", { HAK_PFBASE_FUNC, pf_sys_open, 2, 3 } },
{ "pclose", { HAK_PFBASE_FUNC, pf_sys_pclose, 1, 1 } }, { "pclose", { HAK_PFBASE_FUNC, pf_sys_pclose, 1, 1 } },
{ "pipe", { HAK_PFBASE_FUNC, pf_sys_pipe, 0, 0 } }, { "pipe", { HAK_PFBASE_FUNC, pf_sys_pipe, 0, 0 } },
{ "pkill", { HAK_PFBASE_FUNC, pf_sys_pkill, 1, 1 } }, { "pkill", { HAK_PFBASE_FUNC, pf_sys_pkill, 1, 1 } },
{ "popen", { HAK_PFBASE_FUNC, pf_sys_popen, 1, 2 } }, { "popen", { HAK_PFBASE_FUNC, pf_sys_popen, 1, 2 } },
{ "pwait", { HAK_PFBASE_FUNC, pf_sys_pwait, 1, 1 } }, { "pwait", { HAK_PFBASE_FUNC, pf_sys_pwait, 1, 1 } },
{ "random", { HAK_PFBASE_FUNC, pf_sys_random, 0, 0 } }, { "random", { HAK_PFBASE_FUNC, pf_sys_random, 0, 0 } },
{ "read", { HAK_PFBASE_FUNC, pf_sys_read, 2, 4 } }, { "read", { HAK_PFBASE_FUNC, pf_sys_read, 2, 4 } },
{ "srandom", { HAK_PFBASE_FUNC, pf_sys_srandom, 1, 1 } },
{ "stime", { HAK_PFBASE_FUNC, pf_sys_stime, 1, 1 } }, { "sig-catch", { HAK_PFBASE_FUNC, hak_pf_system_catch_sig, 1, 1 } },
{ "time", { HAK_PFBASE_FUNC, pf_sys_time, 0, 0 } }, { "sig-get", { HAK_PFBASE_FUNC, hak_pf_system_get_sig, 0, 0 } },
{ "write", { HAK_PFBASE_FUNC, pf_sys_write, 2, 4 } } { "sig-getfd", { HAK_PFBASE_FUNC, hak_pf_system_get_sigfd, 0, 0 } },
{ "sig-set", { HAK_PFBASE_FUNC, hak_pf_system_set_sig, 1, 1 } },
{ "sig-uncatch", { HAK_PFBASE_FUNC, hak_pf_system_uncatch_sig, 1, 1 } },
{ "srandom", { HAK_PFBASE_FUNC, pf_sys_srandom, 1, 1 } },
{ "stime", { HAK_PFBASE_FUNC, pf_sys_stime, 1, 1 } },
{ "time", { HAK_PFBASE_FUNC, pf_sys_time, 0, 0 } },
{ "write", { HAK_PFBASE_FUNC, pf_sys_write, 2, 4 } }
}; };
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
+4 -1
View File
@@ -23,7 +23,7 @@ class FixedSizedCollection: IndexedCollection {
fun[#class] new(size) { fun[#class] new(size) {
| obj iv | | obj iv |
obj := (core.basicNew self size) obj := (core.basicNew self size)
if (self:respondsTo "initValue") { ## TODO: change "initValue" to a symbol once supported if (self:respondsTo #initValue) {
i := 0 i := 0
iv := (self:initValue) iv := (self:initValue)
while (< i size) { ## TODO: change to i < size after having implemented these methods on integer/smallintger while (< i size) { ## TODO: change to i < size after having implemented these methods on integer/smallintger
@@ -42,6 +42,9 @@ class FixedSizedCollection: IndexedCollection {
class[#varying] Array: FixedSizedCollection { class[#varying] Array: FixedSizedCollection {
} }
class[#byte #varying] ByteArray: FixedSizedCollection {
}
class[#char #varying] String: FixedSizedCollection { class[#char #varying] String: FixedSizedCollection {
fun[#class] initValue() { fun[#class] initValue() {
##return '\0' ##return '\0'
+75
View File
@@ -0,0 +1,75 @@
##$include-once "Semaphore.hak"
class[#uncopyable] Mutex: Object(
_sem
_owner
) {
fun[#ci] new() {
self._sem := (Semaphore:forMutex)
self._owner := nil
return self
}
## TODO: support relay of variable arguments to (fnc args...)
##fun critical(fnc args...) {
fun critical(fnc) {
| p ex r |
p := (core.active-process)
## already the owner: just run the body. the outermost critical
## is the one that releases, so nesting needs no bookkeeping.
if (eqv? p self._owner) { return (fnc) }
## the function must never terminate the process.
## if it does, the owner will get stuck to that terminated process
## process forever. for now, there is no automatic clean-up.
self._sem:wait
self._owner := p
## TODO: update code to use 'finally' if 'finally' is implemented...
try { r := (fnc) } catch (e) { ex := e }
self._owner := nil
self._sem:signal
if (nqv? ex nil) { throw ex }
return r
}
## the non-blocking form of critical. runs fnc and answers true if the
## mutex was free - or already held by this very process - and answers
## false at once, without running fnc, if another process holds it.
##
## note this answers true/false rather than the body's value, unlike
## critical: there would otherwise be no way to tell "the body answered
## nil" from "the body never ran". have fnc assign to a captured variable
## if it needs to report something back.
fun tryCritical(fnc) {
| p ex |
p := (core.active-process)
## already the owner. same reasoning as critical: the outermost
## critical is the one that releases, so nesting needs no bookkeeping
if (eqv? p self._owner) { fnc ; return true }
## core.sem-trywait either takes the semaphore or answers false. it
## never suspends, so there is no window where another process could
## slip in between testing the mutex and claiming it.
if (self._sem:tryWait) {
self._owner := p
## TODO: update code to use 'finally' if 'finally' is implemented...
try { fnc } catch (e) { ex := e }
self._owner := nil
self._sem:signal
if (nqv? ex nil) { throw ex }
return true
}
return false
}
}
+76
View File
@@ -0,0 +1,76 @@
class Apex {
fun isNil?() { return false }
fun notNil?() { return true }
fun[#class] basicNew(size) {
return (core.basicNew self size)
}
fun[#class] respondsTo(mthname) {
return (core.classRespondsTo self mthname)
}
fun respondsTo(mthname) {
return (core.instRespondsTo self mthname)
}
fun primAt(pos) {
return (core.primAt self pos)
}
fun primtAtPut(pos value) {
return (core.primAtPut self pos value)
}
fun basicAt(pos) {
return (core.basicAt self pos)
}
fun basicAtPut(pos value) {
return (core.basicAtPut self pos value)
}
fun basicSize() {
return (core.basicSize self)
}
## TODO: ...
fun == (oprnd) { return (== self oprnd) }
fun != (oprnd) { return (!= self oprnd) }
## TODO: fun perform(name ...) {}
}
class[#uncopyable #varying #limited #final] Class: Apex (
_name
_mdic
_spec
_selfspec
_superclass
_nivars_super
_ibrand
_ivarnames
_cvarnames
) {
fun name() {
##return (core.className self)
return _class
}
fun instanceVariableNames() {
## TODO: this still returns nil as the acutal manipulation of the field has not been implemented
return _ivarnames
}
fun classVariableNames() {
## TODO: this still returns nil as the acutal manipulation of the field has not been implemented
return _cvarnames
}
}
class UndefinedObject: Apex {
fun isNil?() { return true }
fun notNil?() { return false }
}
class Object: Apex {
}
+31
View File
@@ -0,0 +1,31 @@
##$include-once "Object.hak"
class[#uncopyable #final #limited #varying] Process: Object(
_initial_context
_current_context
_id
_state
_sp
_st
_exsp
_exst
_clsp
_clst
_fsp
_fst
_sched_prev
_sched_next
_sem_wawit_prev
_sem_wait_next
_sem
) {
## TODO: add many read-only methods
fun id() {
return self._id
}
fun state() {
return self._state
}
}
+80
View File
@@ -0,0 +1,80 @@
##$include-once "Object.hak"
class[#uncopyable] Semaphore: Object(
_waiting_first
_wait_last
_count
_subtype
_index
_ftime_sec_or_handle
_ftime_nsec_or_type
_signal_action
_group
_grm_prev
_grm_next
) {
fun[#class] new() {
return (core.sem-new 0)
}
fun[#class] forMutex() {
return (core.sem-new 1)
}
fun signal() {
return (core.sem-signal self 0 0)
}
fun signalAfter(secs nsecs) {
return (core.sem-signal self secs nsecs)
}
fun signalOnInput(handle) {
return (core.sem-signal-on-input self handle)
}
fun signalOnOutput(handle) {
return (core.sem-signal-on-output self handle)
}
## acquire without ever blocking. answers true if acquired, false if the
## semaphore was unsignalled and waiting would have been necessary.
fun tryWait() {
return (core.sem-trywait self)
}
fun unsignal() {
return (core.sem-unsignal self)
}
fun wait() {
return (core.sem-wait self)
}
}
class[#uncopyable] SemaphoreGroup: Object(
_waiting_first
_waiting_last
_sem_unsig_first
_sem_unsig_last
_sem_sig_first
_sem_sig_last
_sem_io_count
_sem_count
) {
fun[#class] new() {
return (core.semgr-new)
}
fun add(sem) {
return (core.semgr-add self sem)
}
fun remove(sem) {
return (core.semgr-remove self sem)
}
fun wait() {
return (core.semgr-wait self)
}
}
+6 -79
View File
@@ -1,84 +1,11 @@
class Apex { $include "Object.hak"
fun isNil?() { return false }
fun notNil?() { return true }
fun[#class] basicNew(size) {
return (core.basicNew self size)
}
fun[#class] respondsTo(mthname) {
return (core.classRespondsTo self mthname)
}
fun respondsTo(mthname) {
return (core.instRespondsTo self mthname)
}
fun primAt(pos) {
return (core.primAt self pos)
}
fun primtAtPut(pos value) {
return (core.primAtPut self pos value)
}
fun basicAt(pos) {
return (core.basicAt self pos)
}
fun basicAtPut(pos value) {
return (core.basicAtPut self pos value)
}
fun basicSize() {
return (core.basicSize self)
}
## TODO: ...
fun == (oprnd) { return (== self oprnd) }
fun != (oprnd) { return (!= self oprnd) }
## TODO: fun perform(name ...) {}
}
class[#uncopyable #varying #limited #final] Class: Apex (
_name
_mdic
_spec
_selfspec
_superclass
_nivars_super
_ibrand
_ivarnames
_cvarnames
) {
fun name() {
##return (core.className self)
return _class
}
fun instanceVariableNames() {
## TODO: this still returns nil as the acutal manipulation of the field has not been implemented
return _ivarnames
}
fun classVariableNames() {
## TODO: this still returns nil as the acutal manipulation of the field has not been implemented
return _cvarnames
}
}
class UndefinedObject: Apex {
fun isNil?() { return true }
fun notNil?() { return false }
}
class Object: Apex {
}
## ---------------------------------------------------------------------------------
$include "Magnitude.hak" $include "Magnitude.hak"
$include "Collection.hak" $include "Collection.hak"
$include "Semaphore.hak"
$include "Mutex.hak"
$include "Process.hak"
##$include "System.hak" ##$include "System.hak"
## --------------------------------------------------------------------------------- ## ---------------------------------------------------------------------------------
+19 -19
View File
@@ -37,9 +37,9 @@ class ChildGroup(
sigsem ## the shared semaphore; only in shared mode sigsem ## the shared semaphore; only in shared mode
) { ) {
fun[#ci] new() { fun[#ci] new() {
set sg (semgr-new) set sg (core.semgr-new)
set tmo (sem-new) set tmo (core.sem-new)
semgr-add sg tmo core.semgr-add sg tmo
set capa 8 set capa 8
set kids (core.basicNew Array 8) set kids (core.basicNew Array 8)
set nkids 0 set nkids 0
@@ -107,16 +107,16 @@ class ChildGroup(
## semaphore on the signal descriptor for the whole group, once. ## semaphore on the signal descriptor for the whole group, once.
if (not self.shared) { if (not self.shared) {
set shared true set shared true
system-catch-sig sys.SIGCHLD sys.sig-catch sys.SIGCHLD
set sigsem (sem-new) set sigsem (core.sem-new)
semgr-add self.sg self.sigsem core.semgr-add self.sg self.sigsem
sem-signal-on-input self.sigsem (system-get-sigfd) core.sem-signal-on-input self.sigsem (sys.sig-getfd)
} }
} else { } else {
## A handle of its own, so a wakeup identifies this child directly. ## A handle of its own, so a wakeup identifies this child directly.
sem := (sem-new) sem := (core.sem-new)
semgr-add self.sg sem core.semgr-add self.sg sem
sem-signal-on-input sem xh core.sem-signal-on-input sem xh
} }
kid := (core.basicNew Array 6) kid := (core.basicNew Array 6)
@@ -171,16 +171,16 @@ class ChildGroup(
if (not (nil? kid)) { return kid } if (not (nil? kid)) { return kid }
while true { while true {
sem-signal self.tmo secs 0 core.sem-signal self.tmo secs 0
w := (semgr-wait self.sg) w := (core.semgr-wait self.sg)
sem-unsignal self.tmo core.sem-unsignal self.tmo
if (eqv? w self.tmo) { return nil } if (eqv? w self.tmo) { return nil }
if self.shared { if self.shared {
## the signal descriptor spoke: take the byte, then look at ## the signal descriptor spoke: take the byte, then look at
## everyone, since one SIGCHLD may stand for several exits ## everyone, since one SIGCHLD may stand for several exits
system-get-sig sys.sig-get
kid := (self:finished) kid := (self:finished)
if (not (nil? kid)) { return kid } if (not (nil? kid)) { return kid }
## otherwise it was a SIGCHLD for a child of the host ## otherwise it was a SIGCHLD for a child of the host
@@ -188,7 +188,7 @@ class ChildGroup(
} else { } else {
kid := (self:kid-of-sem w) kid := (self:kid-of-sem w)
if (not (nil? kid)) { if (not (nil? kid)) {
sem-unsignal w core.sem-unsignal w
return kid return kid
} }
} }
@@ -210,8 +210,8 @@ class ChildGroup(
| sem | | sem |
sem := (core.basicAt kid 5) sem := (core.basicAt kid 5)
if (not (nil? sem)) { if (not (nil? sem)) {
sem-unsignal sem core.sem-unsignal sem
semgr-remove self.sg sem core.semgr-remove self.sg sem
} }
self:forget kid self:forget kid
sys.pclose (core.basicAt kid 0) sys.pclose (core.basicAt kid 0)
@@ -227,8 +227,8 @@ class ChildGroup(
i := (+ i 1) i := (+ i 1)
} }
if self.shared { if self.shared {
sem-unsignal self.sigsem core.sem-unsignal self.sigsem
system-uncatch-sig sys.SIGCHLD sys.sig-uncatch sys.SIGCHLD
set shared false set shared false
} }
} }
+7 -1
View File
@@ -5,7 +5,8 @@ AM_CPPFLAGS = \
-I$(abs_builddir)/../lib \ -I$(abs_builddir)/../lib \
-I$(abs_srcdir) \ -I$(abs_srcdir) \
-I$(abs_srcdir)/../lib \ -I$(abs_srcdir)/../lib \
-I$(includedir) -I$(includedir) \
-DHAK_TEST_MODLIBDIRS='"@abs_top_builddir@/mod:@abs_top_builddir@/mod/.libs"'
LDADD = ../lib/libhak.la LDADD = ../lib/libhak.la
check_SCRIPTS = \ check_SCRIPTS = \
@@ -13,12 +14,17 @@ check_SCRIPTS = \
cons-01.hak \ cons-01.hak \
dic-01.hak \ dic-01.hak \
feed-01.hak \ feed-01.hak \
fork-01.hak \
fork-02.hak \
fun-01.hak \ fun-01.hak \
hnd-01.hak \ hnd-01.hak \
hnd-02.hak \ hnd-02.hak \
hnd-03.hak \ hnd-03.hak \
insta-01.hak \ insta-01.hak \
insta-02.hak \ insta-02.hak \
mutex-01.hak \
mutex-02.hak \
mutex-03.hak \
mux-01.hak \ mux-01.hak \
mux-02.hak \ mux-02.hak \
mux-03.hak \ mux-03.hak \
+7 -1
View File
@@ -550,7 +550,8 @@ AM_CPPFLAGS = \
-I$(abs_builddir)/../lib \ -I$(abs_builddir)/../lib \
-I$(abs_srcdir) \ -I$(abs_srcdir) \
-I$(abs_srcdir)/../lib \ -I$(abs_srcdir)/../lib \
-I$(includedir) -I$(includedir) \
-DHAK_TEST_MODLIBDIRS='"@abs_top_builddir@/mod:@abs_top_builddir@/mod/.libs"'
LDADD = ../lib/libhak.la LDADD = ../lib/libhak.la
check_SCRIPTS = \ check_SCRIPTS = \
@@ -558,12 +559,17 @@ check_SCRIPTS = \
cons-01.hak \ cons-01.hak \
dic-01.hak \ dic-01.hak \
feed-01.hak \ feed-01.hak \
fork-01.hak \
fork-02.hak \
fun-01.hak \ fun-01.hak \
hnd-01.hak \ hnd-01.hak \
hnd-02.hak \ hnd-02.hak \
hnd-03.hak \ hnd-03.hak \
insta-01.hak \ insta-01.hak \
insta-02.hak \ insta-02.hak \
mutex-01.hak \
mutex-02.hak \
mutex-03.hak \
mux-01.hak \ mux-01.hak \
mux-02.hak \ mux-02.hak \
mux-03.hak \ mux-03.hak \
+73
View File
@@ -0,0 +1,73 @@
## fork must build the new process's initial context in the NEW process.
##
## A context normally lives on the frame stack of the process that owns it.
## fork has to create one before the new process runs, and it used to carve it
## out of the CALLER's frame stack instead of the callee's. Nothing goes wrong
## while the caller is alive, so this is only observable once the caller has
## terminated and its process object has been collected: the child is then left
## with initial_context/current_context pointing into freed memory.
##
## Two things below are what make that observable, and neither is incidental:
##
## - the main process forks and then simply ENDS. It does not wait for the
## workers. HAK_TRAIT_AWAIT_PROCS keeps the vm running the children after
## the main process is gone, so the creator really is dead and collected
## while its children are still running.
##
## - each worker builds a block literal INSIDE itself and runs it. MAKE_BLOCK
## reifies the home context, which is the dereference that reads the freed
## stack context. Without a block literal the dangling pointer is merely
## held, not followed.
##
## So the test is the run itself: reaching the OK lines means the children
## outlived their creator and still found their own contexts. Against the old
## behaviour this segfaults instead, and run.sh reports the non-zero exit.
##
## [NOTE] keep this file free of anything that is not part of the above. Extra
## phases beforehand change the heap enough that the freed memory is no longer
## recycled under the child, and the crash stops reproducing - which is exactly
## why this does not live at the end of t/mutex-02.hak. When HAK_ENABLE_STACK_
## CONTEXT is undefined there are no stack contexts and no bug to trip over;
## the file still runs clean, it just is not testing anything.
$include "../src/kernel.hak"
fun chk(ok msg) {
if ok { printf "OK: %s\n" msg } \
else { printf "ERROR: %s\n" msg }
}
WORKERS := 5
SPINS := 100
mux := (Mutex:new)
fun orphan() {
| body |
## built here, in the forked process, so MAKE_BLOCK runs against the
## context fork created for this process
body := (fun() {
| i |
i := 0
while (< i SPINS) {
i := (+ i 1)
core.yield ## give the other workers a turn while holding it
}
})
mux:critical body
chk true "a forked process still runs after its creator is gone"
}
fun spawn() {
| i |
i := 0
while (< i WORKERS) {
core.fork orphan
i := (+ i 1)
}
}
## no wait, on purpose - see the header
spawn
+74
View File
@@ -0,0 +1,74 @@
## fork must not leak a frame in the CALLER's frame stack.
##
## A stack context is carved out of a process's frame stack by alloc_frame_slots
## bumping that process's fsp, and it is popped again by release_stack_context
## when the owning process returns through it. fork has to build a context for
## the process it is creating, and it used to allocate that context out of the
## CALLER's frame stack. The caller never returns through it, so nothing ever
## popped it: every fork permanently consumed a frame of the forking process.
##
## That is the same one-line defect t/fork-01.hak covers, but it shows up as a
## completely different symptom, so it is worth pinning separately. fork-01
## catches the dangling context (a segfault once the parent is collected); this
## one catches the slow exhaustion, which is what a long-lived process that
## forks in a loop - a server accepting connections, say - would actually hit.
## Neither symptom implies the other on inspection.
##
## Sizing: one leaked context is HAK_STACK_CONTEXT_NAMED_SLOTS (15) slots plus
## the block's temporaries, and the frame stack is HAK_DFL_PROCSTK_SIZE slots
## (8192 by default, or the HAK_MIN_FSTK_SIZE floor of 1024 under HAK_SMALL_
## MEMORY_FOOTPRINT). So the old behaviour ran out after roughly 546 forks on a
## default build and far sooner on a small one. 600 clears both. The count only
## has to sit above the threshold and never needs retuning, because a correct
## fork does not grow the caller's frame stack at all - measured flat at 5000.
##
## [NOTE] the loop is inside a function on purpose. The leak is charged to the
## process running it, so that process has to stay alive across all 600 forks
## for the frames to pile up.
$include "../src/kernel.hak"
fun chk(ok msg) {
if ok { printf "OK: %s\n" msg } \
else { printf "ERROR: %s\n" msg }
}
FORKS := 600
forked := 0
failed := 0
ran := 0
done := (Semaphore:new)
fun noop() {
ran := (+ ran 1)
done:signal
}
## catch rather than let the overflow abort the script, so a regression is
## reported as a failed assertion instead of an unhandled exception
fun spawner() {
| i |
i := 0
while (< i FORKS) {
try { core.fork noop ; forked := (+ forked 1) } catch (e) { failed := (+ failed 1) }
i := (+ i 1)
}
}
fun waitall(n) {
| i |
i := 0
while (< i n) {
done:wait
i := (+ i 1)
}
}
spawner
chk (= failed 0) "600 forks from one function all succeed"
chk (= forked FORKS) "every fork answered a process"
waitall forked
chk (= ran FORKS) "all 600 forked processes actually ran"
+17 -17
View File
@@ -7,21 +7,21 @@ fun chk(ok msg) {
else { printf "ERROR: %s\n" msg } else { printf "ERROR: %s\n" msg }
} }
iosem := (sem-new) iosem := (core.sem-new)
tmo := (sem-new) tmo := (core.sem-new)
sg := (semgr-new) sg := (core.semgr-new)
semgr-add sg iosem core.semgr-add sg iosem
semgr-add sg tmo core.semgr-add sg tmo
fin := (sem-new) fin := (core.sem-new)
## returns 1 when the handle became readable, 0 when the timeout won ## returns 1 when the handle became readable, 0 when the timeout won
fun waitin(h secs) { fun waitin(h secs) {
| s | | s |
sem-signal tmo secs 0 core.sem-signal tmo secs 0
sem-signal-on-input iosem h core.sem-signal-on-input iosem h
s := (semgr-wait sg) s := (core.semgr-wait sg)
sem-unsignal iosem core.sem-unsignal iosem
sem-unsignal tmo core.sem-unsignal tmo
if (eqv? s tmo) { return 0 } \ if (eqv? s tmo) { return 0 } \
else { return 1 } else { return 1 }
} }
@@ -46,12 +46,12 @@ fun reader() {
n := (sys.read r buf) n := (sys.read r buf)
if (>= n 0) { if (>= n 0) {
got := n got := n
sem-signal fin core.sem-signal fin
return 0 return 0
} }
if (= (waitin r 5) 0) { if (= (waitin r 5) 0) {
got := -1 got := -1
sem-signal fin core.sem-signal fin
return 0 return 0
} }
} }
@@ -63,7 +63,7 @@ fun writer() {
## so these ticks only happen if the VM is still scheduling ## so these ticks only happen if the VM is still scheduling
while (< ticks 4) { while (< ticks 4) {
ticks := (+ ticks 1) ticks := (+ ticks 1)
yield core.yield
} }
wb := (core.basicNew ByteArray 2) wb := (core.basicNew ByteArray 2)
core.basicAtPut wb 0 120 core.basicAtPut wb 0 120
@@ -71,9 +71,9 @@ fun writer() {
sys.write w wb sys.write w wb
} }
fork reader core.fork reader
fork writer core.fork writer
sem-wait fin core.sem-wait fin
chk (= ticks 4) "other coprocesses ran while the reader was blocked" chk (= ticks 4) "other coprocesses ran while the reader was blocked"
chk (= got 2) "the reader woke and read the data" chk (= got 2) "the reader woke and read the data"
+6 -6
View File
@@ -2,13 +2,13 @@
## stops hak code naming a descriptor it never opened - including hak's own ## stops hak code naming a descriptor it never opened - including hak's own
## multiplexer, signal and io-thread descriptors, and anything the host ## multiplexer, signal and io-thread descriptors, and anything the host
## application that embeds hak holds open. ## application that embeds hak holds open.
s := (sem-new) s := (core.sem-new)
sem-signal-on-input s 0 ##ERROR: system handle 0 core.sem-signal-on-input s 0 ##ERROR: system handle 0
--- ---
s := (sem-new) s := (core.sem-new)
sem-signal-on-input s 4 ##ERROR: system handle 4 core.sem-signal-on-input s 4 ##ERROR: system handle 4
--- ---
@@ -24,8 +24,8 @@ sys.read r (core.basicNew ByteArray 4) ##ERROR: system handle 0
## a regular file is never accepted by the multiplexer: epoll refuses one ## a regular file is never accepted by the multiplexer: epoll refuses one
## outright, and poll() would report it permanently ready ## outright, and poll() would report it permanently ready
f := (sys.open "/etc/passwd" "r") f := (sys.open "/etc/passwd" "r")
s := (sem-new) s := (core.sem-new)
sem-signal-on-input s f ##ERROR: not of an acceptable kind core.sem-signal-on-input s f ##ERROR: not of an acceptable kind
--- ---
+1 -1
View File
@@ -56,7 +56,7 @@ a := (b:get-a)
if (a != 4) {printf "ERROR: a must be 4\n" } \ if (a != 4) {printf "ERROR: a must be 4\n" } \
else { printf "OK %d\n" a } else { printf "OK %d\n" a }
c := (object-new A) c := (core.object-new A)
a := (c:get-a) a := (c:get-a)
if (a != nil) {printf "ERROR: a must be nil\n" } \ if (a != nil) {printf "ERROR: a must be nil\n" } \
else { printf "OK %O\n" a } else { printf "OK %O\n" a }
+95
View File
@@ -0,0 +1,95 @@
## a semaphore used as a mutex must give mutual exclusion across coprocesses.
##
## Semaphore:forMutex is (core.sem-new 1) - a counting semaphore that starts at
## one, so the first waiter takes it and every other one blocks until the
## holder signals. What makes this worth a test is that the holder gives up the
## CPU inside the critical section: core.yield lets the other processes run
## while the lock is held, which is exactly the window a broken mutex would
## leak through.
##
## Both phases run the same worker. The only difference is the semaphore's
## initial count, so a failure cannot be blamed on the two paths differing:
##
## count 4 -> four processes may hold it at once, so the overlap counter
## must actually see them overlapping. this is the control: if it
## reported 1, the workers would not be interleaving at all and
## the mutex phase below would pass for the wrong reason.
## count 1 -> a mutex. the overlap counter must never exceed one.
##
## [NOTE] the spin counts are deliberately small - enough interleaving to
## expose an overlap, without making the test slow. What matters is that the
## holder yields at all, not how often.
$include "../src/kernel.hak"
fun chk(ok msg) {
if ok { printf "OK: %s\n" msg } \
else { printf "ERROR: %s\n" msg }
}
WORKERS := 4
SPINS := 20
inside := 0 ## processes inside the critical section right now
maxin := 0 ## high-water mark of the above
rounds := 0 ## completed critical sections
done := (Semaphore:new)
fun worker(lock n) {
| i |
lock:wait ## lock
inside := (+ inside 1)
if (> inside maxin) { maxin := inside }
## hold the lock while yielding, so any other process that can enter will
i := 0
while (< i n) {
i := (+ i 1)
core.yield
}
inside := (- inside 1)
rounds := (+ rounds 1)
lock:signal ## unlock
done:signal
}
fun waitall(n) {
| i |
i := 0
while (< i n) {
done:wait
i := (+ i 1)
}
}
fun spawn(lock) {
| i |
i := 0
while (< i WORKERS) {
core.fork worker lock SPINS
i := (+ i 1)
}
waitall WORKERS
}
## --- control: a count of WORKERS lets everyone in at once ---
inside := 0
maxin := 0
rounds := 0
spawn (core.sem-new WORKERS)
chk (= rounds WORKERS) "every process finishes when the semaphore admits them all"
chk (= inside 0) "the occupancy counter is balanced afterwards"
chk (> maxin 1) "the processes really do interleave, so an overlap is detectable"
## --- the mutex proper ---
inside := 0
maxin := 0
rounds := 0
spawn (Semaphore:forMutex)
chk (= rounds WORKERS) "every process finishes through the mutex too"
chk (= inside 0) "the occupancy counter is balanced afterwards"
chk (= maxin 1) "only one process is ever inside the critical section"
+117
View File
@@ -0,0 +1,117 @@
## the Mutex class.
##
## t/mutex-01.hak covers mutual exclusion over a raw counting semaphore, with
## the lock taken and released by hand. This one goes through Mutex:critical,
## which adds:
##
## - the critical section is a block literal built INSIDE a forked process,
## so each worker runs MAKE_BLOCK against its own context rather than
## sharing one made by the parent.
##
## - a throw out of the critical section must still release the lock, since
## Mutex:critical catches, unlocks, and rethrows.
##
## Every phase here waits for its workers, so the parent outlives them all.
## That deliberately keeps this file away from the fork stack-context lifetime
## question, which needs the parent to die first and is tested on its own in
## t/fork-01.hak.
##
## [NOTE] reentrancy (the same process calling critical again while holding it)
## is deliberately not exercised here - see the comment at the bottom.
$include "../src/kernel.hak"
fun chk(ok msg) {
if ok { printf "OK: %s\n" msg } \
else { printf "ERROR: %s\n" msg }
}
WORKERS := 5
SPINS := 20
inside := 0 ## processes inside the critical section right now
maxin := 0 ## high-water mark of the above
rounds := 0 ## completed critical sections
done := (Semaphore:new)
## the body is built inside the forked process, so every worker runs MAKE_BLOCK
## against its own context - the path that used to reference the parent's.
fun worker(m locked) {
| body |
body := (fun() {
| i |
inside := (+ inside 1)
if (> inside maxin) { maxin := inside }
i := 0
while (< i SPINS) {
i := (+ i 1)
core.yield
}
inside := (- inside 1)
rounds := (+ rounds 1)
})
if locked { m:critical body } else { body }
done:signal
}
fun waitall(n) {
| i |
i := 0
while (< i n) {
done:wait
i := (+ i 1)
}
}
fun spawn(m locked) {
| i |
i := 0
while (< i WORKERS) {
core.fork worker m locked
i := (+ i 1)
}
waitall WORKERS
}
mux := (Mutex:new)
## --- control: same workers, same block, no locking ---
inside := 0
maxin := 0
rounds := 0
spawn mux false
chk (= rounds WORKERS) "every unlocked process finishes"
chk (= inside 0) "the occupancy counter is balanced afterwards"
chk (> maxin 1) "the processes really do interleave, so an overlap is detectable"
## --- the same thing through Mutex:critical ---
inside := 0
maxin := 0
rounds := 0
spawn mux true
chk (= rounds WORKERS) "every process finishes through Mutex:critical too"
chk (= inside 0) "the occupancy counter is balanced afterwards"
chk (= maxin 1) "only one process is ever inside the critical section"
## --- a throw out of the critical section unlocks and propagates ---
caught := 0
try { mux:critical (fun() { throw 5 }) } catch (e) { caught := e }
chk (= caught 5) "an exception raised inside a critical section propagates"
reused := 0
mux:critical (fun() { reused := 1 })
chk (= reused 1) "the mutex is still usable after an exception unwound it"
## --- each process has its own identity ---
main_id := ((core.active-process):id)
other_id := 0
fun idjob() { other_id := ((core.active-process):id) ; done:signal }
core.fork idjob
waitall 1
chk (>= main_id 0) "the main process has an id"
chk (> other_id main_id) "a forked process gets a later id"
chk (nqv? main_id other_id) "a forked process has an id of its own"
+79
View File
@@ -0,0 +1,79 @@
## Mutex:tryCritical - the non-blocking form of critical.
##
## t/mutex-01.hak covers a raw semaphore as a mutex and t/mutex-02.hak covers
## Mutex:critical. This one covers the try form, whose whole contract is what
## it does when the mutex is NOT available: answer false, leave the body
## unrun, and - the part that is easy to get wrong - come back immediately
## rather than waiting.
##
## That last point is why core.sem-trywait had to exist. Testing _owner and
## then calling _sem:wait would be a check-then-act, and process switching is
## tick-driven (switch_process_if_needed -> switch_to_next_runnable_process),
## so two processes could both find the mutex free and the second would block
## inside a call that promised not to. core.sem-trywait claims the semaphore
## or refuses in one primitive, with no suspension point in between.
##
## [NOTE] the non-blocking assertion is made by watching the holder rather
## than by timing: main runs tryCritical while a forked holder is still
## spinning inside its own critical section, so if tryCritical had waited for
## the mutex the holder would necessarily have finished first. A blocking
## implementation fails three of the assertions below.
$include "../src/kernel.hak"
fun chk(ok msg) { if ok { printf "OK: %s\n" msg } else { printf "ERROR: %s\n" msg } }
## --- uncontended: it runs and answers true ---
m := (Mutex:new)
ran := 0
chk (m:tryCritical (fun() { ran := 1 })) "tryCritical answers true when the mutex is free"
chk (= ran 1) "and it actually runs the body"
## --- the mutex is released afterwards ---
chk (m:tryCritical (fun() { })) "the mutex is free again after tryCritical"
## --- reentrant: the owner may re-enter ---
nested := 0
inner := 0
m:critical (fun() { nested := (m:tryCritical (fun() { inner := 1 })) })
chk nested "the holder can re-enter through tryCritical"
chk (= inner 1) "and the nested body runs"
## --- contended: answers false WITHOUT running the body and WITHOUT blocking ---
held := (Mutex:new)
done := (Semaphore:new)
entered := (Semaphore:new)
tried := nil
body_ran := 0
holder_done := 0
fun holder() {
held:critical (fun() {
| i |
entered:signal ## tell main we are inside
i := 0
while (< i 200) { i := (+ i 1) ; core.yield }
})
holder_done := 1 ## only set once it has left
done:signal
}
core.fork holder
entered:wait ## now the mutex is definitely held
tried := (held:tryCritical (fun() { body_ran := 1 }))
chk (nqv? tried true) "tryCritical answers false while another process holds it"
chk (= body_ran 0) "and it does not run the body"
## the holder is still spinning inside its critical section. had tryCritical
## waited for the mutex, the holder would necessarily have finished first.
chk (= holder_done 0) "and it returned while the holder was still inside, so it did not block"
done:wait
chk (held:tryCritical (fun() { })) "the mutex is acquirable once the holder leaves"
## --- a throw from the body still unlocks ---
mx := (Mutex:new)
caught := 0
try { mx:tryCritical (fun() { throw 7 }) } catch (e) { caught := e }
chk (= caught 7) "an exception from a tryCritical body propagates"
chk (mx:tryCritical (fun() { })) "and the mutex is released when it throws"
+10 -10
View File
@@ -16,20 +16,20 @@ fun chk(ok msg) {
else { printf "ERROR: %s\n" msg } else { printf "ERROR: %s\n" msg }
} }
iosem := (sem-new) iosem := (core.sem-new)
tmo := (sem-new) tmo := (core.sem-new)
sg := (semgr-new) sg := (core.semgr-new)
semgr-add sg iosem core.semgr-add sg iosem
semgr-add sg tmo core.semgr-add sg tmo
## 1 when the handle became readable, 0 when the timer won instead ## 1 when the handle became readable, 0 when the timer won instead
fun waitin(h secs) { fun waitin(h secs) {
| s | | s |
sem-signal tmo secs 0 core.sem-signal tmo secs 0
sem-signal-on-input iosem h core.sem-signal-on-input iosem h
s := (semgr-wait sg) s := (core.semgr-wait sg)
sem-unsignal iosem core.sem-unsignal iosem
sem-unsignal tmo core.sem-unsignal tmo
if (eqv? s tmo) { return 0 } else { return 1 } if (eqv? s tmo) { return 0 } else { return 1 }
} }
+18 -18
View File
@@ -15,15 +15,15 @@ fun chk(ok msg) {
else { printf "ERROR: %s\n" msg } else { printf "ERROR: %s\n" msg }
} }
sg := (semgr-new) sg := (core.semgr-new)
sa := (sem-new) sa := (core.sem-new)
sb := (sem-new) sb := (core.sem-new)
sc := (sem-new) sc := (core.sem-new)
tmo := (sem-new) tmo := (core.sem-new)
semgr-add sg sa core.semgr-add sg sa
semgr-add sg sb core.semgr-add sg sb
semgr-add sg sc core.semgr-add sg sc
semgr-add sg tmo core.semgr-add sg tmo
## staggered so the completion order is a, then b, then c ## staggered so the completion order is a, then b, then c
pa := (sys.popen "sleep 0.2; echo aaa" "r") pa := (sys.popen "sleep 0.2; echo aaa" "r")
@@ -35,14 +35,14 @@ hb := (core.basicAt pb 2)
hc := (core.basicAt pc 2) hc := (core.basicAt pc 2)
## all three bound at the same time - three live tuple entries ## all three bound at the same time - three live tuple entries
sem-signal-on-input sa ha core.sem-signal-on-input sa ha
sem-signal-on-input sb hb core.sem-signal-on-input sb hb
sem-signal-on-input sc hc core.sem-signal-on-input sc hc
sem-signal tmo 9 0 core.sem-signal tmo 9 0
fun expect(want h name) { fun expect(want h name) {
| s buf got | | s buf got |
s := (semgr-wait sg) s := (core.semgr-wait sg)
chk (eqv? s want) name chk (eqv? s want) name
buf := (core.basicNew ByteArray 8) buf := (core.basicNew ByteArray 8)
got := (sys.read h buf) got := (sys.read h buf)
@@ -52,15 +52,15 @@ fun expect(want h name) {
## unbinding sa frees the first slot, so the last entry migrates into it and ## unbinding sa frees the first slot, so the last entry migrates into it and
## sb/sc must still resolve to their own handles afterwards ## sb/sc must still resolve to their own handles afterwards
expect sa ha "the first child woke its own semaphore" expect sa ha "the first child woke its own semaphore"
sem-unsignal sa core.sem-unsignal sa
expect sb hb "the second child woke its own semaphore after compaction" expect sb hb "the second child woke its own semaphore after compaction"
sem-unsignal sb core.sem-unsignal sb
expect sc hc "the third child woke its own semaphore after compaction" expect sc hc "the third child woke its own semaphore after compaction"
sem-unsignal sc core.sem-unsignal sc
sem-unsignal tmo core.sem-unsignal tmo
sys.pclose (core.basicAt pa 0) sys.pclose (core.basicAt pa 0)
sys.pclose (core.basicAt pb 0) sys.pclose (core.basicAt pb 0)
sys.pclose (core.basicAt pc 0) sys.pclose (core.basicAt pc 0)
+22 -22
View File
@@ -16,52 +16,52 @@ fun chk(ok msg) {
else { printf "ERROR: %s\n" msg } else { printf "ERROR: %s\n" msg }
} }
sg := (semgr-new) sg := (core.semgr-new)
isem := (sem-new) isem := (core.sem-new)
osem := (sem-new) osem := (core.sem-new)
tmo := (sem-new) tmo := (core.sem-new)
semgr-add sg isem core.semgr-add sg isem
semgr-add sg osem core.semgr-add sg osem
semgr-add sg tmo core.semgr-add sg tmo
p := (sys.pipe) p := (sys.pipe)
r := (core.basicAt p 0) r := (core.basicAt p 0)
w := (core.basicAt p 1) w := (core.basicAt p 1)
## one descriptor, two directions - the tuple now carries both ## one descriptor, two directions - the tuple now carries both
sem-signal-on-input isem w core.sem-signal-on-input isem w
sem-signal-on-output osem w core.sem-signal-on-output osem w
## drop only the input direction. the output registration must survive, and so ## drop only the input direction. the output registration must survive, and so
## must any event already reported for it ## must any event already reported for it
sem-unsignal isem core.sem-unsignal isem
sem-signal tmo 5 0 core.sem-signal tmo 5 0
s := (semgr-wait sg) s := (core.semgr-wait sg)
chk (eqv? s osem) "the surviving direction still reports after a partial unbind" chk (eqv? s osem) "the surviving direction still reports after a partial unbind"
sem-unsignal tmo core.sem-unsignal tmo
## put the input direction back while the output one is still registered. this ## put the input direction back while the output one is still registered. this
## is the add branch of the modify path - the mirror of the drop above - and it ## is the add branch of the modify path - the mirror of the drop above - and it
## has to leave the output registration alone. ## has to leave the output registration alone.
sem-signal-on-input isem w core.sem-signal-on-input isem w
## now drop the output direction instead, keeping input. a write end is never ## now drop the output direction instead, keeping input. a write end is never
## readable, so with input alone nothing can report and the timer must win. if ## readable, so with input alone nothing can report and the timer must win. if
## the modify path had left the output registration behind, its writability ## the modify path had left the output registration behind, its writability
## would be reported here and the timer would lose. ## would be reported here and the timer would lose.
sem-unsignal osem core.sem-unsignal osem
sem-signal tmo 0 300000000 core.sem-signal tmo 0 300000000
s := (semgr-wait sg) s := (core.semgr-wait sg)
chk (eqv? s tmo) "the dropped direction stops reporting after a partial unbind" chk (eqv? s tmo) "the dropped direction stops reporting after a partial unbind"
sem-unsignal tmo core.sem-unsignal tmo
## and the full unbind from that state really removes the registration ## and the full unbind from that state really removes the registration
sem-unsignal isem core.sem-unsignal isem
sem-signal tmo 0 300000000 core.sem-signal tmo 0 300000000
s := (semgr-wait sg) s := (core.semgr-wait sg)
chk (eqv? s tmo) "nothing reports once both directions are unbound" chk (eqv? s tmo) "nothing reports once both directions are unbound"
sem-unsignal tmo core.sem-unsignal tmo
sys.close r sys.close r
sys.close w sys.close w
+14 -14
View File
@@ -8,11 +8,11 @@ fun loop1() {
while (< k 100) { while (< k 100) {
printf "loop1 => %d\n" k printf "loop1 => %d\n" k
k := (+ k 2) k := (+ k 2)
yield core.yield
} }
z1 := k z1 := k
sem-signal s1 core.sem-signal s1
} }
fun loop2() { fun loop2() {
@@ -22,26 +22,26 @@ fun loop2() {
while (< k 100) { while (< k 100) {
printf "loop2 => %d\n" k printf "loop2 => %d\n" k
k := (+ k 2) k := (+ k 2)
yield core.yield
} }
z2 := k z2 := k
sem-signal s2 core.sem-signal s2
} }
s1 := (sem-new) s1 := (core.sem-new)
s2 := (sem-new) s2 := (core.sem-new)
p1 := (fork loop1) p1 := (core.fork loop1)
p2 := (fork loop2) p2 := (core.fork loop2)
##suspend p1 ##core.suspend p1
##suspend p2 ##core.suspend p2
##resume p1 ##core.resume p1
##resume p2 ##core.resume p2
sem-wait s1 core.sem-wait s1
sem-wait s2 core.sem-wait s2
if (== z1 101) { printf "OK: z1 is %d\n" z1 } \ if (== z1 101) { printf "OK: z1 is %d\n" z1 } \
else { printf "ERROR: z1 is not 101 - %d\n" z1 } else { printf "ERROR: z1 is not 101 - %d\n" z1 }
+2 -2
View File
@@ -22,10 +22,10 @@ ticks := 0
fun ticker() { fun ticker() {
while (< ticks 5) { while (< ticks 5) {
ticks := (+ ticks 1) ticks := (+ ticks 1)
yield core.yield
} }
} }
fork ticker core.fork ticker
order := (core.basicNew Array 3) order := (core.basicNew Array 3)
n := 0 n := 0
+24 -24
View File
@@ -27,23 +27,23 @@ sys.close (core.basicAt q 0)
sys.close (core.basicAt q 1) sys.close (core.basicAt q 1)
## --- catch and uncatch are idempotent --- ## --- catch and uncatch are idempotent ---
chk (= (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "system-catch-sig returns the signal number" chk (= (sys.sig-catch sys.SIGUSR1) sys.SIGUSR1) "sys.sig-catch returns the signal number"
chk (= (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "catching an already caught signal is fine" chk (= (sys.sig-catch sys.SIGUSR1) sys.SIGUSR1) "catching an already caught signal is fine"
chk (= (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "system-uncatch-sig returns the signal number" chk (= (sys.sig-uncatch sys.SIGUSR1) sys.SIGUSR1) "sys.sig-uncatch returns the signal number"
chk (= (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "uncatching an uncaught signal is fine" chk (= (sys.sig-uncatch sys.SIGUSR1) sys.SIGUSR1) "uncatching an uncaught signal is fine"
## --- a real signal reaches hak code, without stalling the coprocesses --- ## --- a real signal reaches hak code, without stalling the coprocesses ---
## SIGCHLD is used because a child exiting is something this test can arrange ## SIGCHLD is used because a child exiting is something this test can arrange
## on its own, with no outside help. ## on its own, with no outside help.
system-catch-sig sys.SIGCHLD sys.sig-catch sys.SIGCHLD
h := (system-get-sigfd) h := (sys.sig-getfd)
s := (sem-new) s := (core.sem-new)
tmo := (sem-new) tmo := (core.sem-new)
sg := (semgr-new) sg := (core.semgr-new)
semgr-add sg s core.semgr-add sg s
semgr-add sg tmo core.semgr-add sg tmo
fin := (sem-new) fin := (core.sem-new)
ticks := 0 ticks := 0
signo := -1 signo := -1
@@ -52,14 +52,14 @@ proc := (core.basicAt pr 0)
fun waiter() { fun waiter() {
| w | | w |
sem-signal tmo 20 0 core.sem-signal tmo 20 0
sem-signal-on-input s h core.sem-signal-on-input s h
w := (semgr-wait sg) w := (core.semgr-wait sg)
sem-unsignal s core.sem-unsignal s
sem-unsignal tmo core.sem-unsignal tmo
if (eqv? w tmo) { signo := -2 } \ if (eqv? w tmo) { signo := -2 } \
else { signo := (system-get-sig) } else { signo := (sys.sig-get) }
sem-signal fin core.sem-signal fin
return 0 return 0
} }
@@ -67,16 +67,16 @@ fun ticker() {
## the waiter is parked on the signal descriptor by now ## the waiter is parked on the signal descriptor by now
while (< ticks 4) { while (< ticks 4) {
ticks := (+ ticks 1) ticks := (+ ticks 1)
yield core.yield
} }
} }
fork waiter core.fork waiter
fork ticker core.fork ticker
sem-wait fin core.sem-wait fin
chk (= ticks 4) "coprocesses ran while a coprocess waited on a signal" chk (= ticks 4) "coprocesses ran while a coprocess waited on a signal"
chk (= signo sys.SIGCHLD) "the signal number came through the signal descriptor" chk (= signo sys.SIGCHLD) "the signal number came through the signal descriptor"
chk (= (sys.pwait proc) 4) "and the child's exit status is readable" chk (= (sys.pwait proc) 4) "and the child's exit status is readable"
sys.pclose proc sys.pclose proc
system-uncatch-sig sys.SIGCHLD sys.sig-uncatch sys.SIGCHLD
+3 -3
View File
@@ -54,8 +54,8 @@ chk (== sys.SIGTERM 15) "SIGTERM is 15"
## and the constants behave: a routable one can be caught, an unroutable one ## and the constants behave: a routable one can be caught, an unroutable one
## cannot, whatever the numbers happen to be here ## cannot, whatever the numbers happen to be here
chk (== (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is catchable" chk (== (sys.sig-catch sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is catchable"
chk (== (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is uncatchable again" chk (== (sys.sig-uncatch sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is uncatchable again"
raised := false raised := false
try { system-catch-sig sys.SIGKILL } catch (e) { raised := true } try { sys.sig-catch sys.SIGKILL } catch (e) { raised := true }
chk raised "SIGKILL is refused" chk raised "SIGKILL is refused"
+10 -10
View File
@@ -1,41 +1,41 @@
## signals that cannot be caught ## signals that cannot be caught
system-catch-sig sys.SIGKILL ##ERROR: not routable sys.sig-catch sys.SIGKILL ##ERROR: not routable
--- ---
system-catch-sig sys.SIGSTOP ##ERROR: not routable sys.sig-catch sys.SIGSTOP ##ERROR: not routable
--- ---
## signals that indicate a crash: turning one into a byte on a pipe and ## signals that indicate a crash: turning one into a byte on a pipe and
## carrying on would hide the fault rather than report it ## carrying on would hide the fault rather than report it
system-catch-sig sys.SIGSEGV ##ERROR: not routable sys.sig-catch sys.SIGSEGV ##ERROR: not routable
--- ---
system-catch-sig sys.SIGBUS ##ERROR: not routable sys.sig-catch sys.SIGBUS ##ERROR: not routable
--- ---
system-catch-sig sys.SIGFPE ##ERROR: not routable sys.sig-catch sys.SIGFPE ##ERROR: not routable
--- ---
system-catch-sig sys.SIGILL ##ERROR: not routable sys.sig-catch sys.SIGILL ##ERROR: not routable
--- ---
## the timer signal hak itself uses to switch processes ## the timer signal hak itself uses to switch processes
system-catch-sig sys.SIGVTALRM ##ERROR: not routable sys.sig-catch sys.SIGVTALRM ##ERROR: not routable
--- ---
system-catch-sig 0 ##ERROR: 0 not routable sys.sig-catch 0 ##ERROR: 0 not routable
--- ---
system-catch-sig 9999 ##ERROR: 9999 not routable sys.sig-catch 9999 ##ERROR: 9999 not routable
--- ---
system-catch-sig "two" ##ERROR: number not a small integer sys.sig-catch "two" ##ERROR: number not a small integer
+13 -13
View File
@@ -5,19 +5,19 @@ fun chk(ok msg) {
else { printf "ERROR: %s\n" msg } else { printf "ERROR: %s\n" msg }
} }
iosem := (sem-new) iosem := (core.sem-new)
tmo := (sem-new) tmo := (core.sem-new)
sg := (semgr-new) sg := (core.semgr-new)
semgr-add sg iosem core.semgr-add sg iosem
semgr-add sg tmo core.semgr-add sg tmo
fun waitin(h secs) { fun waitin(h secs) {
| s | | s |
sem-signal tmo secs 0 core.sem-signal tmo secs 0
sem-signal-on-input iosem h core.sem-signal-on-input iosem h
s := (semgr-wait sg) s := (core.semgr-wait sg)
sem-unsignal iosem core.sem-unsignal iosem
sem-unsignal tmo core.sem-unsignal tmo
if (eqv? s tmo) { return 0 } else { return 1 } if (eqv? s tmo) { return 0 } else { return 1 }
} }
@@ -38,9 +38,9 @@ fun reap(proc) {
while (< k 300) { while (< k 300) {
n := (sys.pwait proc) n := (sys.pwait proc)
if (not (= n 256)) { return n } if (not (= n 256)) { return n }
sem-signal tmo 0 20000000 core.sem-signal tmo 0 20000000
semgr-wait sg core.semgr-wait sg
sem-unsignal tmo core.sem-unsignal tmo
k := (+ k 1) k := (+ k 1)
} }
return 256 return 256
+16 -16
View File
@@ -9,12 +9,12 @@ fun chk(ok msg) {
else { printf "ERROR: %s\n" msg } else { printf "ERROR: %s\n" msg }
} }
iosem := (sem-new) iosem := (core.sem-new)
tmo := (sem-new) tmo := (core.sem-new)
sg := (semgr-new) sg := (core.semgr-new)
semgr-add sg iosem core.semgr-add sg iosem
semgr-add sg tmo core.semgr-add sg tmo
fin := (sem-new) fin := (core.sem-new)
p := (sys.popen "sleep 1; exit 5" "r") p := (sys.popen "sleep 1; exit 5" "r")
proc := (core.basicAt p 0) proc := (core.basicAt p 0)
@@ -30,14 +30,14 @@ else {
fun waiter() { fun waiter() {
| s | | s |
sem-signal tmo 20 0 core.sem-signal tmo 20 0
sem-signal-on-input iosem xh core.sem-signal-on-input iosem xh
s := (semgr-wait sg) s := (core.semgr-wait sg)
sem-unsignal iosem core.sem-unsignal iosem
sem-unsignal tmo core.sem-unsignal tmo
if (eqv? s tmo) { status := -1 } \ if (eqv? s tmo) { status := -1 } \
else { status := (sys.pwait proc) } else { status := (sys.pwait proc) }
sem-signal fin core.sem-signal fin
return 0 return 0
} }
@@ -46,14 +46,14 @@ else {
## happen if the VM went on scheduling instead of blocking ## happen if the VM went on scheduling instead of blocking
while (< ticks 4) { while (< ticks 4) {
ticks := (+ ticks 1) ticks := (+ ticks 1)
yield core.yield
} }
} }
chk (integer? xh) "sys.popen hands back an exit handle" chk (integer? xh) "sys.popen hands back an exit handle"
fork waiter core.fork waiter
fork ticker core.fork ticker
sem-wait fin core.sem-wait fin
chk (= ticks 4) "other coprocesses ran while the child was alive" chk (= ticks 4) "other coprocesses ran while the child was alive"
chk (= status 5) "the exit handle woke the waiter and the status was read" chk (= status 5) "the exit handle woke the waiter and the status was read"
+24 -6
View File
@@ -80,12 +80,12 @@ static void state_contract (void)
static const char SRC[] = static const char SRC[] =
"flag := 0\n" "flag := 0\n"
"s := (sem-new)\n" "s := (core.sem-new)\n"
"fun setter() { flag := 1 ; sem-signal s }\n" "fun setter() { flag := 1 ; core.sem-signal s }\n"
"p := (fork setter)\n" "p := (core.fork setter)\n"
"i := 0\n" "i := 0\n"
"while (< i 300000) { if (== flag 1) { break } ; i := (+ i 1) }\n" "while (< i 300000) { if (== flag 1) { break } ; i := (+ i 1) }\n"
"sem-wait s\n" "core.sem-wait s\n"
"r := i\n"; "r := i\n";
static hak_oow_t bc_seen = 0; static hak_oow_t bc_seen = 0;
@@ -105,6 +105,22 @@ static int on_cnode (hak_t* hak, hak_cnode_t* obj)
return hak_compile(hak, obj, 0); return hak_compile(hak, obj, 0);
} }
/* The script below reaches the process and semaphore primitives through the
* core module, which is where they are registered. A build configured with
* --enable-static-module links that module in and resolves it unaided, but one
* without it has to load the module from the build tree, and a bare
* hak_openstd() has nowhere to look. HAK_TEST_MODLIBDIRS comes from
* t/Makefile.am and names the same directories run.sh passes to the script
* tests via --modlibdirs. */
static int set_modlibdirs (hak_t* hak)
{
#if defined(HAK_TEST_MODLIBDIRS)
return hak_setoption(hak, HAK_OPT_MODLIBDIRS_BCSTR, HAK_TEST_MODLIBDIRS);
#else
return 0;
#endif
}
static void preempts_a_spinner (void) static void preempts_a_spinner (void)
{ {
hak_t* hak; hak_t* hak;
@@ -117,9 +133,11 @@ static void preempts_a_spinner (void)
OK (hak != HAK_NULL, "instantiation"); OK (hak != HAK_NULL, "instantiation");
if (!hak) return; if (!hak) return;
hak_getoption(hak, HAK_TRAIT, &trait); hak_getoption(hak, HAK_OPT_TRAIT, &trait);
trait |= HAK_TRAIT_AWAIT_PROCS | HAK_TRAIT_LANG_ENABLE_EOL; trait |= HAK_TRAIT_AWAIT_PROCS | HAK_TRAIT_LANG_ENABLE_EOL;
hak_setoption(hak, HAK_TRAIT, &trait); hak_setoption(hak, HAK_OPT_TRAIT, &trait);
OK (set_modlibdirs(hak) == 0, "module search path");
memset (&cb, 0, sizeof(cb)); memset (&cb, 0, sizeof(cb));
cb.vm_checkbc = cb_checkbc; cb.vm_checkbc = cb_checkbc;
+3 -3
View File
@@ -79,12 +79,12 @@ static int run_at_depth (int depth, int expect_overflow)
OK (hak != HAK_NULL, "instantiation"); OK (hak != HAK_NULL, "instantiation");
if (!hak) goto done; if (!hak) goto done;
hak_getoption(hak, HAK_TRAIT, &trait); hak_getoption(hak, HAK_OPT_TRAIT, &trait);
trait |= HAK_TRAIT_LANG_ENABLE_EOL; trait |= HAK_TRAIT_LANG_ENABLE_EOL;
hak_setoption(hak, HAK_TRAIT, &trait); hak_setoption(hak, HAK_OPT_TRAIT, &trait);
stksize = STK_SLOTS; stksize = STK_SLOTS;
OK (hak_setoption(hak, HAK_PROCSTK_SIZE, &stksize) == 0, "process stack size"); OK (hak_setoption(hak, HAK_OPT_PROCSTK_SIZE, &stksize) == 0, "process stack size");
OK (hak_ignite(hak, 0) == 0, "ignition"); OK (hak_ignite(hak, 0) == 0, "ignition");
OK (hak_addbuiltinprims(hak) == 0, "builtin primitives"); OK (hak_addbuiltinprims(hak) == 0, "builtin primitives");
+2 -2
View File
@@ -21,7 +21,7 @@ fun setter() { flag := 1 }
## setter is runnable from here on, but it cannot run while this process holds ## setter is runnable from here on, but it cannot run while this process holds
## the CPU - and this process never calls yield. ## the CPU - and this process never calls yield.
p := (fork setter) p := (core.fork setter)
i := 0 i := 0
while (< i 3000000) { while (< i 3000000) {
@@ -38,7 +38,7 @@ chk (== flag 1) "a process that never yields is preempted so another can run"
## process immediately: then setter would have run before the loop started and ## process immediately: then setter would have run before the loop started and
## i would be ~0, proving nothing about preemption. One tick is 20ms, which is ## i would be ~0, proving nothing about preemption. One tick is 20ms, which is
## a great many iterations. ## a great many iterations.
chk (> i 1000) "the switch came from the ticker, not from an eager fork" chk (> i 1000) "the switch came from the ticker, not from an eager core.fork"
## The preempted process must be resumed, not abandoned - reaching here at all ## The preempted process must be resumed, not abandoned - reaching here at all
## means the scheduler came back to it. ## means the scheduler came back to it.