ucode: add patches to improve exception handling for ubus/uloop
Add API to allow setting an exception handler for user provided callbacks Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
		| @@ -0,0 +1,217 @@ | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Wed, 11 Jun 2025 18:40:10 +0200 | ||||
| Subject: [PATCH] ubus: add exception_handler_set function | ||||
|  | ||||
| This allows calling the provided handler on exceptions, avoiding the | ||||
| existing behavior of calling uloop_end(). | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| --- | ||||
|  | ||||
| --- a/lib/ubus.c | ||||
| +++ b/lib/ubus.c | ||||
| @@ -573,6 +573,40 @@ uc_ubus_call_cb(struct ubus_request *req | ||||
|  } | ||||
|   | ||||
|  static void | ||||
| +uc_ubus_vm_handle_exception(uc_vm_t *vm) | ||||
| +{ | ||||
| +	uc_value_t *exh, *val; | ||||
| + | ||||
| +	exh = uc_vm_registry_get(vm, "ubus.ex_handler"); | ||||
| +	if (!ucv_is_callable(exh)) | ||||
| +		goto error; | ||||
| + | ||||
| +	val = uc_vm_exception_value(vm); | ||||
| +	uc_vm_stack_push(vm, ucv_get(exh)); | ||||
| +	uc_vm_stack_push(vm, ucv_get(val)); | ||||
| + | ||||
| +	if (uc_vm_call(vm, false, 1) != EXCEPTION_NONE) | ||||
| +		goto error; | ||||
| + | ||||
| +	ucv_put(uc_vm_stack_pop(vm)); | ||||
| +	return; | ||||
| + | ||||
| +error: | ||||
| +	uloop_end(); | ||||
| +} | ||||
| + | ||||
| +static bool | ||||
| +uc_ubus_vm_call(uc_vm_t *vm, bool mcall, size_t nargs) | ||||
| +{ | ||||
| +	if (uc_vm_call(vm, mcall, nargs) == EXCEPTION_NONE) | ||||
| +		return true; | ||||
| + | ||||
| +	uc_ubus_vm_handle_exception(vm); | ||||
| + | ||||
| +	return false; | ||||
| +} | ||||
| + | ||||
| +static void | ||||
|  uc_ubus_call_user_cb(uc_ubus_deferred_t *defer, int ret, uc_value_t *reply) | ||||
|  { | ||||
|  	uc_value_t *this = ucv_get(defer->res); | ||||
| @@ -587,7 +621,7 @@ uc_ubus_call_user_cb(uc_ubus_deferred_t | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(ret)); | ||||
|  		uc_vm_stack_push(vm, ucv_get(reply)); | ||||
|   | ||||
| -		if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(vm, true, 2)) | ||||
|  			ucv_put(uc_vm_stack_pop(vm)); | ||||
|  	} | ||||
|   | ||||
| @@ -623,10 +657,8 @@ uc_ubus_call_data_user_cb(struct ubus_re | ||||
|  		uc_vm_stack_push(vm, ucv_get(func)); | ||||
|  		uc_vm_stack_push(vm, ucv_get(reply)); | ||||
|   | ||||
| -		if (uc_vm_call(vm, true, 1) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(vm, true, 1)) | ||||
|  			ucv_put(uc_vm_stack_pop(vm)); | ||||
| -		else | ||||
| -			uloop_end(); | ||||
|  	} | ||||
|  } | ||||
|   | ||||
| @@ -645,10 +677,8 @@ uc_ubus_call_fd_cb(struct ubus_request * | ||||
|  		uc_vm_stack_push(vm, ucv_get(func)); | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(fd)); | ||||
|   | ||||
| -		if (uc_vm_call(vm, true, 1) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(vm, true, 1)) | ||||
|  			ucv_put(uc_vm_stack_pop(vm)); | ||||
| -		else | ||||
| -			uloop_end(); | ||||
|  	} | ||||
|  } | ||||
|   | ||||
| @@ -927,10 +957,8 @@ uc_ubus_defer_common(uc_vm_t *vm, uc_ubu | ||||
|  		uc_vm_stack_push(vm, ucv_get(replycb)); | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(rv)); | ||||
|   | ||||
| -		if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(vm, false, 1)) | ||||
|  			ucv_put(uc_vm_stack_pop(vm)); | ||||
| -		else | ||||
| -			uloop_end(); | ||||
|   | ||||
|  		ucv_put(res->res); | ||||
|  	} | ||||
| @@ -1199,10 +1227,8 @@ uc_ubus_object_notify_data_cb(struct ubu | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(type)); | ||||
|  		uc_vm_stack_push(vm, blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true)); | ||||
|   | ||||
| -		if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(vm, true, 2)) | ||||
|  			ucv_put(uc_vm_stack_pop(vm)); | ||||
| -		else | ||||
| -			uloop_end(); | ||||
|  	} | ||||
|  } | ||||
|   | ||||
| @@ -1222,10 +1248,8 @@ uc_ubus_object_notify_status_cb(struct u | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(idx)); | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(ret)); | ||||
|   | ||||
| -		if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(vm, true, 2)) | ||||
|  			ucv_put(uc_vm_stack_pop(vm)); | ||||
| -		else | ||||
| -			uloop_end(); | ||||
|  	} | ||||
|  } | ||||
|   | ||||
| @@ -1245,10 +1269,8 @@ uc_ubus_object_notify_complete_cb(struct | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(idx)); | ||||
|  		uc_vm_stack_push(vm, ucv_int64_new(ret)); | ||||
|   | ||||
| -		if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(vm, true, 2)) | ||||
|  			ucv_put(uc_vm_stack_pop(vm)); | ||||
| -		else | ||||
| -			uloop_end(); | ||||
|  	} | ||||
|   | ||||
|  	notifyctx->complete = true; | ||||
| @@ -1579,7 +1601,7 @@ uc_ubus_handle_reply_common(struct ubus_ | ||||
|  	/* treat other exceptions as fatal and halt uloop */ | ||||
|  	default: | ||||
|  		uc_ubus_request_finish_common(callctx, UBUS_STATUS_UNKNOWN_ERROR); | ||||
| -		uloop_end(); | ||||
| +		uc_ubus_vm_handle_exception(vm); | ||||
|  		break; | ||||
|  	} | ||||
|   | ||||
| @@ -1638,10 +1660,8 @@ uc_ubus_object_subscribe_cb(struct ubus_ | ||||
|  	uc_vm_stack_push(uuobj->vm, ucv_get(uuobj->res)); | ||||
|  	uc_vm_stack_push(uuobj->vm, ucv_get(func)); | ||||
|   | ||||
| -	if (uc_vm_call(uuobj->vm, true, 0) == EXCEPTION_NONE) | ||||
| +	if (uc_ubus_vm_call(uuobj->vm, true, 0)) | ||||
|  		ucv_put(uc_vm_stack_pop(uuobj->vm)); | ||||
| -	else | ||||
| -		uloop_end(); | ||||
|  } | ||||
|   | ||||
|  static bool | ||||
| @@ -1917,10 +1937,8 @@ uc_ubus_listener_cb(struct ubus_context | ||||
|  	uc_vm_stack_push(vm, ucv_string_new(type)); | ||||
|  	uc_vm_stack_push(vm, blob_array_to_ucv(vm, blob_data(msg), blob_len(msg), true)); | ||||
|   | ||||
| -	if (uc_vm_call(vm, true, 2) == EXCEPTION_NONE) | ||||
| +	if (uc_ubus_vm_call(vm, true, 2)) | ||||
|  		ucv_put(uc_vm_stack_pop(vm)); | ||||
| -	else | ||||
| -		uloop_end(); | ||||
|  } | ||||
|   | ||||
|  static uc_value_t * | ||||
| @@ -2040,10 +2058,8 @@ uc_ubus_subscriber_remove_cb(struct ubus | ||||
|  	uc_vm_stack_push(vm, ucv_get(func)); | ||||
|  	uc_vm_stack_push(vm, ucv_uint64_new(id)); | ||||
|   | ||||
| -	if (uc_vm_call(vm, true, 1) == EXCEPTION_NONE) | ||||
| +	if (uc_ubus_vm_call(vm, true, 1)) | ||||
|  		ucv_put(uc_vm_stack_pop(vm)); | ||||
| -	else | ||||
| -		uloop_end(); | ||||
|  } | ||||
|   | ||||
|  static uc_value_t * | ||||
| @@ -2334,10 +2350,8 @@ uc_ubus_channel_disconnect_cb(struct ubu | ||||
|  		uc_vm_stack_push(c->vm, ucv_get(c->res)); | ||||
|  		uc_vm_stack_push(c->vm, ucv_get(func)); | ||||
|   | ||||
| -		if (uc_vm_call(c->vm, true, 0) == EXCEPTION_NONE) | ||||
| +		if (uc_ubus_vm_call(c->vm, true, 0)) | ||||
|  			ucv_put(uc_vm_stack_pop(c->vm)); | ||||
| -		else | ||||
| -			uloop_end(); | ||||
|  	} | ||||
|   | ||||
|  	blob_buf_free(&c->buf); | ||||
| @@ -2438,10 +2452,25 @@ uc_ubus_channel_connect(uc_vm_t *vm, siz | ||||
|  } | ||||
|   | ||||
|   | ||||
| +static uc_value_t * | ||||
| +uc_ubus_exception_handler_set(uc_vm_t *vm, size_t nargs) | ||||
| +{ | ||||
| +	uc_value_t *arg = uc_fn_arg(0); | ||||
| + | ||||
| +	if (arg && !ucv_is_callable(arg)) | ||||
| +		return NULL; | ||||
| + | ||||
| +	uc_vm_registry_set(vm, "ubus.ex_handler", ucv_get(arg)); | ||||
| + | ||||
| +	return ucv_boolean_new(true); | ||||
| +} | ||||
| + | ||||
| + | ||||
|  static const uc_function_list_t global_fns[] = { | ||||
|  	{ "error",			uc_ubus_error }, | ||||
|  	{ "connect",		uc_ubus_connect }, | ||||
|  	{ "open_channel",	uc_ubus_channel_connect }, | ||||
| +	{ "exception_handler_set", uc_ubus_exception_handler_set }, | ||||
|  }; | ||||
|   | ||||
|  static const uc_function_list_t conn_fns[] = { | ||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau