Compare commits

...
10 Commits
22 changed files with 870 additions and 355 deletions
+34 -32
View File
@@ -249,8 +249,8 @@ static int handle_logopt (hak_t* hak, const hak_bch_t* logstr)
}
fname.ptr = (hak_bch_t*)logstr;
hak_setoption (hak, HAK_LOG_TARGET_BCS, &fname);
hak_setoption (hak, HAK_LOG_MASK, &logmask);
hak_setoption (hak, HAK_OPT_LOG_TARGET_BCS, &fname);
hak_setoption (hak, HAK_OPT_LOG_MASK, &logmask);
return 0;
}
@@ -280,9 +280,9 @@ static int handle_dbgopt (hak_t* hak, const hak_bch_t* str)
}
while (cm);
hak_getoption(hak, HAK_TRAIT, &trait);
hak_getoption(hak, HAK_OPT_TRAIT, &trait);
trait |= dbgopt;
hak_setoption(hak, HAK_TRAIT, &trait);
hak_setoption(hak, HAK_OPT_TRAIT, &trait);
return 0;
}
#endif
@@ -865,6 +865,7 @@ int main (int argc, char* argv[])
{ ":debug", '\0' },
#endif
{ ":heapsize", '\0' },
{ ":incdirs", 'I' },
{ ":log", 'l' },
{ "info", '\0' },
{ ":modlibdirs", '\0' },
@@ -873,7 +874,7 @@ int main (int argc, char* argv[])
};
static hak_bopt_t opt =
{
"l:v",
"I:l:v",
lopt
};
@@ -882,6 +883,7 @@ int main (int argc, char* argv[])
int verbose = 0;
int show_info = 0;
const char* modlibdirs = HAK_NULL;
const char* incdirs = HAK_NULL;
#if defined(HAK_BUILD_DEBUG)
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, "Options are:\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, " --modlibdirs string specify directories to load modules from\n");
fprintf(stderr, " -v show verbose messages\n");
@@ -907,6 +910,10 @@ int main (int argc, char* argv[])
{
switch (c)
{
case 'I':
incdirs = opt.arg;
break;
case 'l':
logopt = opt.arg;
break;
@@ -980,15 +987,15 @@ int main (int argc, char* argv[])
{
hak_oow_t tab_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;
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 */
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 */
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 */
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_AWAIT_PROCS;
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 defined(HAK_OOCH_IS_UCH)
hak_ooch_t* tmp;
tmp = hak_dupbtoucstr(hak, modlibdirs, HAK_NULL);
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)
/* 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_MODLIBDIRS_BCSTR, modlibdirs) <= -1)
{
hak_logbfmt(hak, HAK_LOG_STDERR,"ERROR: cannot set modlibdirs - [%d] %js\n", hak_geterrnum(hak), hak_geterrmsg(hak));
goto oops;
}
#endif
}
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.
{
hak_bitmask_t trait;
hak_getoption(hak, HAK_TRAIT, &trait);
hak_getoption(hak, HAK_OPT_TRAIT, &trait);
trait |= HAK_TRAIT_INTERACTIVE;
hak_setoption(hak, HAK_TRAIT, &trait);
hak_setoption(hak, HAK_OPT_TRAIT, &trait);
}
#endif
+216 -15
View File
@@ -4,8 +4,10 @@ import (
"flag"
"fmt"
"hak"
"io"
"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 */
var BINDIR = "."
var SBINDIR = "."
@@ -25,10 +30,14 @@ var LIBDIR = "."
var SYSCONFDIR = "."
type Param struct {
log_file string
log_target string
log_mask hak.BitMask
input_file string
heapsize uint
modlibdirs string
incdirs string
verbose bool
show_info bool
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 {
/*
var nargs int = len(os.Args)
@@ -64,34 +160,110 @@ func handle_arguments(param *Param) error {
var fs *flag.FlagSet
var heapsize *uint
var modlibdirs *string
var incdirs *string
var log *string
var verbose *bool
var show_info *bool
var err error
fs = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
heapsize = fs.Uint("heapsize", 0, "specify heap size")
modlibdirs = fs.String("modlibdirs", "", "specify module library directories")
log = fs.String("log", "", "specify log file")
/* the same set bin/hak.c accepts. the flag package treats -x and --x
* alike, so registering both spellings of a short option is enough to
* 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
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:])
fs.Usage = param.fs_usage // restore it
fs.SetOutput(os.Stderr) // so the restored usage still prints
if err != nil {
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 {
return fmt.Errorf("no input file specified")
} 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")
}
param.input_file = fs.Arg(0);
param.log_file = *log // TODO: parse the option part (e.g. --log /dev/stderr,debug+)
param.heapsize = *heapsize // TODO: set this to hak
param.modlibdirs = *modlibdirs // TODO: set this to hak
return nil;
param.input_file = fs.Arg(0)
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() {
@@ -99,6 +271,7 @@ func main() {
var x *hak.Hak = nil
var err error = nil
var param Param
var stop_ticker func()
var rfh hak.CciFileHandler
var sfh hak.UdiFileHandler
@@ -111,20 +284,39 @@ func main() {
os.Exit(1)
}
if param.show_info {
fmt.Println(hak.BuildInfo())
os.Exit(0)
}
x, err = hak.New()
if err != nil {
fmt.Printf("ERROR: failed to instantiate hak - %s\n", err.Error())
os.Exit(1)
}
if param.log_file != "" {
x.SetLogMask(^hak.BitMask(0))
x.SetLogTarget("/dev/stderr")
if param.log_target != "" {
/* honour both halves of --log. the previous code discarded the path
* 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)
err = x.Ignite(1000000)
err = x.Ignite(uintptr(param.heapsize))
if err != nil {
fmt.Printf("ERROR: failed to ignite - %s\n", err.Error())
goto oops
@@ -169,16 +361,25 @@ func main() {
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.SetLogMask(0)
stop_ticker = start_ticker(x)
err = x.Execute()
stop_ticker()
if err != nil {
//fmt.Printf("ERROR: %s[%d:%d] - %s\n", herr.File, herr.Line, herr.Colm, herr.Msg)
fmt.Printf("ERROR: %s\n", err.Error())
goto oops
}
if param.verbose {
fmt.Printf("EXECUTION OK - %s\n", param.input_file)
}
x.Close()
os.Exit(0)
+47 -13
View File
@@ -12,6 +12,7 @@ import (
"io"
"os"
"path"
"strings"
"path/filepath"
"reflect"
"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 (
ioarg *C.hak_io_cciarg_t
name string
raw string
try_incdirs bool
fd int
tptr unsafe.Pointer
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
var includer_name string
name = string(ucstr_to_rune_slice(ioarg.name))
raw = string(ucstr_to_rune_slice(ioarg.name))
tptr = ioarg.includer.handle
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))
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
tptr = C.hak_allocmem(c, C.size_t(unsafe.Sizeof(fd)) + C.size_t(unsafe.Sizeof(tlen)) + tlen)
if tptr == nil {
if ioarg.includer != nil {
g.io.cci.Close(fd)
}
g.set_errmsg(C.HAK_ESYSMEM, "cci name allocation failure")
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 |
*(*int)(tptr) = fd;
*(*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
/* 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) {
if g.inst_no >= 0 {
inst_table.delete_instance(g.inst_no)
@@ -142,7 +174,7 @@ func (hak *Hak) GetTrait() BitMask {
var x C.int
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 {
// this must not happen
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) {
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 {
// this must not happen
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 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 {
// this must not happen
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) {
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 {
// this must not happen
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 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 {
// 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)
}
func (hak *Hak) SetLogTarget(target string) {
func (hak *Hak) SetLogTarget(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_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 {
// 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 {
@@ -399,6 +482,16 @@ func (hak *Hak) Decode() error {
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 {
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)
{
#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;
}
/* [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);
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;
}
/* [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);
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;
}
/* [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);
return HAK_PF_SUCCESS;
}
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);
return HAK_PF_SUCCESS;
}
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);
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;
}
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);
}
/* TODO: sem->signal_action? */
/* other fields are all set to nil */
+9
View File
@@ -2272,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_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 */
/* ========================================================================= */
+127 -47
View File
@@ -380,11 +380,28 @@ void hak_fini (hak_t* hak)
}
}
if (hak->option.incdirs.ptr)
if (hak->option.modlibdirs_b)
{
hak_freemem(hak, hak->option.incdirs.ptr);
hak->option.incdirs.ptr = HAK_NULL;
hak->option.incdirs.len = 0;
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)
@@ -462,28 +479,74 @@ static int dup_str_opt (hak_t* hak, const hak_ooch_t* value, hak_oocs_t* tmp)
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)
{
hak_cb_t* cb;
switch (id)
{
case HAK_TRAIT:
case HAK_OPT_TRAIT:
hak->option.trait = *(const hak_bitmask_t*)value;
#if defined(HAK_BUILD_DEBUG)
hak->option.karatsuba_cutoff = ((hak->option.trait & HAK_TRAIT_DEBUG_BIGINT)? HAK_KARATSUBA_CUTOFF_DEBUG: HAK_KARATSUBA_CUTOFF);
#endif
break;
case HAK_LOG_MASK:
case HAK_OPT_LOG_MASK:
hak->option.log_mask = *(const hak_bitmask_t*)value;
break;
case HAK_LOG_MAXCAPA:
case HAK_OPT_LOG_MAXCAPA:
hak->option.log_maxcapa = *(hak_oow_t*)value;
break;
case HAK_LOG_TARGET_BCSTR:
case HAK_OPT_LOG_TARGET_BCSTR:
{
hak_bch_t* v1;
hak_uch_t* v2;
@@ -503,7 +566,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_LOG_TARGET_UCSTR:
case HAK_OPT_LOG_TARGET_UCSTR:
{
hak_uch_t* v1;
hak_bch_t* v2;
@@ -523,7 +586,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_LOG_TARGET_BCS:
case HAK_OPT_LOG_TARGET_BCS:
{
hak_bch_t* v1;
hak_uch_t* v2;
@@ -544,7 +607,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_LOG_TARGET_UCS:
case HAK_OPT_LOG_TARGET_UCS:
{
hak_uch_t* v1;
hak_bch_t* v2;
@@ -565,7 +628,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_SYMTAB_SIZE:
case HAK_OPT_SYMTAB_SIZE:
{
hak_oow_t w;
@@ -576,7 +639,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_SYSDIC_SIZE:
case HAK_OPT_SYSDIC_SIZE:
{
hak_oow_t w;
@@ -587,7 +650,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_PROCSTK_SIZE:
case HAK_OPT_PROCSTK_SIZE:
{
hak_oow_t w;
@@ -598,7 +661,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_EXSTK_SIZE:
case HAK_OPT_EXSTK_SIZE:
{
hak_oow_t w;
@@ -609,7 +672,7 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_CLSTK_SIZE:
case HAK_OPT_CLSTK_SIZE:
{
hak_oow_t w;
@@ -620,34 +683,40 @@ int hak_setoption (hak_t* hak, hak_option_t id, const void* value)
break;
}
case HAK_MOD_LIBDIRS:
case HAK_MOD_PREFIX:
case HAK_MOD_POSTFIX:
case HAK_OPT_MODLIBDIRS_BCSTR:
if (set_dual_str_opt(hak, value, 1, &hak->option.modlibdirs_b, &hak->option.modlibdirs_u) <= -1) return -1;
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;
int idx;
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);
hak->option.mod[idx] = tmp;
return 0;
}
case HAK_MOD_INCTX:
case HAK_OPT_MODINCTX:
hak->option.mod_inctx = *(void**)value;
break;
case HAK_OPT_INCDIRS:
{
hak_oocs_t tmp;
if (dup_str_opt(hak, value, &tmp) <= -1) return -1;
if (hak->option.incdirs.ptr) hak_freemem(hak, hak->option.incdirs.ptr);
hak->option.incdirs = tmp;
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:
goto einval;
@@ -669,68 +738,79 @@ int hak_getoption (hak_t* hak, hak_option_t id, void* value)
{
switch (id)
{
case HAK_TRAIT:
case HAK_OPT_TRAIT:
*(hak_bitmask_t*)value = hak->option.trait;
return 0;
case HAK_LOG_MASK:
case HAK_OPT_LOG_MASK:
*(hak_bitmask_t*)value = hak->option.log_mask;
return 0;
case HAK_LOG_MAXCAPA:
case HAK_OPT_LOG_MAXCAPA:
*(hak_oow_t*)value = hak->option.log_maxcapa;
return 0;
case HAK_LOG_TARGET_BCSTR:
case HAK_OPT_LOG_TARGET_BCSTR:
*(hak_bch_t**)value = hak->option.log_target_b;
return 0;
case HAK_LOG_TARGET_UCSTR:
case HAK_OPT_LOG_TARGET_UCSTR:
*(hak_uch_t**)value = hak->option.log_target_u;
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)->len = hak_count_bcstr(hak->option.log_target_b);
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)->len = hak_count_ucstr(hak->option.log_target_u);
return 0;
case HAK_SYMTAB_SIZE:
case HAK_OPT_SYMTAB_SIZE:
*(hak_oow_t*)value = hak->option.dfl_symtab_size;
return 0;
case HAK_SYSDIC_SIZE:
case HAK_OPT_SYSDIC_SIZE:
*(hak_oow_t*)value = hak->option.dfl_sysdic_size;
return 0;
case HAK_PROCSTK_SIZE:
case HAK_OPT_PROCSTK_SIZE:
*(hak_oow_t*)value = hak->option.dfl_procstk_size;
return 0;
case HAK_EXSTK_SIZE:
case HAK_OPT_EXSTK_SIZE:
*(hak_oow_t*)value = hak->option.dfl_exstk_size;
return 0;
case HAK_CLSTK_SIZE:
case HAK_OPT_CLSTK_SIZE:
*(hak_oow_t*)value = hak->option.dfl_clstk_size;
return 0;
case HAK_MOD_LIBDIRS:
case HAK_MOD_PREFIX:
case HAK_MOD_POSTFIX:
*(const hak_ooch_t**)value = hak->option.mod[id - HAK_MOD_LIBDIRS].ptr;
case HAK_OPT_MODLIBDIRS_BCSTR:
*(const hak_bch_t**)value = hak->option.modlibdirs_b;
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;
return 0;
case HAK_OPT_INCDIRS:
*(const hak_ooch_t**)value = hak->option.incdirs.ptr;
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;
};
+49 -25
View File
@@ -241,36 +241,50 @@ typedef hak_errbinf_t hak_errinf_t;
enum hak_option_t
{
HAK_TRAIT,
HAK_LOG_MASK,
HAK_LOG_MAXCAPA,
HAK_OPT_TRAIT,
HAK_OPT_LOG_MASK,
HAK_OPT_LOG_MAXCAPA,
HAK_LOG_TARGET_BCSTR,
HAK_LOG_TARGET_UCSTR,
HAK_LOG_TARGET_BCS,
HAK_LOG_TARGET_UCS,
HAK_OPT_LOG_TARGET_BCSTR,
HAK_OPT_LOG_TARGET_UCSTR,
HAK_OPT_LOG_TARGET_BCS,
HAK_OPT_LOG_TARGET_UCS,
#if defined(HAK_OOCH_IS_UCH)
# define HAK_LOG_TARGET HAK_LOG_TARGET_UCSTR
# define HAK_LOG_TARGET_OOCSTR HAK_LOG_TARGET_UCSTR
# define HAK_LOG_TARGET_OOCS HAK_LOG_TARGET_UCS
# define HAK_OPT_LOG_TARGET HAK_OPT_LOG_TARGET_UCSTR
# define HAK_OPT_LOG_TARGET_OOCSTR HAK_OPT_LOG_TARGET_UCSTR
# define HAK_OPT_LOG_TARGET_OOCS HAK_OPT_LOG_TARGET_UCS
#else
# define HAK_LOG_TARGET HAK_LOG_TARGET_BCSTR
# define HAK_LOG_TARGET_OOCSTR HAK_LOG_TARGET_BCSTR
# define HAK_LOG_TARGET_OOCS HAK_LOG_TARGET_BCS
# define HAK_OPT_LOG_TARGET HAK_OPT_LOG_TARGET_BCSTR
# define HAK_OPT_LOG_TARGET_OOCSTR HAK_OPT_LOG_TARGET_BCSTR
# define HAK_OPT_LOG_TARGET_OOCS HAK_OPT_LOG_TARGET_BCS
#endif
HAK_SYMTAB_SIZE, /* default system table size */
HAK_SYSDIC_SIZE, /* default system dictionary size */
HAK_PROCSTK_SIZE, /* default process stack size */
HAK_EXSTK_SIZE, /* default exception stack size */
HAK_CLSTK_SIZE, /* default class stack size */
HAK_OPT_SYMTAB_SIZE, /* default system table size */
HAK_OPT_SYSDIC_SIZE, /* default system dictionary size */
HAK_OPT_PROCSTK_SIZE, /* default process stack size */
HAK_OPT_EXSTK_SIZE, /* default exception stack size */
HAK_OPT_CLSTK_SIZE, /* default class stack size */
HAK_MOD_LIBDIRS,
HAK_MOD_PREFIX,
HAK_MOD_POSTFIX,
HAK_OPT_MODLIBDIRS_BCSTR,
HAK_OPT_MODLIBDIRS_UCSTR,
#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_INCDIRS
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;
@@ -1787,8 +1801,18 @@ struct hak_t
hak_oow_t dfl_clstk_size;
void* mod_inctx;
hak_oocs_t mod[3];
hak_oocs_t incdirs;
/* 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)
/* 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
* such as getting system time or logging. so the heap size doesn't
* 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);
@@ -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
* affected. new hak instances to be created later
* 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;
}
+14 -15
View File
@@ -1256,7 +1256,7 @@ hak_pfrc_t hak_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_hnd_t* hnd;
@@ -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;
}
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;
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;
}
/* (system-catch-sig signo) - route an operating system signal into the
* signal descriptor, where hak code can wait for
* it with core.sem-signal-on-input
* (system-uncatch-sig signo) - release it again
/* (sys.sig-catch signo) - route an operating system signal into the signal
* descriptor, where hak code can wait for it with
* core.sem-signal-on-input
* (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
* 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;
}
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);
}
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);
}
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_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_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' } },
{ 0, 0, pf_system_get_sig, 14, { 's','y','s','t','e','m','-','g','e','t','-','s','i','g' } },
{ 1, 1, pf_system_set_sig, 14, { 's','y','s','t','e','m','-','s','e','t','-','s','i','g' } },
{ 1, 1, pf_system_catch_sig, 16, { 's','y','s','t','e','m','-','c','a','t','c','h','-','s','i','g' } },
{ 1, 1, pf_system_uncatch_sig, 18, { 's','y','s','t','e','m','-','u','n','c','a','t','c','h','-','s','i','g' } },
/* the signal primitives are registered by the sys module instead - see
* pfinfos[] in mod/sys.c. they are reached as sys.sig-getfd, sys.sig-get,
* sys.sig-set, sys.sig-catch and sys.sig-uncatch. the implementations stay
* here and are declared in lib/hak-prv.h. */
{ 0, 0, pf_gc, 2, { 'g','c' } },
+91 -66
View File
@@ -356,7 +356,7 @@
* 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
* 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)
@@ -2104,6 +2104,8 @@ kqueue_syserr:
#elif defined(USE_SELECT)
# define MUXEVT_FD(e) ((e).fd)
# define MUXEVT_MASK(e) ((e).events)
#else
# error UNSUPPORTED
#endif
/* 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;
#if defined(USE_DEVPOLL)
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
if (MUXEVT_FD(xtn->ev.buf[n]) == xtn->iothr.p[0])
{
hak_uint8_t u8;
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;
hak_ooi_t mask;
#if defined(USE_DEVPOLL)
revents = xtn->ev.buf[n].revents;
#elif defined(USE_KQUEUE)
#if defined(USE_KQUEUE)
revents = 0;
/* it's "if .. else if" because kqueue filter is either READ or WRITE. */
if (xtn->ev.buf[n].filter == EVFILT_READ) revents |= XPOLLIN;
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_ERROR) revents |= XPOLLERR;
#elif defined(USE_EPOLL)
revents = xtn->ev.buf[n].events;
#elif defined(USE_POLL)
revents = xtn->ev.buf[n].revents;
#elif defined(USE_SELECT)
revents = xtn->ev.buf[n].events;
#else
revents = MUXEVT_MASK(xtn->ev.buf[n]);
#endif
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 & XPOLLHUP) mask |= HAK_SEMAPHORE_IO_MASK_HANGUP;
#if defined(USE_DEVPOLL)
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
muxwcb(hak, MUXEVT_FD(xtn->ev.buf[n]), mask);
}
}
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 &&
g_sig_state[sig].handler != (hak_uintptr_t)SIG_DFL)
{
/* execute the current handler */
((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_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);
}
}
@@ -3137,8 +3112,10 @@ static HAK_INLINE void post_sig_to_all_haks (int signo)
{
xtn_t* xtn = GET_XTN(hak);
hak_uint8_t u8;
/*hak_abortstd(hak);*/
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));
hak = xtn->next;
}
@@ -3535,7 +3512,6 @@ static HAK_INLINE int start_ticker (void)
nanosleep(&ts, HAK_NULL);
#elif defined(HAVE_USLEEP)
usleep(HAK_TICKER_INTERVAL_USECS * 2);
#else
# error UNDEFINED SLEEP
#endif
@@ -3712,11 +3688,17 @@ static void dl_cleanup (hak_t* hak)
#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;
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.
* 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)
{
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);
#endif
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)
hak_bch_t stabuf[128], * bufptr;
hak_oow_t ucslen, bcslen, bufcapa;
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 (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
bufcapa = hak_count_bcstr(name);
bufcapa += (hak->option.mod[0].len > 0)? hak->option.mod[0].len: HAK_COUNTOF(HAK_DEFAULT_PFMODDIR);
#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)
* include the terminating nulls. Never mind about the extra 2 characters. */
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 (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;
end = hak->option.mod[0].ptr + hak->option.mod[0].len;
ptr = modlibdirs;
end = modlibdirs + hak_count_bcstr(modlibdirs);
seg = ptr;
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);
int fd;
if (id != HAK_LOG_TARGET_BCSTR && id != HAK_LOG_TARGET_UCSTR &&
id != HAK_LOG_TARGET_BCS && id != HAK_LOG_TARGET_UCS) return; /* return success. not interested */
if (id != HAK_OPT_LOG_TARGET_BCSTR && id != HAK_OPT_LOG_TARGET_UCSTR &&
id != HAK_OPT_LOG_TARGET_BCS && id != HAK_OPT_LOG_TARGET_UCS) return; /* return success. not interested */
#if defined(_WIN32)
#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);
bb_t* bb = HAK_NULL;
/* TOOD: support predefined include directory as well */
if (arg->includer)
{
/* includee */
hak_oow_t ucslen, bcslen, parlen;
const hak_bch_t* fn, * fb;
int attempt_incdirs;
const hak_bch_t* incdirs_ptr;
#if defined(HAK_OOCH_IS_UCH)
if (hak_convootobcstr(hak, arg->name, &ucslen, HAK_NULL, &bcslen) <= -1) goto oops;
@@ -4682,15 +4662,17 @@ static HAK_INLINE int open_cci_stream (hak_t* hak, hak_io_cciarg_t* arg)
{
fb = "";
parlen = 0;
attempt_incdirs = 0;
}
else
{
fb = hak_get_base_name_from_bcstr_path(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)));
if (!bb) goto oops;
if (HAK_UNLIKELY(!bb)) goto oops;
bb->fn = (hak_bch_t*)(bb + 1);
hak_copy_bchars(bb->fn, fn, parlen);
@@ -4700,9 +4682,43 @@ static HAK_INLINE int open_cci_stream (hak_t* hak, hak_io_cciarg_t* arg)
hak_copy_bcstr(&bb->fn[parlen], bcslen + 1, arg->name);
#endif
incdirs_ptr = hak->option.incdirs_b;
retry:
bb->fp = fopen(bb->fn, FOPEN_R_FLAGS);
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);
goto oops;
}
@@ -4710,6 +4726,15 @@ static HAK_INLINE int open_cci_stream (hak_t* hak, hak_io_cciarg_t* arg)
else
{
/* 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;
pathlen = xtn->cci_path? hak_count_bcstr(xtn->cci_path): 0;
+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
* such as getting system time or logging. so the heap size doesn't
* 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);
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
* affected. new hak instances to be created later
* 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;
}
+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
* such as getting system time or logging. so the heap size doesn't
* 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_getoption (server->dummy_hak, HAK_TRAIT, &trait);
hak_getoption (server->dummy_hak, HAK_OPT_TRAIT, &trait);
#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_BIGINT) trait |= HAK_TRAIT_DEBUG_BIGINT;
#endif
hak_setoption (server->dummy_hak, HAK_TRAIT, &trait);
hak_setoption (server->dummy_hak, HAK_OPT_TRAIT, &trait);
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 = worker;
hak_setoption(hak, HAK_MOD_INCTX, &server->cfg.module_inctx);
hak_setoption(hak, HAK_LOG_MASK, &server->cfg.logmask);
hak_setoption(hak, HAK_OPT_MODINCTX, &server->cfg.module_inctx);
hak_setoption(hak, HAK_OPT_LOG_MASK, &server->cfg.logmask);
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 (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;
#endif
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));
/*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 */
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 (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;
#endif
hak_setoption (server->dummy_hak, HAK_TRAIT, &trait);
hak_setoption (server->dummy_hak, HAK_OPT_TRAIT, &trait);
}
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
* affected. new hak instances to be created later
* 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;
+7 -1
View File
@@ -606,6 +606,7 @@ static hak_pfinfo_t pfinfos[] =
{ "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 } },
{ "eql?", { HAK_PFBASE_FUNC, hak_pf_eql, 2, 2 } },
{ "eqv?", { HAK_PFBASE_FUNC, hak_pf_eqv, 2, 2 } },
@@ -621,8 +622,10 @@ static hak_pfinfo_t pfinfos[] =
{ "primAt", { HAK_PFBASE_FUNC, pf_core_prim_at, 2, 2 } },
{ "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, 0 } },
{ "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 } },
@@ -632,13 +635,16 @@ static hak_pfinfo_t pfinfos[] =
{ "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 } },
{ "smooiToChar", { HAK_PFBASE_FUNC, pf_core_smooi_to_char, 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 } },
};
+8 -2
View File
@@ -31,9 +31,8 @@
#endif
#include "_sys.h"
#include <hak-hnd.h>
#include "../lib/hak-prv.h"
#include <hak-pio.h>
#include <hak-str.h>
#include <stdlib.h>
#include <signal.h>
@@ -813,6 +812,13 @@ static hak_pfinfo_t pfinfos[] =
{ "pwait", { HAK_PFBASE_FUNC, pf_sys_pwait, 1, 1 } },
{ "random", { HAK_PFBASE_FUNC, pf_sys_random, 0, 0 } },
{ "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 } },
{ "stime", { HAK_PFBASE_FUNC, pf_sys_stime, 1, 1 } },
{ "time", { HAK_PFBASE_FUNC, pf_sys_time, 0, 0 } },
+17 -9
View File
@@ -13,27 +13,35 @@ class[#uncopyable] Semaphore: Object(
_grm_next
) {
fun[#class] new() {
return (core.sem-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) {
core.sem-signal self secs nsecs
return (core.sem-signal self secs nsecs)
}
fun signalOnInput(handle) {
core.sem-signal-on-input self handle
return (core.sem-signal-on-input self handle)
}
fun signalOnOutput(handle) {
core.sem-signal-on-output self handle
return (core.sem-signal-on-output self handle)
}
fun unsignal() {
core.sem-unsignal self
return (core.sem-unsignal self)
}
fun wait() {
core.sem-wait self
return (core.sem-wait self)
}
}
@@ -52,14 +60,14 @@ class[#uncopyable] SemaphoreGroup: Object(
}
fun add(sem) {
core.semgr-add self sem
return (core.semgr-add self sem)
}
fun remove(sem) {
core.semgr-remove self sem
return (core.semgr-remove self sem)
}
fun wait() {
core.semgr-wait self
return (core.semgr-wait self)
}
}
+4 -4
View File
@@ -107,10 +107,10 @@ class ChildGroup(
## semaphore on the signal descriptor for the whole group, once.
if (not self.shared) {
set shared true
system-catch-sig sys.SIGCHLD
sys.sig-catch sys.SIGCHLD
set sigsem (core.sem-new)
core.semgr-add self.sg self.sigsem
core.sem-signal-on-input self.sigsem (system-get-sigfd)
core.sem-signal-on-input self.sigsem (sys.sig-getfd)
}
} else {
## A handle of its own, so a wakeup identifies this child directly.
@@ -180,7 +180,7 @@ class ChildGroup(
if self.shared {
## the signal descriptor spoke: take the byte, then look at
## everyone, since one SIGCHLD may stand for several exits
system-get-sig
sys.sig-get
kid := (self:finished)
if (not (nil? kid)) { return kid }
## otherwise it was a SIGCHLD for a child of the host
@@ -228,7 +228,7 @@ class ChildGroup(
}
if self.shared {
core.sem-unsignal self.sigsem
system-uncatch-sig sys.SIGCHLD
sys.sig-uncatch sys.SIGCHLD
set shared false
}
}
+8 -8
View File
@@ -27,17 +27,17 @@ sys.close (core.basicAt q 0)
sys.close (core.basicAt q 1)
## --- catch and uncatch are idempotent ---
chk (= (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "system-catch-sig returns the signal number"
chk (= (system-catch-sig 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 (= (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "uncatching an uncaught signal is fine"
chk (= (sys.sig-catch sys.SIGUSR1) sys.SIGUSR1) "sys.sig-catch returns the signal number"
chk (= (sys.sig-catch sys.SIGUSR1) sys.SIGUSR1) "catching an already caught signal is fine"
chk (= (sys.sig-uncatch sys.SIGUSR1) sys.SIGUSR1) "sys.sig-uncatch returns the signal number"
chk (= (sys.sig-uncatch sys.SIGUSR1) sys.SIGUSR1) "uncatching an uncaught signal is fine"
## --- a real signal reaches hak code, without stalling the coprocesses ---
## SIGCHLD is used because a child exiting is something this test can arrange
## 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 := (core.sem-new)
tmo := (core.sem-new)
sg := (core.semgr-new)
@@ -58,7 +58,7 @@ fun waiter() {
core.sem-unsignal s
core.sem-unsignal tmo
if (eqv? w tmo) { signo := -2 } \
else { signo := (system-get-sig) }
else { signo := (sys.sig-get) }
core.sem-signal fin
return 0
}
@@ -79,4 +79,4 @@ 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 (= (sys.pwait proc) 4) "and the child's exit status is readable"
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
## cannot, whatever the numbers happen to be here
chk (== (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is catchable"
chk (== (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is uncatchable again"
chk (== (sys.sig-catch sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is catchable"
chk (== (sys.sig-uncatch sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is uncatchable again"
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"
+10 -10
View File
@@ -1,41 +1,41 @@
## 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
## 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
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
+3 -14
View File
@@ -115,18 +115,7 @@ static int on_cnode (hak_t* hak, hak_cnode_t* obj)
static int set_modlibdirs (hak_t* hak)
{
#if defined(HAK_TEST_MODLIBDIRS)
# if defined(HAK_OOCH_IS_UCH)
hak_ooch_t* tmp;
int n;
tmp = hak_dupbtoucstr(hak, HAK_TEST_MODLIBDIRS, HAK_NULL);
if (HAK_UNLIKELY(!tmp)) return -1;
n = hak_setoption(hak, HAK_MOD_LIBDIRS, tmp);
hak_freemem(hak, tmp);
return n;
# else
return hak_setoption(hak, HAK_MOD_LIBDIRS, HAK_TEST_MODLIBDIRS);
# endif
return hak_setoption(hak, HAK_OPT_MODLIBDIRS_BCSTR, HAK_TEST_MODLIBDIRS);
#else
return 0;
#endif
@@ -144,9 +133,9 @@ static void preempts_a_spinner (void)
OK (hak != HAK_NULL, "instantiation");
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;
hak_setoption(hak, HAK_TRAIT, &trait);
hak_setoption(hak, HAK_OPT_TRAIT, &trait);
OK (set_modlibdirs(hak) == 0, "module search path");
+3 -3
View File
@@ -79,12 +79,12 @@ static int run_at_depth (int depth, int expect_overflow)
OK (hak != HAK_NULL, "instantiation");
if (!hak) goto done;
hak_getoption(hak, HAK_TRAIT, &trait);
hak_getoption(hak, HAK_OPT_TRAIT, &trait);
trait |= HAK_TRAIT_LANG_ENABLE_EOL;
hak_setoption(hak, HAK_TRAIT, &trait);
hak_setoption(hak, HAK_OPT_TRAIT, &trait);
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_addbuiltinprims(hak) == 0, "builtin primitives");