Compare commits

..
13 Commits
38 changed files with 1223 additions and 583 deletions
+46 -44
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
} }
@@ -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;
@@ -896,6 +898,7 @@ int main (int argc, char* argv[])
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, " -I, --incdirs string specify the list of include directories\n");
fprintf(stderr, " -l, --log string specify the log file path and options\n"); fprintf(stderr, " -l, --log string specify the log file path and options\n");
fprintf(stderr, " --modlibdirs string specify directories to load modules from\n"); fprintf(stderr, " --modlibdirs string specify directories to load modules from\n");
fprintf(stderr, " -v show verbose messages\n"); fprintf(stderr, " -v show verbose messages\n");
@@ -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
+216 -15
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))
} }
+40 -1
View File
@@ -1341,7 +1341,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
@@ -5640,6 +5639,11 @@ 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, prc);
resume_process(hak, prc); resume_process(hak, prc);
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
@@ -5662,6 +5666,11 @@ 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, prc);
suspend_process(hak, prc); suspend_process(hak, prc);
return HAK_PF_SUCCESS; return HAK_PF_SUCCESS;
} }
@@ -5684,18 +5693,33 @@ 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, 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 +5739,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;
} }
if (nargs >= 1)
{
hak_oop_t tmp;
tmp = (hak_oop_semaphore_t)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); 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 */
+11
View File
@@ -2248,6 +2248,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);
@@ -2270,6 +2272,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 */
/* ========================================================================= */ /* ========================================================================= */
+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);
+49 -23
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;
@@ -1786,7 +1801,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)
+96 -71
View File
@@ -356,7 +356,7 @@
* about async-signal-safety - the spinlock is built out of atomics and is safe * about async-signal-safety - the spinlock is built out of atomics and is safe
* by that measure - but about reentrancy: a signal delivered to the thread * by that measure - but about reentrancy: a signal delivered to the thread
* that already holds the lock would spin, or block, on a lock that thread can * that already holds the lock would spin, or block, on a lock that thread can
* no longer reach the end of. post_sig_to_all_haks() therefore walk the chain without it. * no longer reach the end of. post_sig_to_all_haks() therefore walks the chain without it.
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#if defined(USE_THREAD) #if defined(USE_THREAD)
@@ -2104,6 +2104,8 @@ kqueue_syserr:
#elif defined(USE_SELECT) #elif defined(USE_SELECT)
# define MUXEVT_FD(e) ((e).fd) # define MUXEVT_FD(e) ((e).fd)
# define MUXEVT_MASK(e) ((e).events) # define MUXEVT_MASK(e) ((e).events)
#else
# error UNSUPPORTED
#endif #endif
/* Drop multiplexer events already sitting in the buffer for this descriptor. /* Drop multiplexer events already sitting in the buffer for this descriptor.
@@ -2453,20 +2455,7 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
{ {
--n; --n;
#if defined(USE_DEVPOLL) if (MUXEVT_FD(xtn->ev.buf[n]) == xtn->iothr.p[0])
if (xtn->ev.buf[n].fd == xtn->iothr.p[0])
#elif defined(USE_KQUEUE)
if (xtn->ev.buf[n].ident == xtn->iothr.p[0])
#elif defined(USE_EPOLL)
/*if (xtn->ev.buf[n].data.ptr == (void*)HAK_TYPE_MAX(hak_oow_t))*/
if (xtn->ev.buf[n].data.fd == xtn->iothr.p[0])
#elif defined(USE_POLL)
if (xtn->ev.buf[n].fd == xtn->iothr.p[0])
#elif defined(USE_SELECT)
if (xtn->ev.buf[n].fd == xtn->iothr.p[0])
#else
# error UNSUPPORTED
#endif
{ {
hak_uint8_t u8; hak_uint8_t u8;
while (read(xtn->iothr.p[0], &u8, HAK_SIZEOF(u8)) > 0) while (read(xtn->iothr.p[0], &u8, HAK_SIZEOF(u8)) > 0)
@@ -2480,21 +2469,15 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
int revents; int revents;
hak_ooi_t mask; hak_ooi_t mask;
#if defined(USE_DEVPOLL) #if defined(USE_KQUEUE)
revents = xtn->ev.buf[n].revents;
#elif defined(USE_KQUEUE)
revents = 0; revents = 0;
/* it's "if .. else if" because kqueue filter is either READ or WRITE. */ /* it's "if .. else if" because kqueue filter is either READ or WRITE. */
if (xtn->ev.buf[n].filter == EVFILT_READ) revents |= XPOLLIN; if (xtn->ev.buf[n].filter == EVFILT_READ) revents |= XPOLLIN;
else if (xtn->ev.buf[n].filter == EVFILT_WRITE) revents |= XPOLLOUT; else if (xtn->ev.buf[n].filter == EVFILT_WRITE) revents |= XPOLLOUT;
if (xtn->ev.buf[n].flags & EV_EOF) revents |= XPOLLHUP; if (xtn->ev.buf[n].flags & EV_EOF) revents |= XPOLLHUP;
if (xtn->ev.buf[n].flags & EV_ERROR) revents |= XPOLLERR; if (xtn->ev.buf[n].flags & EV_ERROR) revents |= XPOLLERR;
#elif defined(USE_EPOLL) #else
revents = xtn->ev.buf[n].events; revents = MUXEVT_MASK(xtn->ev.buf[n]);
#elif defined(USE_POLL)
revents = xtn->ev.buf[n].revents;
#elif defined(USE_SELECT)
revents = xtn->ev.buf[n].events;
#endif #endif
mask = 0; mask = 0;
@@ -2503,19 +2486,7 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
if (revents & XPOLLERR) mask |= HAK_SEMAPHORE_IO_MASK_ERROR; if (revents & XPOLLERR) mask |= HAK_SEMAPHORE_IO_MASK_ERROR;
if (revents & XPOLLHUP) mask |= HAK_SEMAPHORE_IO_MASK_HANGUP; if (revents & XPOLLHUP) mask |= HAK_SEMAPHORE_IO_MASK_HANGUP;
#if defined(USE_DEVPOLL) muxwcb(hak, MUXEVT_FD(xtn->ev.buf[n]), mask);
muxwcb(hak, xtn->ev.buf[n].fd, mask);
#elif defined(USE_KQUEUE)
muxwcb(hak, xtn->ev.buf[n].ident, mask);
#elif defined(USE_EPOLL)
muxwcb(hak, xtn->ev.buf[n].data.fd, mask);
#elif defined(USE_POLL)
muxwcb(hak, xtn->ev.buf[n].fd, mask);
#elif defined(USE_SELECT)
muxwcb(hak, xtn->ev.buf[n].fd, mask);
#else
# error UNSUPPORTED
#endif
} }
} }
while (n > 0); while (n > 0);
@@ -2864,6 +2835,7 @@ static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx)
if (g_sig_state[sig].handler != (hak_uintptr_t)SIG_IGN && if (g_sig_state[sig].handler != (hak_uintptr_t)SIG_IGN &&
g_sig_state[sig].handler != (hak_uintptr_t)SIG_DFL) g_sig_state[sig].handler != (hak_uintptr_t)SIG_DFL)
{ {
/* execute the current handler */
((sig_handler_t)g_sig_state[sig].handler)(sig); ((sig_handler_t)g_sig_state[sig].handler)(sig);
} }
@@ -2871,6 +2843,9 @@ static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx)
g_sig_state[sig].old_handler != (hak_uintptr_t)SIG_IGN && g_sig_state[sig].old_handler != (hak_uintptr_t)SIG_IGN &&
g_sig_state[sig].old_handler != (hak_uintptr_t)SIG_DFL) g_sig_state[sig].old_handler != (hak_uintptr_t)SIG_DFL)
{ {
/* execute the original remembered handler */
/* TODO: if the runtime has installed its own signal handler, proably this one must not be called.
* when the runtime registers a single handler, it may optionally request that the previous one should also be invoked? */
((void(*)(int, siginfo_t*, void*))g_sig_state[sig].old_handler)(sig, si, ctx); ((void(*)(int, siginfo_t*, void*))g_sig_state[sig].old_handler)(sig, si, ctx);
} }
} }
@@ -3137,8 +3112,10 @@ static HAK_INLINE void post_sig_to_all_haks (int signo)
{ {
xtn_t* xtn = GET_XTN(hak); xtn_t* xtn = GET_XTN(hak);
hak_uint8_t u8; hak_uint8_t u8;
/*hak_abortstd(hak);*/
u8 = signo & 0xFF; u8 = signo & 0xFF;
/* write a byte of signal number. vm_getsig() reads this when
* it's invoked by the vm */
write(xtn->sigfd.p[1], &u8, HAK_SIZEOF(u8)); write(xtn->sigfd.p[1], &u8, HAK_SIZEOF(u8));
hak = xtn->next; hak = xtn->next;
} }
@@ -3535,7 +3512,6 @@ static HAK_INLINE int start_ticker (void)
nanosleep(&ts, HAK_NULL); nanosleep(&ts, HAK_NULL);
#elif defined(HAVE_USLEEP) #elif defined(HAVE_USLEEP)
usleep(HAK_TICKER_INTERVAL_USECS * 2); usleep(HAK_TICKER_INTERVAL_USECS * 2);
#else #else
# error UNDEFINED SLEEP # error UNDEFINED SLEEP
#endif #endif
@@ -3712,11 +3688,17 @@ static void dl_cleanup (hak_t* hak)
#endif #endif
} }
static void* dlopen_pfmod (hak_t* hak, const hak_ooch_t* name, const hak_ooch_t* dirptr, const hak_oow_t dirlen, hak_bch_t* bufptr, hak_oow_t bufcapa) /* [NOTE] dirptr/dirlen is a byte string - it is a segment of the modlibdirs
* option, which is stored in the byte form precisely because it ends up
* here and in dlopen(). only 'name' still needs converting. */
static void* dlopen_pfmod (hak_t* hak, const hak_ooch_t* name, const hak_bch_t* dirptr, const hak_oow_t dirlen, hak_bch_t* bufptr, hak_oow_t bufcapa)
{ {
void* handle; void* handle;
hak_oow_t len, i, xlen, dlen; hak_oow_t len, i, xlen, dlen;
hak_oow_t ucslen, bcslen; hak_oow_t bcslen;
#if defined(HAK_OOCH_IS_UCH)
hak_oow_t ucslen;
#endif
/* opening a primitive function module - mostly libhak-xxxx. /* opening a primitive function module - mostly libhak-xxxx.
* if PFMODPREFIX is absolute, never use PFMODDIR */ * if PFMODPREFIX is absolute, never use PFMODDIR */
@@ -3727,13 +3709,7 @@ static void* dlopen_pfmod (hak_t* hak, const hak_ooch_t* name, const hak_ooch_t*
} }
else if (dirptr) else if (dirptr)
{ {
xlen = dirlen;
dlen = bufcapa;
#if defined(HAK_OOCH_IS_UCH)
if (hak_convootobchars(hak, dirptr, &xlen, bufptr, &dlen) <= -1) return HAK_NULL;
#else
dlen = hak_copy_bchars_to_bcstr(bufptr, bufcapa, dirptr, dirlen); dlen = hak_copy_bchars_to_bcstr(bufptr, bufcapa, dirptr, dirlen);
#endif
if (dlen > 0 && bufptr[dlen - 1] != HAK_DFL_PATH_SEP) if (dlen > 0 && bufptr[dlen - 1] != HAK_DFL_PATH_SEP)
{ {
@@ -3869,25 +3845,28 @@ static void* dl_open (hak_t* hak, const hak_ooch_t* name, int flags)
{ {
#if defined(USE_LTDL) || defined(USE_DLFCN) || defined(USE_MACH_O_DYLD) #if defined(USE_LTDL) || defined(USE_DLFCN) || defined(USE_MACH_O_DYLD)
hak_bch_t stabuf[128], * bufptr; hak_bch_t stabuf[128], * bufptr;
hak_oow_t ucslen, bcslen, bufcapa;
void* handle = HAK_NULL; void* handle = HAK_NULL;
hak_oow_t bufcapa;
const hak_bch_t* modlibdirs;
#if defined(HAK_OOCH_IS_UCH)
hak_oow_t ucslen;
#endif
modlibdirs = hak->option.modlibdirs_b;
#if defined(HAK_OOCH_IS_UCH) #if defined(HAK_OOCH_IS_UCH)
if (hak_convootobcstr(hak, name, &ucslen, HAK_NULL, &bufcapa) <= -1) return HAK_NULL; if (hak_convootobcstr(hak, name, &ucslen, HAK_NULL, &bufcapa) <= -1) return HAK_NULL;
if (hak->option.mod[0].len > 0)
{
/* multiple directories separated by a colon can be specified for HAK_MOD_LIBDIRS
* however, use the total length to secure space just for simplicity */
ucslen = hak->option.mod[0].len;
if (hak_convootobchars(hak, hak->option.mod[0].ptr, &ucslen, HAK_NULL, &bcslen) <= -1) return HAK_NULL;
bufcapa += bcslen;
}
#else #else
bufcapa = hak_count_bcstr(name); bufcapa = hak_count_bcstr(name);
bufcapa += (hak->option.mod[0].len > 0)? hak->option.mod[0].len: HAK_COUNTOF(HAK_DEFAULT_PFMODDIR);
#endif #endif
/* modlibdirs is stored in the byte form too, so no conversion is needed
* here. multiple directories separated by a colon can be specified for
* HAK_OPT_MODLIBDIRS - use the total length to secure space, for
* simplicity. */
bufcapa += (modlibdirs && modlibdirs[0] != '\0')?
hak_count_bcstr(modlibdirs): HAK_COUNTOF(HAK_DEFAULT_PFMODDIR);
/* HAK_COUNTOF(HAK_DEFAULT_PFMODPREFIX) and HAK_COUNTOF(HAK_DEFAULT_PFMODPOSTIFX) /* HAK_COUNTOF(HAK_DEFAULT_PFMODPREFIX) and HAK_COUNTOF(HAK_DEFAULT_PFMODPOSTIFX)
* include the terminating nulls. Never mind about the extra 2 characters. */ * include the terminating nulls. Never mind about the extra 2 characters. */
bufcapa += HAK_COUNTOF(HAK_DEFAULT_PFMODPREFIX) + HAK_COUNTOF(HAK_DEFAULT_PFMODPOSTFIX) + 1; bufcapa += HAK_COUNTOF(HAK_DEFAULT_PFMODPREFIX) + HAK_COUNTOF(HAK_DEFAULT_PFMODPOSTFIX) + 1;
@@ -3901,12 +3880,12 @@ static void* dl_open (hak_t* hak, const hak_ooch_t* name, int flags)
if (flags & HAK_VMPRIM_DLOPEN_PFMOD) if (flags & HAK_VMPRIM_DLOPEN_PFMOD)
{ {
if (hak->option.mod[0].len > 0) if (modlibdirs && modlibdirs[0] != '\0')
{ {
const hak_ooch_t* ptr, * end, * seg; const hak_bch_t* ptr, * end, * seg;
ptr = hak->option.mod[0].ptr; ptr = modlibdirs;
end = hak->option.mod[0].ptr + hak->option.mod[0].len; end = modlibdirs + hak_count_bcstr(modlibdirs);
seg = ptr; seg = ptr;
while (ptr <= end) while (ptr <= end)
@@ -4109,8 +4088,8 @@ static void cb_on_option (hak_t* hak, hak_option_t id, const void* value)
xtn_t* xtn = GET_XTN(hak); xtn_t* xtn = GET_XTN(hak);
int fd; int fd;
if (id != HAK_LOG_TARGET_BCSTR && id != HAK_LOG_TARGET_UCSTR && if (id != HAK_OPT_LOG_TARGET_BCSTR && id != HAK_OPT_LOG_TARGET_UCSTR &&
id != HAK_LOG_TARGET_BCS && id != HAK_LOG_TARGET_UCS) return; /* return success. not interested */ id != HAK_OPT_LOG_TARGET_BCS && id != HAK_OPT_LOG_TARGET_UCS) return; /* return success. not interested */
#if defined(_WIN32) #if defined(_WIN32)
#if defined(HAK_OOCH_IS_UCH) && (HAK_SIZEOF_UCH_T == HAK_SIZEOF_WCHAR_T) #if defined(HAK_OOCH_IS_UCH) && (HAK_SIZEOF_UCH_T == HAK_SIZEOF_WCHAR_T)
@@ -4663,12 +4642,13 @@ static HAK_INLINE int open_cci_stream (hak_t* hak, hak_io_cciarg_t* arg)
xtn_t* xtn = GET_XTN(hak); xtn_t* xtn = GET_XTN(hak);
bb_t* bb = HAK_NULL; bb_t* bb = HAK_NULL;
/* TOOD: support predefined include directory as well */
if (arg->includer) if (arg->includer)
{ {
/* includee */ /* includee */
hak_oow_t ucslen, bcslen, parlen; hak_oow_t ucslen, bcslen, parlen;
const hak_bch_t* fn, * fb; const hak_bch_t* fn, * fb;
int attempt_incdirs;
const hak_bch_t* incdirs_ptr;
#if defined(HAK_OOCH_IS_UCH) #if defined(HAK_OOCH_IS_UCH)
if (hak_convootobcstr(hak, arg->name, &ucslen, HAK_NULL, &bcslen) <= -1) goto oops; if (hak_convootobcstr(hak, arg->name, &ucslen, HAK_NULL, &bcslen) <= -1) goto oops;
@@ -4682,27 +4662,63 @@ static HAK_INLINE int open_cci_stream (hak_t* hak, hak_io_cciarg_t* arg)
{ {
fb = ""; fb = "";
parlen = 0; parlen = 0;
attempt_incdirs = 0;
} }
else else
{ {
fb = hak_get_base_name_from_bcstr_path(fn); fb = hak_get_base_name_from_bcstr_path(fn);
parlen = fb - fn; parlen = fb - fn;
attempt_incdirs = !((arg->name[0] == '.' && arg->name[1] == '/') || (arg->name[0] == '.' && arg->name[1] == '.' && arg->name[2] == '/'));
} }
bb = (bb_t*)hak_callocmem(hak, HAK_SIZEOF(*bb) + (HAK_SIZEOF(hak_bch_t) * (parlen + bcslen + 1))); bb = (bb_t*)hak_callocmem(hak, HAK_SIZEOF(*bb) + (HAK_SIZEOF(hak_bch_t) * (parlen + bcslen + 1)));
if (!bb) goto oops; if (HAK_UNLIKELY(!bb)) goto oops;
bb->fn = (hak_bch_t*)(bb + 1); bb->fn = (hak_bch_t*)(bb + 1);
hak_copy_bchars (bb->fn, fn, parlen); hak_copy_bchars(bb->fn, fn, parlen);
#if defined(HAK_OOCH_IS_UCH) #if defined(HAK_OOCH_IS_UCH)
hak_convootobcstr(hak, arg->name, &ucslen, &bb->fn[parlen], &bcslen); hak_convootobcstr(hak, arg->name, &ucslen, &bb->fn[parlen], &bcslen);
#else #else
hak_copy_bcstr(&bb->fn[parlen], bcslen + 1, arg->name); hak_copy_bcstr(&bb->fn[parlen], bcslen + 1, arg->name);
#endif #endif
incdirs_ptr = hak->option.incdirs_b;
retry:
bb->fp = fopen(bb->fn, FOPEN_R_FLAGS); bb->fp = fopen(bb->fn, FOPEN_R_FLAGS);
if (!bb->fp) if (!bb->fp)
{ {
if ((errno == ENOENT || errno == ENOTDIR) && attempt_incdirs && incdirs_ptr && incdirs_ptr[0] != '\0')
{
hak_oow_t incdir_bcslen;
const hak_bch_t* colon;
hak_freemem(hak, bb); bb = HAK_NULL;
/* incdirs is kept in the byte form as well, so the directory part
* needs no conversion here - only the include name does. */
colon = hak_find_bchar_in_bcstr(incdirs_ptr, ':');
incdir_bcslen = colon? (hak_oow_t)(colon - incdirs_ptr): hak_count_bcstr(incdirs_ptr);
bb = (bb_t*)hak_callocmem(hak, HAK_SIZEOF(*bb) + (HAK_SIZEOF(hak_bch_t) * (incdir_bcslen + bcslen + 2)));
if (HAK_UNLIKELY(!bb)) goto oops;
bb->fn = (hak_bch_t*)(bb + 1);
/* TODO: i need to support different directory separator */
hak_copy_bchars(bb->fn, incdirs_ptr, incdir_bcslen);
if (incdir_bcslen > 0 && bb->fn[incdir_bcslen - 1] != '/') bb->fn[incdir_bcslen++] = '/';
#if defined(HAK_OOCH_IS_UCH)
hak_convootobcstr(hak, arg->name, &ucslen, &bb->fn[incdir_bcslen], &bcslen);
#else
hak_copy_bcstr(&bb->fn[incdir_bcslen], bcslen + 1, arg->name);
#endif
incdirs_ptr = colon? colon + 1: HAK_NULL;
/*printf("RETRYING bb->fn [%s]\n", bb->fn);*/
goto retry;
}
hak_seterrbfmt(hak, HAK_EIOERR, "unable to open %hs", bb->fn); hak_seterrbfmt(hak, HAK_EIOERR, "unable to open %hs", bb->fn);
goto oops; goto oops;
} }
@@ -4710,6 +4726,15 @@ static HAK_INLINE int open_cci_stream (hak_t* hak, hak_io_cciarg_t* arg)
else else
{ {
/* main stream */ /* main stream */
/* [NOTE]
* in the current implementation, the main stream is rarely used read
* because the input the the reader/compiler is fed via hak_feed() and its relatives.
* this part doesn't really open the specified file.
*/
/* TODO: make if hak_feed() is going to be used or not.
* if it's not used, it can open it as usual as xtn->cci_path point to the file name anyways */
hak_oow_t pathlen; hak_oow_t pathlen;
pathlen = xtn->cci_path? hak_count_bcstr(xtn->cci_path): 0; pathlen = xtn->cci_path? hak_count_bcstr(xtn->cci_path): 0;
@@ -4822,7 +4847,7 @@ static HAK_INLINE int read_cci_stream (hak_t* hak, hak_io_cciarg_t* arg)
#else #else
bcslen = (bb->len < HAK_COUNTOF(arg->buf.c))? bb->len: HAK_COUNTOF(arg->buf.c); bcslen = (bb->len < HAK_COUNTOF(arg->buf.c))? bb->len: HAK_COUNTOF(arg->buf.c);
ucslen = bcslen; ucslen = bcslen;
hak_copy_bchars (arg->buf.c, bb->buf, bcslen); hak_copy_bchars(arg->buf.c, bb->buf, bcslen);
#endif #endif
remlen = bb->len - bcslen; remlen = bb->len - bcslen;
@@ -4973,7 +4998,7 @@ static HAK_INLINE int read_udi_stream (hak_t* hak, hak_io_udiarg_t* arg)
#else #else
bcslen = (bb->len < HAK_COUNTOF(arg->buf.c))? bb->len: HAK_COUNTOF(arg->buf.c); bcslen = (bb->len < HAK_COUNTOF(arg->buf.c))? bb->len: HAK_COUNTOF(arg->buf.c);
ucslen = bcslen; ucslen = bcslen;
hak_copy_bchars (arg->buf.c, bb->buf, bcslen); hak_copy_bchars(arg->buf.c, bb->buf, bcslen);
#endif #endif
remlen = bb->len - bcslen; remlen = bb->len - bcslen;
@@ -5016,7 +5041,7 @@ static HAK_INLINE int read_udi_stream_bytes (hak_t* hak, hak_io_udiarg_t* arg)
bcslen = (bb->len < HAK_COUNTOF(arg->buf.b))? bb->len: HAK_COUNTOF(arg->buf.b); bcslen = (bb->len < HAK_COUNTOF(arg->buf.b))? bb->len: HAK_COUNTOF(arg->buf.b);
ucslen = bcslen; ucslen = bcslen;
hak_copy_bchars ((hak_bch_t*)arg->buf.b, bb->buf, bcslen); hak_copy_bchars((hak_bch_t*)arg->buf.b, bb->buf, bcslen);
remlen = bb->len - bcslen; remlen = bb->len - bcslen;
if (remlen > 0) HAK_MEMMOVE(bb->buf, &bb->buf[bcslen], remlen); if (remlen > 0) HAK_MEMMOVE(bb->buf, &bb->buf[bcslen], remlen);
@@ -5113,7 +5138,7 @@ static HAK_INLINE int write_udo_stream (hak_t* hak, hak_io_udoarg_t* arg)
ucslen = arg->len - donelen; ucslen = arg->len - donelen;
if (ucslen > bcslen) ucslen = bcslen; if (ucslen > bcslen) ucslen = bcslen;
else if (ucslen < bcslen) bcslen = ucslen; else if (ucslen < bcslen) bcslen = ucslen;
hak_copy_bchars (bcsbuf, &ptr[donelen], bcslen); hak_copy_bchars(bcsbuf, &ptr[donelen], bcslen);
#endif #endif
if (fwrite(bcsbuf, HAK_SIZEOF(bcsbuf[0]), bcslen, (FILE*)arg->handle) < bcslen) if (fwrite(bcsbuf, HAK_SIZEOF(bcsbuf[0]), bcslen, (FILE*)arg->handle) < bcslen)
+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;
+25
View File
@@ -605,21 +605,46 @@ static hak_pfinfo_t pfinfos[] =
{ "classRespondsTo", { HAK_PFBASE_FUNC, pf_core_class_responds_to, 2, 2 } }, { "classRespondsTo", { HAK_PFBASE_FUNC, pf_core_class_responds_to, 2, 2 } },
{ "cons", { HAK_PFBASE_FUNC, pf_core_cons, 2, 2 } }, { "cons", { HAK_PFBASE_FUNC, pf_core_cons, 2, 2 } },
{ "current-process", { HAK_PFBASE_FUNC, hak_pf_process_current, 0, 0 } },
{ "eqk?", { HAK_PFBASE_FUNC, hak_pf_eqk, 2, 2 } }, { "eqk?", { HAK_PFBASE_FUNC, hak_pf_eqk, 2, 2 } },
{ "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-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 } },
}; };
+9 -3
View File
@@ -31,9 +31,8 @@
#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>
@@ -174,7 +173,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.
* ------------------------------------------------------------------------ */ * ------------------------------------------------------------------------ */
@@ -813,6 +812,13 @@ static hak_pfinfo_t pfinfos[] =
{ "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 } },
{ "sig-catch", { HAK_PFBASE_FUNC, hak_pf_system_catch_sig, 1, 1 } },
{ "sig-get", { HAK_PFBASE_FUNC, hak_pf_system_get_sig, 0, 0 } },
{ "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 } }, { "srandom", { HAK_PFBASE_FUNC, pf_sys_srandom, 1, 1 } },
{ "stime", { HAK_PFBASE_FUNC, pf_sys_stime, 1, 1 } }, { "stime", { HAK_PFBASE_FUNC, pf_sys_stime, 1, 1 } },
{ "time", { HAK_PFBASE_FUNC, pf_sys_time, 0, 0 } }, { "time", { HAK_PFBASE_FUNC, pf_sys_time, 0, 0 } },
+3
View File
@@ -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'
+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 {
}
+73
View File
@@ -0,0 +1,73 @@
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)
}
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)
}
}
+3 -79
View File
@@ -1,84 +1,8 @@
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 "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
} }
} }
+2 -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 = \
+2 -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 = \
+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 }
+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.