diff --git a/moo/kernel/Context.moo b/moo/kernel/Context.moo index c543b93..84d43ab 100644 --- a/moo/kernel/Context.moo +++ b/moo/kernel/Context.moo @@ -121,6 +121,7 @@ class(#pointer,#final,#limited) BlockContext(Context) // create a new process in the suspended state method(#variadic,#primitive) newProcess(). + method(#variadic,#primitive) newSystemProcess(). // this method is for internal use only. never call this. // evaluate the block method(#variadic,#primitive) value(). diff --git a/moo/kernel/System.moo b/moo/kernel/System.moo index e53c8c8..63e03ac 100644 --- a/moo/kernel/System.moo +++ b/moo/kernel/System.moo @@ -13,8 +13,7 @@ class System(Apex) var(#class) asyncsg. var(#class) gcfin_sem. var(#class) gcfin_should_exit := false. - var(#class) gcfin_proc. - var(#class) ossig_proc. + var(#class) ossig_pid. var(#class) shr. // signal handler registry pooldic Log @@ -64,7 +63,7 @@ class System(Apex) method(#class) startup(class_name, method_name) { - | class ret | + | class ret gcfin_proc ossig_proc | System gc. @@ -79,11 +78,13 @@ class System(Apex) // start the gc finalizer process and os signal handler process //[ self __gc_finalizer ] fork. //[ self __os_sig_handler ] fork. - self.gcfin_proc := [ self __gc_finalizer ] newProcess. - self.ossig_proc := [ :caller | self __os_sig_handler: caller ] newProcess(thisProcess). + gcfin_proc := [ self __gc_finalizer ] newSystemProcess. + ossig_proc := [ :caller | self __os_sig_handler: caller ] newSystemProcess(thisProcess). + + self.ossig_pid := ossig_proc id. - self.gcfin_proc resume. - self.ossig_proc resume. + gcfin_proc resume. + ossig_proc resume. [ // TODO: change the method signature to variadic and pass extra arguments to perform??? @@ -147,7 +148,6 @@ class System(Apex) self.gcfin_sem signal. // in case the process is stuck in wait. self.gcfin_sem unsignal. System logNl: 'End of GC finalization process ' & (thisProcess id) asString. - self.gcfin_proc := nil. ]. } @@ -207,7 +207,8 @@ class System(Apex) 3 .. -> other processes started by application. */ /* TODO: this loop is error-prone as it can't handle when the processs id wraps back and the id of gcfin_proc and ossig_proc gets bigger than normal child processes */ - proc := System _findProcessByIdGreaterThan: (self.ossig_proc id). + //proc := System _findProcessByIdGreaterThan: self.ossig_pid. + proc := System _findProcessByIdGreaterThan: -1. while (proc notError) { pid := proc id. @@ -225,7 +226,6 @@ class System(Apex) self.gcfin_should_exit := true. self.gcfin_sem signal. // wake the gcfin process. - self.ossig_proc := nil. self _halting. // inform VM that it should get ready for halting. ]. } diff --git a/moo/lib/exec.c b/moo/lib/exec.c index 1826afd..748dad9 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -282,6 +282,7 @@ static MOO_INLINE void alloc_pid (moo_t* moo, moo_oop_process_t proc) moo->proc_map_free_first = MOO_OOP_TO_SMOOI(moo->proc_map[pid]); if (moo->proc_map_free_first <= -1) moo->proc_map_free_last = -1; moo->proc_map[pid] = (moo_oop_t)proc; + moo->proc_map_used++; } static MOO_INLINE void free_pid (moo_t* moo, moo_oop_process_t proc) @@ -290,7 +291,9 @@ static MOO_INLINE void free_pid (moo_t* moo, moo_oop_process_t proc) pid = MOO_OOP_TO_SMOOI(proc->id); MOO_ASSERT (moo, pid < moo->proc_map_capa); + MOO_ASSERT (moo, moo->proc_map_used > 0); + /* chain the freed slot at the end of the free list */ moo->proc_map[pid] = MOO_SMOOI_TO_OOP(-1); if (moo->proc_map_free_last <= -1) { @@ -302,9 +305,10 @@ static MOO_INLINE void free_pid (moo_t* moo, moo_oop_process_t proc) moo->proc_map[moo->proc_map_free_last] = MOO_SMOOI_TO_OOP(pid); } moo->proc_map_free_last = pid; + moo->proc_map_used--; } -static moo_oop_process_t make_process (moo_t* moo, moo_oop_context_t c) +static moo_oop_process_t make_process (moo_t* moo, moo_oop_context_t c, int proc_flags) { moo_oop_process_t proc; moo_ooi_t total_count; @@ -327,7 +331,7 @@ static moo_oop_process_t make_process (moo_t* moo, moo_oop_context_t c) moo_popvolat (moo); if (!proc) return MOO_NULL; - MOO_OBJ_SET_FLAGS_PROC (proc, 1); /* a special flag to indicate an object is a process instance */ + MOO_OBJ_SET_FLAGS_PROC (proc, proc_flags); /* a special flag to indicate an object is a process instance */ proc->state = MOO_SMOOI_TO_OOP(PROC_STATE_SUSPENDED); /* assign a process id to the process */ @@ -1624,7 +1628,7 @@ static moo_oop_process_t start_initial_process (moo_t* moo, moo_oop_context_t c) MOO_ASSERT (moo, moo->processor->runnable.count == MOO_SMOOI_TO_OOP(0)); MOO_ASSERT (moo, moo->processor->active == moo->nil_process); - proc = make_process(moo, c); + proc = make_process(moo, c, 2); if (!proc) return MOO_NULL; chain_into_processor (moo, proc, PROC_STATE_RUNNING); @@ -2256,6 +2260,11 @@ static moo_pfrc_t pf_hash (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) case MOO_OBJ_FLAGS_HASH_STORED: hv = *(moo_oow_t*)((moo_uint8_t*)rcv + MOO_SIZEOF(moo_obj_t) + moo_getobjpayloadbytes(moo, rcv) - MOO_SIZEOF(moo_oow_t)); break; + + default: + /* this must not happend. internal error */ + moo_seterrbfmt (moo, MOO_EINTERN, "internal error - unknown hash flags %d in %O", (int)MOO_OBJ_GET_FLAGS_HASH(rcv), rcv); + return MOO_PF_HARD_FAILURE; } } } @@ -2642,7 +2651,7 @@ static moo_pfrc_t pf_block_value (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) return MOO_PF_SUCCESS; } -static moo_pfrc_t pf_block_new_process (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) +static MOO_INLINE moo_pfrc_t __block_new_process (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs, int proc_flags) { /* create a new process from a block context. * the receiver must be be a block. @@ -2693,7 +2702,7 @@ static moo_pfrc_t pf_block_new_process (moo_t* moo, moo_mod_t* mod, moo_ooi_t na * context of a process. */ blkctx->sender = (moo_oop_context_t)moo->_nil; - proc = make_process(moo, blkctx); + proc = make_process(moo, blkctx, proc_flags); if (!proc) return MOO_PF_FAILURE; /* hard failure */ /* TOOD: can't this be treated as a soft failure? throw an exception instead?? */ /* __block_value() has popped all arguments and the receiver. @@ -2702,6 +2711,16 @@ static moo_pfrc_t pf_block_new_process (moo_t* moo, moo_mod_t* mod, moo_ooi_t na return MOO_PF_SUCCESS; } +static moo_pfrc_t pf_block_new_process (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) +{ + return __block_new_process(moo, mod, nargs, 1); +} + +static moo_pfrc_t pf_block_new_system_process (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) +{ + return __block_new_process(moo, mod, nargs, 2); +} + /* ------------------------------------------------------------------ */ static moo_pfrc_t pf_process_sp (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) @@ -3296,10 +3315,9 @@ static moo_pfrc_t pf_system_halting (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs static moo_pfrc_t pf_system_find_process_by_id (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { - moo_oop_t rcv, id; - moo_oop_process_t proc; + moo_oop_t /*rcv,*/ id; - rcv = MOO_STACK_GETRCV(moo, nargs); + /*rcv = MOO_STACK_GETRCV(moo, nargs);*/ id = MOO_STACK_GETARG(moo, nargs, 0); /*MOO_PF_CHECK_RCV (moo, rcv == (moo_oop_t)moo->processor);*/ @@ -3326,10 +3344,9 @@ static moo_pfrc_t pf_system_find_process_by_id (moo_t* moo, moo_mod_t* mod, moo_ static moo_pfrc_t pf_system_find_process_by_id_gt (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { - moo_oop_t rcv, id; - moo_oop_process_t proc; + moo_oop_t /*rcv,*/ id; - rcv = MOO_STACK_GETRCV(moo, nargs); + /*rcv = MOO_STACK_GETRCV(moo, nargs);*/ id = MOO_STACK_GETARG(moo, nargs, 0); /*MOO_PF_CHECK_RCV (moo, rcv == (moo_oop_t)moo->processor);*/ @@ -3337,14 +3354,19 @@ static moo_pfrc_t pf_system_find_process_by_id_gt (moo_t* moo, moo_mod_t* mod, m if (MOO_OOP_IS_SMOOI(id)) { moo_ooi_t index = MOO_OOP_TO_SMOOI(id); - if (index >= 0) + if (index >= -1) /* allow -1 to be able to return pid 0. */ { /* TOOD: enhance alloc_pid() and free_pid() to maintain the hightest pid number so that this loop can stop before reaching proc_map_capa */ for (++index; index < moo->proc_map_capa; index++) { - if (MOO_CLASSOF(moo, moo->proc_map[index]) == moo->_process) + /* note the free slot contains a small integer which indicate the next slot index in proc_map. + * if the slot it taken, it should point to a process object. read the comment at end of this loop. */ + moo_oop_t tmp; + + tmp = moo->proc_map[index]; + if (MOO_CLASSOF(moo, tmp) == moo->_process && MOO_OBJ_GET_FLAGS_PROC(tmp) == 1) /* normal process only. skip a system process */ { - MOO_STACK_SETRET (moo, nargs, moo->proc_map[index]); + MOO_STACK_SETRET (moo, nargs, tmp); return MOO_PF_SUCCESS; } @@ -4378,6 +4400,7 @@ static pf_t pftab[] = { "Apex_~~", { moo_pf_not_identical, 1, 1 } }, { "BlockContext_newProcess", { pf_block_new_process, 0, MA } }, + { "BlockContext_newSystemProcess", { pf_block_new_system_process, 0, MA } }, { "BlockContext_value", { pf_block_value, 0, MA } }, { "Character_<", { pf_character_lt, 1, 1 } }, @@ -6471,6 +6494,7 @@ int moo_invoke (moo_t* moo, const moo_oocs_t* objname, const moo_oocs_t* mthname MOO_ASSERT (moo, moo->initial_context == MOO_NULL); MOO_ASSERT (moo, moo->active_context == MOO_NULL); MOO_ASSERT (moo, moo->active_method == MOO_NULL); + #if defined(MOO_PROFILE_VM) moo->stat.inst_counter = 0; @@ -6481,6 +6505,31 @@ int moo_invoke (moo_t* moo, const moo_oocs_t* objname, const moo_oocs_t* mthname moo_clearmethodcache (moo); +#if 0 + /* unless the system is buggy, moo->proc_map_used should be 0. + * the standard library terminates all processes before halting. + * + * [EXPERIMENTAL] + * if you like the process allocation to start from 0, uncomment + * the following 'if' block */ + if (moo->proc_map_capa > 0 && moo->proc_map_used == 0) + { + /* rechain the process map. it must be compatible with prepare_to_alloc_pid(). + * by placing the low indiced slot at the beginning of the free list, + * the special processes (main_proc, gcfin_proc, ossig_proc) are allocated + * with low process IDs. */ + moo_ooi_t i, j; + + moo->proc_map_free_first = 0; + for (i = 0, j = 1; j < moo->proc_map_capa; i++, j++) + { + moo->proc_map[i] = MOO_SMOOI_TO_OOP(j); + } + moo->proc_map[i] = MOO_SMOOI_TO_OOP(-1); + moo->proc_map_free_last = i; + } +#endif + if (start_initial_process_and_context(moo, objname, mthname) <= -1) return -1; moo->initial_context = moo->processor->active->initial_context; @@ -6491,6 +6540,7 @@ int moo_invoke (moo_t* moo, const moo_oocs_t* objname, const moo_oocs_t* mthname moo->active_context = MOO_NULL; moo->active_method = MOO_NULL; + #if defined(MOO_PROFILE_VM) MOO_LOG1 (moo, MOO_LOG_IC | MOO_LOG_INFO, "Total message sends: %zu\n", moo->stat.message_sends); MOO_LOG2 (moo, MOO_LOG_IC | MOO_LOG_INFO, "Method cache - hits: %zu, misses: %zu\n", moo->stat.method_cache_hits, moo->stat.method_cache_misses); diff --git a/moo/lib/gc.c b/moo/lib/gc.c index 071d4e3..b104640 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -405,7 +405,7 @@ static kernel_class_info_t kernel_classes[] = { 6, { 'S','y','s','t','e','m' }, 0, - 6, /* asyncsg, gcfin_sem, gcfin_should_exit, gcfin_proc, ossig_proc, shr */ + 5, /* asyncsg, gcfin_sem, gcfin_should_exit, ossig_pid, shr */ 0, 0, MOO_OBJ_TYPE_OOP, diff --git a/moo/lib/moo.c b/moo/lib/moo.c index 1ea6948..223888a 100644 --- a/moo/lib/moo.c +++ b/moo/lib/moo.c @@ -239,6 +239,7 @@ void moo_fini (moo_t* moo) { moo_freemem (moo, moo->proc_map); moo->proc_map_capa = 0; + moo->proc_map_used = 0; moo->proc_map_free_first = -1; moo->proc_map_free_last = -1; } diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 575a275..4e01695 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -290,7 +290,7 @@ typedef enum moo_gcfin_t moo_gcfin_t; #define MOO_OBJ_FLAGS_KERNEL_BITS 2 #define MOO_OBJ_FLAGS_PERM_BITS 1 #define MOO_OBJ_FLAGS_MOVED_BITS 1 -#define MOO_OBJ_FLAGS_PROC_BITS 1 +#define MOO_OBJ_FLAGS_PROC_BITS 2 #define MOO_OBJ_FLAGS_RDONLY_BITS 1 #define MOO_OBJ_FLAGS_GCFIN_BITS 4 #define MOO_OBJ_FLAGS_TRAILER_BITS 1 @@ -1674,6 +1674,7 @@ struct moo_t moo_oop_t* proc_map; moo_oow_t proc_map_capa; + moo_oow_t proc_map_used; moo_ooi_t proc_map_free_first; moo_ooi_t proc_map_free_last; diff --git a/moo/wasm/build.sh b/moo/wasm/build.sh index 8e2c4c5..c0c6b5a 100644 --- a/moo/wasm/build.sh +++ b/moo/wasm/build.sh @@ -11,12 +11,15 @@ emcc -Wall -O2 -g \ -DMOO_HAVE_CFG_H \ -I${blddir}/lib \ -I${topdir}/lib\ - -s WASM=1 -s LINKABLE=1 \ + -s WASM=1 \ + -s LINKABLE=1 \ + -s ALLOW_MEMORY_GROWTH=1 \ -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall','cwrap']" \ -o libmoo.js \ --embed-file ${topdir}/kernel/ \ --pre-js ${topdir}/wasm/moo.cb.js +##-s USE_PTHREADS=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ ##cp -pf ${topdir}/wasm/moo.html . ##cp -pf ${topdir}/wasm/moo.worker.js . ln -sf ${topdir}/wasm/moo.html moo.html