fix actor working
This commit is contained in:
@@ -344,14 +344,17 @@ void script_startup(cell_rt *prt)
|
||||
tmp = js_core_json_use(js);
|
||||
JS_SetPropertyStr(js, env_ref.val, "json", tmp);
|
||||
|
||||
crt->actor_sym_ref.val = JS_NewObject(js);
|
||||
crt->actor_sym_ref.val = JS_NewString(js, "__ACTOR__");
|
||||
JS_SetActorSym(js, JS_DupValue(js, crt->actor_sym_ref.val));
|
||||
JS_SetPropertyStr(js, env_ref.val, "actorsym", JS_DupValue(js, crt->actor_sym_ref.val));
|
||||
|
||||
// Always set init (even if null)
|
||||
if (crt->init_wota) {
|
||||
tmp = wota2value(js, crt->init_wota);
|
||||
JS_SetPropertyStr(js, env_ref.val, "init", tmp);
|
||||
JSGCRef init_ref;
|
||||
JS_PushGCRef(js, &init_ref);
|
||||
init_ref.val = wota2value(js, crt->init_wota);
|
||||
JS_SetPropertyStr(js, env_ref.val, "init", init_ref.val);
|
||||
JS_PopGCRef(js, &init_ref);
|
||||
free(crt->init_wota);
|
||||
crt->init_wota = NULL;
|
||||
} else {
|
||||
@@ -556,7 +559,7 @@ int cell_init(int argc, char **argv)
|
||||
cli_rt->on_exception_ref.val = JS_NULL;
|
||||
cli_rt->message_handle_ref.val = JS_NULL;
|
||||
cli_rt->unneeded_ref.val = JS_NULL;
|
||||
cli_rt->actor_sym_ref.val = JS_NewObject(ctx);
|
||||
cli_rt->actor_sym_ref.val = JS_NewString(ctx, "__ACTOR__");
|
||||
JS_SetActorSym(ctx, JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
|
||||
|
||||
root_cell = cli_rt;
|
||||
|
||||
@@ -10,6 +10,8 @@ JSC_CCALL(os_createactor,
|
||||
return JS_ThrowInternalError(js, "Can't start a new actor while disrupting.");
|
||||
|
||||
void *startup = value2wota(js, argv[0], JS_NULL, NULL);
|
||||
if (!startup)
|
||||
return JS_ThrowInternalError(js, "Failed to encode startup data");
|
||||
create_actor(startup);
|
||||
)
|
||||
|
||||
@@ -21,46 +23,32 @@ JSC_CCALL(os_mailbox_push,
|
||||
int exist = actor_exists(id);
|
||||
|
||||
if (!exist) {
|
||||
JS_FreeCString(js,id);
|
||||
JS_FreeCString(js, id);
|
||||
return JS_ThrowInternalError(js, "No mailbox found for given ID");
|
||||
}
|
||||
|
||||
JS_FreeCString(js,id);
|
||||
|
||||
/* JSValue sys = JS_GetPropertyStr(js, argv[1], "__SYSTEM__");
|
||||
if (!JS_IsNull(sys)) {
|
||||
const char *k = JS_ToCString(js,sys);
|
||||
int stop = 0;
|
||||
if (strcmp(k, "stop") == 0) {
|
||||
stop = 1;
|
||||
actor_disrupt(target);
|
||||
}
|
||||
JS_FreeValue(js,sys);
|
||||
JS_FreeCString(js,k);
|
||||
|
||||
if (stop) return JS_NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
size_t size;
|
||||
void *data = js_get_blob_data(js, &size, argv[1]);
|
||||
if (data == (void*)-1) {
|
||||
JS_FreeCString(js, id);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (size == 0) {
|
||||
JS_FreeCString(js, id);
|
||||
return JS_ThrowInternalError(js, "No data present in blob");
|
||||
}
|
||||
|
||||
// Create a new blob and copy the data
|
||||
blob *msg_blob = blob_new(size * 8); // Convert bytes to bits
|
||||
|
||||
blob *msg_blob = blob_new(size * 8);
|
||||
if (!msg_blob) {
|
||||
JS_FreeCString(js, id);
|
||||
return JS_ThrowInternalError(js, "Could not allocate blob");
|
||||
}
|
||||
|
||||
// Copy data to blob
|
||||
|
||||
blob_write_bytes(msg_blob, data, size);
|
||||
blob_make_stone(msg_blob); // Make it immutable
|
||||
|
||||
blob_make_stone(msg_blob);
|
||||
|
||||
const char *err = send_message(id, msg_blob);
|
||||
JS_FreeCString(js, id);
|
||||
if (err) {
|
||||
blob_destroy(msg_blob);
|
||||
return JS_ThrowInternalError(js, "Could not send message: %s", err);
|
||||
|
||||
@@ -11342,11 +11342,16 @@ static char *js_do_nota_decode (JSContext *js, JSValue *tmp, char *nota, JSValue
|
||||
nota = nota_read_record (&n, nota);
|
||||
*tmp = JS_NewObject (js);
|
||||
for (int i = 0; i < n; i++) {
|
||||
JSGCRef prop_key_ref, sub_val_ref;
|
||||
JS_PushGCRef (js, &prop_key_ref);
|
||||
JS_PushGCRef (js, &sub_val_ref);
|
||||
nota = nota_read_text (&str, nota);
|
||||
JSValue prop_key = JS_NewString (js, str);
|
||||
nota = js_do_nota_decode (js, &ret2, nota, *tmp, prop_key, reviver);
|
||||
JS_SetPropertyStr (js, *tmp, str, ret2);
|
||||
JS_FreeValue (js, prop_key);
|
||||
prop_key_ref.val = JS_NewString (js, str);
|
||||
sub_val_ref.val = JS_NULL;
|
||||
nota = js_do_nota_decode (js, &sub_val_ref.val, nota, *tmp, prop_key_ref.val, reviver);
|
||||
JS_SetPropertyStr (js, *tmp, str, sub_val_ref.val);
|
||||
JS_PopGCRef (js, &sub_val_ref);
|
||||
JS_PopGCRef (js, &prop_key_ref);
|
||||
sys_free (str);
|
||||
}
|
||||
break;
|
||||
@@ -11357,16 +11362,18 @@ static char *js_do_nota_decode (JSContext *js, JSValue *tmp, char *nota, JSValue
|
||||
case NOTA_SYM:
|
||||
nota = nota_read_sym (&b, nota);
|
||||
if (b == NOTA_PRIVATE) {
|
||||
JSGCRef inner_ref;
|
||||
JSGCRef inner_ref, obj_ref2;
|
||||
JS_PushGCRef (js, &inner_ref);
|
||||
JS_PushGCRef (js, &obj_ref2);
|
||||
inner_ref.val = JS_NULL;
|
||||
nota = js_do_nota_decode (js, &inner_ref.val, nota, holder, JS_NULL, reviver);
|
||||
JSValue obj = JS_NewObject (js);
|
||||
obj_ref2.val = JS_NewObject (js);
|
||||
if (!JS_IsNull (js->actor_sym))
|
||||
JS_SetPropertyKey (js, obj, js->actor_sym, inner_ref.val);
|
||||
JS_CellStone (js, obj);
|
||||
JS_SetPropertyKey (js, obj_ref2.val, js->actor_sym, inner_ref.val);
|
||||
JS_CellStone (js, obj_ref2.val);
|
||||
*tmp = obj_ref2.val;
|
||||
JS_PopGCRef (js, &obj_ref2);
|
||||
JS_PopGCRef (js, &inner_ref);
|
||||
*tmp = obj;
|
||||
} else {
|
||||
switch (b) {
|
||||
case NOTA_NULL: *tmp = JS_NULL; break;
|
||||
@@ -11771,15 +11778,21 @@ static void encode_object_properties (WotaEncodeContext *enc, JSValueConst val,
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < plen; i++) {
|
||||
JSValue key = JS_GetPropertyNumber (ctx, keys_ref.val, i);
|
||||
JSValue prop_val = JS_GetProperty (ctx, val_ref.val, key);
|
||||
/* Store key into its GCRef slot immediately so it's rooted before
|
||||
JS_GetProperty can trigger GC and relocate the string. */
|
||||
key_refs[i].val = JS_GetPropertyNumber (ctx, keys_ref.val, i);
|
||||
JSValue prop_val = JS_GetProperty (ctx, val_ref.val, key_refs[i].val);
|
||||
if (!JS_IsFunction (prop_val)) {
|
||||
key_refs[non_function_count].val = key;
|
||||
if (i != non_function_count) {
|
||||
key_refs[non_function_count].val = key_refs[i].val;
|
||||
key_refs[i].val = JS_NULL;
|
||||
}
|
||||
prop_refs[non_function_count].val = prop_val;
|
||||
non_function_count++;
|
||||
} else {
|
||||
JS_FreeValue (ctx, prop_val);
|
||||
JS_FreeValue (ctx, key);
|
||||
JS_FreeValue (ctx, key_refs[i].val);
|
||||
key_refs[i].val = JS_NULL;
|
||||
}
|
||||
}
|
||||
JS_FreeValue (ctx, keys_ref.val);
|
||||
@@ -11844,6 +11857,13 @@ static void wota_encode_value (WotaEncodeContext *enc, JSValueConst val, JSValue
|
||||
wota_write_sym (&enc->wb, WOTA_NULL);
|
||||
break;
|
||||
case JS_TAG_PTR: {
|
||||
if (JS_IsText (replaced)) {
|
||||
size_t plen;
|
||||
const char *str = JS_ToCStringLen (ctx, &plen, replaced);
|
||||
wota_write_text_len (&enc->wb, str ? str : "", str ? plen : 0);
|
||||
JS_FreeCString (ctx, str);
|
||||
break;
|
||||
}
|
||||
if (js_is_blob (ctx, replaced)) {
|
||||
size_t buf_len;
|
||||
void *buf_data = js_get_blob_data (ctx, &buf_len, replaced);
|
||||
@@ -11936,16 +11956,18 @@ static char *decode_wota_value (JSContext *ctx, char *data_ptr, JSValue *out_val
|
||||
int scode;
|
||||
data_ptr = wota_read_sym (&scode, data_ptr);
|
||||
if (scode == WOTA_PRIVATE) {
|
||||
JSGCRef inner_ref;
|
||||
JSGCRef inner_ref, obj_ref2;
|
||||
JS_PushGCRef (ctx, &inner_ref);
|
||||
JS_PushGCRef (ctx, &obj_ref2);
|
||||
inner_ref.val = JS_NULL;
|
||||
data_ptr = decode_wota_value (ctx, data_ptr, &inner_ref.val, holder, JS_NULL, reviver);
|
||||
JSValue obj = JS_NewObject (ctx);
|
||||
obj_ref2.val = JS_NewObject (ctx);
|
||||
if (!JS_IsNull (ctx->actor_sym))
|
||||
JS_SetPropertyKey (ctx, obj, ctx->actor_sym, inner_ref.val);
|
||||
JS_CellStone (ctx, obj);
|
||||
JS_SetPropertyKey (ctx, obj_ref2.val, ctx->actor_sym, inner_ref.val);
|
||||
JS_CellStone (ctx, obj_ref2.val);
|
||||
*out_val = obj_ref2.val;
|
||||
JS_PopGCRef (ctx, &obj_ref2);
|
||||
JS_PopGCRef (ctx, &inner_ref);
|
||||
*out_val = obj;
|
||||
} else if (scode == WOTA_NULL) *out_val = JS_NULL;
|
||||
else if (scode == WOTA_FALSE) *out_val = JS_NewBool (ctx, 0);
|
||||
else if (scode == WOTA_TRUE) *out_val = JS_NewBool (ctx, 1);
|
||||
@@ -12003,8 +12025,7 @@ static char *decode_wota_value (JSContext *ctx, char *data_ptr, JSValue *out_val
|
||||
prop_key_ref.val = JS_NewStringLen (ctx, tkey, key_len);
|
||||
sub_val_ref.val = JS_NULL;
|
||||
data_ptr = decode_wota_value (ctx, data_ptr, &sub_val_ref.val, obj_ref.val, prop_key_ref.val, reviver);
|
||||
JS_SetProperty (ctx, obj_ref.val, prop_key_ref.val, sub_val_ref.val);
|
||||
JS_FreeValue (ctx, prop_key_ref.val);
|
||||
JS_SetPropertyStr (ctx, obj_ref.val, tkey, sub_val_ref.val);
|
||||
JS_PopGCRef (ctx, &sub_val_ref);
|
||||
JS_PopGCRef (ctx, &prop_key_ref);
|
||||
sys_free (tkey);
|
||||
@@ -12094,12 +12115,18 @@ static JSValue js_wota_decode (JSContext *ctx, JSValueConst this_val, int argc,
|
||||
if (!buf || len == 0) return JS_ThrowTypeError (ctx, "No blob data present");
|
||||
JSValue reviver = (argc > 1 && JS_IsFunction (argv[1])) ? argv[1] : JS_NULL;
|
||||
char *data_ptr = (char *)buf;
|
||||
JSValue result = JS_NULL;
|
||||
JSValue holder = JS_NewObject (ctx);
|
||||
JSValue empty_key = JS_NewString (ctx, "");
|
||||
decode_wota_value (ctx, data_ptr, &result, holder, empty_key, reviver);
|
||||
JS_FreeValue (ctx, empty_key);
|
||||
JS_FreeValue (ctx, holder);
|
||||
JSGCRef result_ref, holder_ref, empty_key_ref;
|
||||
JS_PushGCRef (ctx, &result_ref);
|
||||
JS_PushGCRef (ctx, &holder_ref);
|
||||
JS_PushGCRef (ctx, &empty_key_ref);
|
||||
result_ref.val = JS_NULL;
|
||||
holder_ref.val = JS_NewObject (ctx);
|
||||
empty_key_ref.val = JS_NewString (ctx, "");
|
||||
decode_wota_value (ctx, data_ptr, &result_ref.val, holder_ref.val, empty_key_ref.val, reviver);
|
||||
JSValue result = result_ref.val;
|
||||
JS_PopGCRef (ctx, &empty_key_ref);
|
||||
JS_PopGCRef (ctx, &holder_ref);
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -377,24 +377,33 @@ int actor_exists(const char *id)
|
||||
void set_actor_state(cell_rt *actor)
|
||||
{
|
||||
if (actor->disrupt) {
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "set_actor_state: %s disrupted, freeing\n", actor->name ? actor->name : actor->id);
|
||||
#endif
|
||||
actor_free(actor);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(actor->msg_mutex);
|
||||
|
||||
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "set_actor_state: %s state=%d letters=%ld\n", actor->name ? actor->name : actor->id, actor->state, (long)arrlen(actor->letters));
|
||||
#endif
|
||||
switch(actor->state) {
|
||||
case ACTOR_RUNNING:
|
||||
case ACTOR_READY:
|
||||
if (actor->ar)
|
||||
actor->ar = 0;
|
||||
break;
|
||||
|
||||
|
||||
case ACTOR_IDLE:
|
||||
if (arrlen(actor->letters)) {
|
||||
if (actor->is_quiescent) {
|
||||
actor->is_quiescent = 0;
|
||||
atomic_fetch_sub(&engine.quiescent_count, 1);
|
||||
}
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "set_actor_state: %s IDLE->READY, enqueueing (main=%d)\n", actor->name ? actor->name : actor->id, actor->main_thread_only);
|
||||
#endif
|
||||
actor->state = ACTOR_READY;
|
||||
actor->ar = 0;
|
||||
|
||||
@@ -635,21 +644,26 @@ void actor_turn(cell_rt *actor)
|
||||
if (actor->trace_hook)
|
||||
actor->trace_hook(actor->name, CELL_HOOK_ENTER);
|
||||
|
||||
TAKETURN:
|
||||
|
||||
pthread_mutex_lock(actor->msg_mutex);
|
||||
JSValue result;
|
||||
if (!arrlen(actor->letters)) {
|
||||
int pending = arrlen(actor->letters);
|
||||
if (!pending) {
|
||||
pthread_mutex_unlock(actor->msg_mutex);
|
||||
goto ENDTURN;
|
||||
}
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "actor_turn: %s has %d letters, type=%d\n", actor->name ? actor->name : actor->id, pending, actor->letters[0].type);
|
||||
#endif
|
||||
letter l = actor->letters[0];
|
||||
arrdel(actor->letters, 0); // O(N) but we kept array as requested
|
||||
arrdel(actor->letters, 0);
|
||||
pthread_mutex_unlock(actor->msg_mutex);
|
||||
|
||||
|
||||
if (l.type == LETTER_BLOB) {
|
||||
// Create a JS blob from the C blob
|
||||
size_t size = blob_length(l.blob_data) / 8; // Convert bits to bytes
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "actor_turn BLOB: %s size=%zu, calling message_handle\n", actor->name ? actor->name : actor->id, size);
|
||||
#endif
|
||||
JSValue arg = js_new_blob_stoned_copy(actor->context, (void*)blob_data(l.blob_data), size);
|
||||
blob_destroy(l.blob_data);
|
||||
result = JS_Call(actor->context, actor->message_handle_ref.val, JS_NULL, 1, &arg);
|
||||
@@ -674,11 +688,17 @@ void actor_turn(cell_rt *actor)
|
||||
if (actor->disrupt) {
|
||||
/* Actor must die. Unlock before freeing so actor_free can
|
||||
lock/unlock/destroy the mutex without use-after-free. */
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "actor_turn ENDTURN: %s disrupted, freeing\n", actor->name ? actor->name : actor->id);
|
||||
#endif
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
actor_free(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "actor_turn ENDTURN: %s has %ld letters, calling set_actor_state\n", actor->name ? actor->name : actor->id, (long)arrlen(actor->letters));
|
||||
#endif
|
||||
set_actor_state(actor);
|
||||
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
|
||||
Reference in New Issue
Block a user