diff --git a/scripts/core/engine.js b/scripts/core/engine.js index 8691cedd..07b13a99 100644 --- a/scripts/core/engine.js +++ b/scripts/core/engine.js @@ -633,12 +633,12 @@ function portal_fn(e) break case "receive": - pppfn(e.data) + pppfn(e.data.data) break } } -var peer2contact = new WeakMap() +var peer2contact = new WeakMap() // $_.contact = function(callback, record) { if (!callback) throw new Error('Contact requires a callback function') @@ -649,15 +649,15 @@ $_.contact = function(callback, record) record }) } -$_.contact[prosperon.DOC] = "The contact function sends a message to a portal on another machine to obtain an actor object. +$_.contact[prosperon.DOC] = `The contact function sends a message to a portal on another machine to obtain an actor object. -The callback is a function with a actor input and a reason input. If successful, actor is bound to an actor object. If not successful, actor is null and reason may contain an explanation." +The callback is a function with a actor input and a reason input. If successful, actor is bound to an actor object. If not successful, actor is null and reason may contain an explanation.` $_.receiver = function(fn) { receive_fn = fn; } -$_.receiver[prosperon.DOC] = "registers a function that will receive all messages sent to the actor except for delay events, reply messages (which are sent to the send callback), the unneeded message, and portal contact messages." +$_.receiver[prosperon.DOC] = `registers a function that will receive all messages sent to the actor except for delay events, reply messages (which are sent to the send callback), the unneeded message, and portal contact messages.` $_.start = function(cb, prg, arg) { @@ -678,13 +678,13 @@ $_.start = function(cb, prg, arg) os.createprocess(argv) } -$_.start[prosperon.DOC] = "The start function creates a new actor. The callback function receives messages about the new actor, starting with a message containing the new actor's address object. +$_.start[prosperon.DOC] = `The start function creates a new actor. The callback function receives messages about the new actor, starting with a message containing the new actor's address object. The program text identifies the executable in the program shop that the new actor runs. The arguments array contains up to four arguments of type logical, number, text, or actor address object. -The current actor is the overling of the new actor, and it is notified when the new actor stops. The new actor is an underling of the current actor." +The current actor is the overling of the new actor, and it is notified when the new actor stops. The new actor is an underling of the current actor.` $_.stop = function(actor) { @@ -693,7 +693,7 @@ $_.stop = function(actor) actor_send(actor, {type:"stop"}) } -$_.stop[prosperon.DOC] = "The stop function stops an underling." +$_.stop[prosperon.DOC] = `The stop function stops an underling.` var unneeded_fn = $_.stop var unneeded_time = ar @@ -704,14 +704,14 @@ $_.unneeded = function(fn, seconds = ar) unneeded_fn = fn unneeded_time = seconds } -$_.unneeded[prosperon.DOC] = "registers a function that is called when the actor has not received a message in the recent seconds. The default for seconds is the ar timer. This likely means that the actor is no longer needed. The actor should finish its work and then @.stop()." +$_.unneeded[prosperon.DOC] = `registers a function that is called when the actor has not received a message in the recent seconds. The default for seconds is the ar timer. This likely means that the actor is no longer needed. The actor should finish its work and then @.stop().` $_.delay = function(fn, seconds) { var id = os.addtimer(fn, seconds); return function() { os.removetimer(id); } } -$_.delay[prosperon.DOC] = "used to schedule the invocation of a function at a later time. Any value returned from the delayed invocation is ignored" +$_.delay[prosperon.DOC] = `used to schedule the invocation of a function at a later time. Any value returned from the delayed invocation is ignored` // Set of actor guids var couplings = new Set() @@ -720,7 +720,7 @@ $_.couple = function(actor) { couplings.add(actor.id) } -$_.couple[prosperon.DOC] = "causes this actor to stop when another actor stops." +$_.couple[prosperon.DOC] = `causes this actor to stop when another actor stops.` // Shuffles the message to the actor with whatever means available function actor_send(actor, message) @@ -775,9 +775,9 @@ $_.send = function(actor, message, reply) actor_send(actor, send) } -$_.send[prosperon.DOC] = "sends a message to another actor. The left expression must resolve to an actor address object or a message object that is expecting a reply because it was sent with a callback. The right expression is a record containing the outgoing message. The outgoing message record must not contain functions or patterns or cyclic structures. +$_.send[prosperon.DOC] = `sends a message to another actor. The left expression must resolve to an actor address object or a message object that is expecting a reply because it was sent with a callback. The right expression is a record containing the outgoing message. The outgoing message record must not contain functions or patterns or cyclic structures. -If a callback function is included, then the callback function will receive the reply, not the receiver function." +If a callback function is included, then the callback function will receive the reply, not the receiver function.` var cmd = use('cmd') cmd.process(prosperon.argv) @@ -787,6 +787,9 @@ if (!prosperon.args.id) else prosperon.id = prosperon.args.id; +// now can start the mailbox +os.mailbox_start(prosperon.id); + if (prosperon.args.overling) host.connect("localhost", prosperon.args.overling) @@ -855,9 +858,8 @@ function handle_message(e) break case "contact": - if (pppfn) pppfn(e.data) + if (pppfn) pppfn(e.data.data) break - } } diff --git a/source/jsffi.c b/source/jsffi.c index a11b5c6e..1397c371 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -7025,11 +7025,12 @@ JSC_CCALL(os_rects_to_sprites, ) JSC_CCALL(os_on, - on_exception = JS_DupValue(js,argv[1]); + JSValue *onexp = SDL_GetTLS(&on_exception); + *onexp = JS_DupValue(js,argv[1]); ) JSC_CCALL(os_clean_transforms, - clean_all(); + clean_all(js); ) JSC_CCALL(os_totalmem, return number2js(js, SDL_GetSystemRAM())) @@ -7154,6 +7155,91 @@ JSC_CCALL(os_createprocess, return JS_ThrowReferenceError(js, "Unable to create process: %s\n", SDL_GetError()); ) +int create_new_runtime(void *data) +{ + +} + +JSC_CCALL(os_createthread, + SDL_Thread *thread = SDL_CreateThread(create_new_runtime, "newrt", NULL); +) + +typedef struct mailbox { + SDL_mutex *mutex; + void **messages; +} mailbox; + +static struct { char *key; mailbox value; } *mailboxes = NULL; + +JSC_CCALL(os_mailbox_push, + if (argc < 2) return JS_ThrowInternalError(js, "Need an actor and an array buffer."); + char *id = JS_GetCString(js,argv[0]); + void *nota = value2nota(js, argv[1]); + + int mailbox_index = shgeti(mailboxes, id); + if (mailbox_index == -1) { + JS_FreeCString(js,id); + return JS_ThrowInternalError(js, "No mailbox found for given ID."); + } + + mailbox mb = mailboxes[mailbox_index].value; + + SDL_LockMutex(mb.mutex); + arrput(mb.messages, nota); + SDL_UnlockMutex(mb.mutex); + + JS_FreeCString(js,id); +) + +JSC_CCALL(os_mailbox_service, // grab all from our mailbox and + char *id = JS_GetCString(js,argv[0]); + JSValue fn = JS_DupValue(js,argv[1]); + + int mb_index = shgeti(mailboxes, id); + if (mb_index == -1) { + JS_FreeCString(js,id); + JS_FreeValue(js,fn); + return JS_ThrowInternalError(js, "No mailbox found for given ID."); + } + + mailbox mb = mailboxes[mb_index].value; + + void **temp = NULL; + SDL_LockMutex(mb.mutex); + int count = arrlen(mb.messages); + if (count > 0) { + arrsetlen(temp,count); + memcpy(temp, mb.messages, sizeof(void*) * count); + arrsetlen(mb.messages,0); + } + + SDL_UnlockMutex(mb.mutex); + + for (int i = 0; i < count; i++) { + void *nota = temp[i]; + JSValue obj = nota2value(js, nota); + free(nota); + JSValue call = JS_Call(js, fn, JS_UNDEFINED, 1, &obj); // todo: need to free obj here? + uncaught_exception(js, call); + JS_FreeValue(js,obj); + } + arrfree(temp); + + JS_FreeCString(js,id); + JS_FreeCString(js,fn); +) + +JSC_CCALL(os_mailbox_start, + char *id = JS_GetCString(js,argv[0]); + + void **letters = NULL; + mailbox mb; + mb.mutex = SDL_CreateMutex(); + mb.messages = NULL; + shput(mailboxes, id, mb); + JS_FreeCString(js,id); +) + struct { SDL_TimerID key; JSValue *value; } *timer_hash = NULL; Uint64 os_timer_cb(JSValue *fn, SDL_TimerID id, Uint64 delay) @@ -7460,13 +7546,6 @@ bool rtree_iter(const NUMTYPE *min, const NUMTYPE *max, const JSValue *data, str return 1; } -bool rtree_array_iter(const NUMTYPE *min, const NUMTYPE *max, const JSValue *data, sprite **arr) -{ - sprite *sp = js2sprite(global_js, *data); - arrput(*arr, *sp); - return 1; -} - JSC_CCALL(rtree_query, rtree *tree = js2rtree(js,self); rect r = js2rect(js,argv[0]); @@ -7485,13 +7564,6 @@ JSC_CCALL(rtree_query, data.n = 0; rtree_search(tree, min, max, rtree_iter, &data); ret = data.arr; - -/* - sprite *arr = NULL; - rtree_search(tree, min, max, rtree_array_iter, &arr); - ret = JS_NewArrayBufferCopy(js,arr,arrlen(arr)*sizeof(*arr)); - arrfree(arr); -*/ ) struct rtree_each @@ -7897,6 +7969,11 @@ JSValue js_imgui_use(JSContext *js); #define MISTLINE(NAME) (ModuleEntry){#NAME, js_##NAME##_use} +void ffi_setup() +{ + +} + void ffi_load(JSContext *js, int argc, char **argv) { arrput(module_registry, MISTLINE(io)); arrput(module_registry, MISTLINE(os)); @@ -8079,8 +8156,6 @@ void ffi_load(JSContext *js, int argc, char **argv) { fill_event_atoms(js); - global_js = js; - signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGSEGV, signal_handler); diff --git a/source/qjs_nota.c b/source/qjs_nota.c index 5245b507..911d41b4 100755 --- a/source/qjs_nota.c +++ b/source/qjs_nota.c @@ -231,6 +231,40 @@ static void nota_encode_value(NotaEncodeContext *enc, JSValueConst val) } } +void *value2nota(JSContext *ctx, JSValue v) +{ + NotaEncodeContext enc_s, *enc = &enc_s; + enc->ctx = ctx; + enc->visitedStack = JS_NewArray(ctx); // empty array initially + enc->cycle = 0; + + nota_buffer_init(&enc->nb, 128); + + nota_encode_value(enc, argv[0]); + + if (enc->cycle) { + JS_FreeValue(ctx, enc->visitedStack); + nota_buffer_free(&enc->nb); + return NULL; + } + + JS_FreeValue(ctx, enc->visitedStack); + + void* dataPtr = enc->nb.data; // pointer to the raw data + enc->nb.data = NULL; + nota_buffer_free(&enc->nb); + + return dataPtr; +} + +JSValue nota2value(JSContext *js, char *nota) +{ + if (!nota) return JS_UNDEFINED; + JSValue ret; + js_do_nota_decode(js, &ret, nota); + return ret; +} + static JSValue js_nota_encode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { if (argc < 1) diff --git a/source/qjs_nota.h b/source/qjs_nota.h index 85c14822..fd171530 100644 --- a/source/qjs_nota.h +++ b/source/qjs_nota.h @@ -5,4 +5,7 @@ JSValue js_nota_use(JSContext*); -#endif \ No newline at end of file +void *value2nota(JSContext*, JSValue); +JSValue nota2value(JSContext*, void*); + +#endif diff --git a/source/script.c b/source/script.c index 4399f665..99558cb8 100644 --- a/source/script.c +++ b/source/script.c @@ -22,12 +22,8 @@ #include "physfs.h" -static JSContext *js = NULL; -static JSRuntime *rt = NULL; - -JSContext *global_js = NULL; - -JSValue on_exception; +SDL_TLSID on_exception = {0}; +SDL_TLSID js_id = {0}; #define ENGINE "scripts/core/engine.js" @@ -62,6 +58,8 @@ static size_t js_tracy_malloc_usable_size(const void *ptr) #endif } +void tls_free(void *data) { free(data); } + static void *js_tracy_malloc(JSMallocState *s, size_t size) { void *ptr; @@ -139,14 +137,15 @@ static const JSMallocFunctions tracy_malloc_funcs = { #endif - void script_startup(int argc, char **argv) { + JSRuntime *rt; #ifdef TRACY_ENABLE rt = JS_NewRuntime2(&tracy_malloc_funcs, NULL); #else rt = JS_NewRuntime(); #endif - js = JS_NewContextRaw(rt); + JSContext *js = JS_NewContextRaw(rt); + SDL_SetTLS(&js_id, js, NULL); JS_AddIntrinsicBaseObjects(js); JS_AddIntrinsicEval(js); JS_AddIntrinsicRegExp(js); @@ -159,7 +158,9 @@ void script_startup(int argc, char **argv) { JS_AddIntrinsicOperators(js); JS_EnableBignumExt(js, 1); - on_exception = JS_UNDEFINED; + JSValue *onexp = malloc(sizeof(JSValue)); + *onexp = JS_UNDEFINED; + SDL_SetTLS(&on_exception, onexp, tls_free); ffi_load(js, argc, argv); @@ -179,12 +180,13 @@ void script_startup(int argc, char **argv) { free(eng); } -void script_stop() +void script_stop(JSContext *js, JSRuntime *rt) { return; + JSValue *onexp = SDL_GetTLS(&on_exception); + JS_FreeValue(js,*onexp); JS_FreeContext(js); JS_FreeRuntime(rt); - JS_FreeValue(js,on_exception); rt = NULL; js = NULL; @@ -196,10 +198,12 @@ void uncaught_exception(JSContext *js, JSValue v) JS_FreeValue(js,v); return; } + + JSValue *onexp = SDL_GetTLS(&on_exception); - if (!JS_IsUndefined(on_exception)) { + if (!JS_IsUndefined(*onexp)) { JSValue ex = JS_GetException(js); - JSValue ret = JS_Call(js, on_exception, JS_UNDEFINED, 1, &ex); + JSValue ret = JS_Call(js, *onexp, JS_UNDEFINED, 1, &ex); JS_FreeValue(js,ret); JS_FreeValue(js,ex); } else { @@ -219,6 +223,7 @@ void uncaught_exception(JSContext *js, JSValue v) void script_evalf(const char *format, ...) { + JSContext *js = SDL_GetTLS(&js_id); JSValue obj; va_list args; va_start(args, format); diff --git a/source/script.h b/source/script.h index 85504702..cac37e9f 100644 --- a/source/script.h +++ b/source/script.h @@ -2,8 +2,9 @@ #define SCRIPT_H #include "quickjs.h" +#include -extern JSValue on_exception; +extern SDL_TLSID on_exception; void script_startup(); void script_stop(); @@ -11,6 +12,5 @@ void script_stop(); void script_evalf(const char *format, ...); JSValue script_eval(JSContext *js, const char *file, const char *script); void uncaught_exception(JSContext *js, JSValue v); -extern JSContext *global_js; #endif diff --git a/source/transform.c b/source/transform.c index 8302b093..1239d73b 100644 --- a/source/transform.c +++ b/source/transform.c @@ -39,7 +39,7 @@ void transform_free(JSRuntime *rt, transform *t) { if (dirties[i] == t) arrdelswap(dirties, i); } -void transform_clean(transform *t) +void transform_clean(JSContext *js, transform *t) { if (!t->dirty) return; t->dirty = 0; @@ -51,19 +51,19 @@ void transform_clean(transform *t) for (int i = 0; i < arrlen(t->children); i++) { t->children[i]->dirty = 1; - transform_clean(t->children[i]); + transform_clean(js, t->children[i]); } if (!JS_IsUndefined(t->change_hook)) { - JSValue ret = JS_Call(global_js, t->change_hook, JS_DupValue(global_js,t->self), 0, NULL); - JS_FreeValue(global_js,ret); + JSValue ret = JS_Call(js, t->change_hook, JS_DupValue(js,t->self), 0, NULL); + JS_FreeValue(js,ret); } } -void clean_all() +void clean_all(JSContext *js) { for (int i = 0; i < arrlen(dirties); i++) - transform_clean(dirties[i]); + transform_clean(js, dirties[i]); arrsetlen(dirties,0); } diff --git a/source/transform.h b/source/transform.h index 42026fef..071fad02 100644 --- a/source/transform.h +++ b/source/transform.h @@ -21,7 +21,7 @@ typedef struct transform { JSValue change_hook; } transform; -void clean_all(); +void clean_all(JSContext *js); transform *make_transform(); void transform_free(JSRuntime *rt,transform *t); diff --git a/tests/portal.js b/tests/portal.js index df3644ab..69152c63 100644 --- a/tests/portal.js +++ b/tests/portal.js @@ -4,6 +4,7 @@ var password = "abc123" $_.portal(e => { console.log(`got message with password ${e.password}`) + console.log(json.encode(e)) if (e.password !== password) throw new Error("Password does not match.");