From: Felix Fietkau Date: Wed, 11 Jun 2025 18:31:39 +0200 Subject: [PATCH] uloop: add guard() function This allows calling the provided handler on exceptions, avoiding the existing behavior of calling uloop_end(). Signed-off-by: Felix Fietkau --- --- a/lib/uloop.c +++ b/lib/uloop.c @@ -114,27 +114,48 @@ uc_uloop_cb_free(uc_uloop_cb_t *cb) } static bool +uc_uloop_vm_call(uc_vm_t *vm, bool mcall, size_t nargs) +{ + uc_value_t *exh, *val; + + if (uc_vm_call(vm, mcall, nargs) == EXCEPTION_NONE) + return true; + + exh = uc_vm_registry_get(vm, "uloop.ex_handler"); + if (!ucv_is_callable(exh)) + goto error; + + val = uc_vm_exception_object(vm); + uc_vm_stack_push(vm, ucv_get(exh)); + uc_vm_stack_push(vm, val); + + if (uc_vm_call(vm, false, 1) != EXCEPTION_NONE) + goto error; + + ucv_put(uc_vm_stack_pop(vm)); + + return false; + +error: + uloop_end(); + return false; +} + +static void uc_uloop_cb_invoke(uc_uloop_cb_t *cb, uc_value_t *arg) { uc_vm_t *vm = cb->vm; uc_value_t *func = ucv_resource_value_get(cb->obj, 0); if (!ucv_is_callable(func)) - return false; + return; uc_vm_stack_push(vm, ucv_get(cb->obj)); uc_vm_stack_push(vm, ucv_get(func)); uc_vm_stack_push(vm, ucv_get(arg)); - if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { - uloop_end(); - - return false; - } - - ucv_put(uc_vm_stack_pop(vm)); - - return true; + if (uc_uloop_vm_call(vm, true, 1)) + ucv_put(uc_vm_stack_pop(vm)); } /** @@ -1550,11 +1571,8 @@ uc_uloop_task_output_cb(struct uloop_fd uc_vm_stack_push(vm, ucv_get(obj)); uc_vm_stack_push(vm, ucv_get(task->input_cb)); - if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE) { - uloop_end(); - + if (!uc_uloop_vm_call(vm, true, 0)) return; - } msg = uc_vm_stack_pop(vm); uc_uloop_pipe_send_common(vm, msg, task->input_fd); @@ -1572,14 +1590,10 @@ uc_uloop_task_output_cb(struct uloop_fd uc_vm_stack_push(vm, ucv_get(task->output_cb)); uc_vm_stack_push(vm, msg); - if (uc_vm_call(vm, true, 1) == EXCEPTION_NONE) { - ucv_put(uc_vm_stack_pop(vm)); - } - else { - uloop_end(); - + if (!uc_uloop_vm_call(vm, true, 1)) return; - } + + ucv_put(uc_vm_stack_pop(vm)); } else { ucv_put(msg); @@ -1703,7 +1717,7 @@ uc_uloop_task(uc_vm_t *vm, size_t nargs) uc_vm_stack_push(vm, func); uc_vm_stack_push(vm, ucv_get(p)); - if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE) { + if (uc_uloop_vm_call(vm, false, 1)) { res = uc_vm_stack_pop(vm); uc_uloop_pipe_send_common(vm, res, tpipe->output); ucv_put(res); @@ -2167,6 +2181,22 @@ uc_uloop_signal(uc_vm_t *vm, size_t narg } #endif +static uc_value_t * +uc_uloop_guard(uc_vm_t *vm, size_t nargs) +{ + uc_value_t *arg = uc_fn_arg(0); + + if (!nargs) + return ucv_get(uc_vm_registry_get(vm, "uloop.ex_handler")); + + if (arg && !ucv_is_callable(arg)) + return NULL; + + uc_vm_registry_set(vm, "uloop.ex_handler", ucv_get(arg)); + + return ucv_boolean_new(true); +} + static const uc_function_list_t timer_fns[] = { { "set", uc_uloop_timer_set }, @@ -2233,6 +2263,7 @@ static const uc_function_list_t global_f #ifdef HAVE_ULOOP_SIGNAL { "signal", uc_uloop_signal }, #endif + { "guard", uc_uloop_guard }, };