better disrupt logging; actor exit on crash
This commit is contained in:
@@ -456,7 +456,7 @@ int cell_init(int argc, char **argv)
|
||||
if (scheduler_actor_count() > 0) {
|
||||
actor_loop();
|
||||
exit_handler();
|
||||
return exit_code;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* No actors spawned — clean up CLI context */
|
||||
|
||||
@@ -2552,7 +2552,7 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
|
||||
}
|
||||
|
||||
/* Type mismatch — disrupt */
|
||||
return JS_EXCEPTION;
|
||||
return JS_ThrowTypeError(ctx, "type mismatch in binary operation");
|
||||
}
|
||||
|
||||
/* Check for interrupt */
|
||||
@@ -3021,6 +3021,8 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
JSValue func_val = frame->slots[base];
|
||||
|
||||
if (!JS_IsFunction(func_val)) {
|
||||
JS_ThrowTypeError(ctx, "not a function");
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
|
||||
@@ -3263,7 +3265,11 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
/* push R(B) onto array R(A) */
|
||||
JSValue arr = frame->slots[a];
|
||||
JSValue val = frame->slots[b];
|
||||
if (!JS_IsArray(arr)) goto disrupt;
|
||||
if (!JS_IsArray(arr)) {
|
||||
JS_ThrowTypeError(ctx, "cannot push to non-array");
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
JSGCRef arr_gc;
|
||||
JS_PushGCRef(ctx, &arr_gc);
|
||||
arr_gc.val = arr;
|
||||
@@ -3278,7 +3284,11 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
case MACH_POP: {
|
||||
/* R(A) = pop last element from array R(B) */
|
||||
JSValue arr = frame->slots[b];
|
||||
if (!JS_IsArray(arr)) goto disrupt;
|
||||
if (!JS_IsArray(arr)) {
|
||||
JS_ThrowTypeError(ctx, "cannot pop from non-array");
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
JSValue val = JS_ArrayPop(ctx, arr);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(val)) goto disrupt;
|
||||
@@ -3353,7 +3363,13 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
break;
|
||||
}
|
||||
if (JS_IsNull(frame->caller)) {
|
||||
fprintf(stderr, "unhandled disruption\n");
|
||||
if (!JS_HasException(ctx)) {
|
||||
/* Bare disrupt with no error message — provide location */
|
||||
const char *fn_name = code->name_cstr ? code->name_cstr : "<anonymous>";
|
||||
fprintf(stderr, "unhandled disruption in %s\n", fn_name);
|
||||
} else {
|
||||
fprintf(stderr, "unhandled disruption\n");
|
||||
}
|
||||
result = JS_Throw(ctx, JS_NULL);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto done;
|
||||
|
||||
@@ -304,6 +304,7 @@ void actor_free(cell_rt *actor)
|
||||
|
||||
int actor_count = lockless_shlen(actors);
|
||||
if (actor_count == 0) {
|
||||
fprintf(stderr, "all actors are dead\n");
|
||||
pthread_mutex_lock(&engine.lock);
|
||||
engine.shutting_down = 1;
|
||||
pthread_cond_broadcast(&engine.wake_cond);
|
||||
@@ -533,7 +534,7 @@ const char *register_actor(const char *id, cell_rt *actor, int mainthread, doubl
|
||||
actor->main_thread_only = mainthread;
|
||||
actor->id = strdup(id);
|
||||
actor->ar_secs = ar;
|
||||
int added = lockless_shput_unique(actors, id, actor);
|
||||
int added = lockless_shput_unique(actors, actor->id, actor);
|
||||
if (!added) {
|
||||
free(actor->id);
|
||||
return "Actor with given ID already exists.";
|
||||
@@ -591,20 +592,22 @@ void actor_turn(cell_rt *actor)
|
||||
arrdel(actor->letters, 0); // O(N) but we kept array as requested
|
||||
pthread_mutex_unlock(actor->msg_mutex);
|
||||
|
||||
if (l.type == LETTER_BLOB) {
|
||||
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
|
||||
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);
|
||||
uncaught_exception(actor->context, result);
|
||||
if (!uncaught_exception(actor->context, result))
|
||||
actor->disrupt = 1;
|
||||
JS_FreeValue(actor->context, arg);
|
||||
} else if (l.type == LETTER_CALLBACK) {
|
||||
result = JS_Call(actor->context, l.callback, JS_NULL, 0, NULL);
|
||||
uncaught_exception(actor->context, result);
|
||||
if (!uncaught_exception(actor->context, result))
|
||||
actor->disrupt = 1;
|
||||
JS_FreeValue(actor->context, l.callback);
|
||||
}
|
||||
|
||||
|
||||
if (actor->disrupt) goto ENDTURN;
|
||||
|
||||
ENDTURN:
|
||||
@@ -612,9 +615,17 @@ void actor_turn(cell_rt *actor)
|
||||
|
||||
if (actor->trace_hook)
|
||||
actor->trace_hook(actor->name, CELL_HOOK_EXIT);
|
||||
|
||||
|
||||
if (actor->disrupt) {
|
||||
/* Actor must die. Unlock before freeing so actor_free can
|
||||
lock/unlock/destroy the mutex without use-after-free. */
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
actor_free(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
set_actor_state(actor);
|
||||
|
||||
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user