From efeb578065523b2882d71d91f38cd63115928b7a Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 19 Oct 2024 16:06:09 +0200 Subject: types, vm: refactor usage of global variables Introduce an extensible private TLS context structure and use it within libucode to store global state such as active object iterators. This allows using libucode concurrently in multiple threads without unintentionally sharing global state among them. Also adjust the signal dispatching setup logic in `uc_vm_init()` to only enable signal handling if no other VM in the same thread already handles signals. Suggested-by: Isaac de Wolff [squash commits, move signal handler vm pointer and object iterator list into common extensible TLS context, whitespace and naming adjustments, extended signal setup logic] Signed-off-by: Jo-Philipp Wich --- vm.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'vm.c') diff --git a/vm.c b/vm.c index 9488288..ce9c217 100644 --- a/vm.c +++ b/vm.c @@ -145,37 +145,44 @@ uc_vm_alloc_global_scope(uc_vm_t *vm) static void uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex); -static uc_vm_t *signal_handler_vm; - static void uc_vm_signal_handler(int sig) { - assert(signal_handler_vm); + uc_vm_t *vm = uc_thread_context_get()->signal_handler_vm; + + assert(vm); - uc_vm_signal_raise(signal_handler_vm, sig); + uc_vm_signal_raise(vm, sig); } static void uc_vm_signal_handlers_setup(uc_vm_t *vm) { + uc_thread_context_t *tctx; + memset(&vm->signal, 0, sizeof(vm->signal)); vm->signal.sigpipe[0] = -1; vm->signal.sigpipe[1] = -1; - if (!vm->config->setup_signal_handlers) + if (vm->config->setup_signal_handlers) return; - if (pipe2(vm->signal.sigpipe, O_CLOEXEC | O_NONBLOCK) != 0) + tctx = uc_thread_context_get(); + + if (tctx->signal_handler_vm) return; - signal_handler_vm = vm; + if (pipe2(vm->signal.sigpipe, O_CLOEXEC | O_NONBLOCK) != 0) + return; vm->signal.handler = ucv_array_new_length(vm, UC_SYSTEM_SIGNAL_COUNT); vm->signal.sa.sa_handler = uc_vm_signal_handler; vm->signal.sa.sa_flags = SA_RESTART | SA_ONSTACK; sigemptyset(&vm->signal.sa.sa_mask); + + tctx->signal_handler_vm = vm; } void uc_vm_init(uc_vm_t *vm, uc_parse_config_t *config) @@ -778,11 +785,10 @@ uc_vm_exception_tostring(uc_vm_t *vm, size_t nargs) return message ? ucv_get(message) : ucv_string_new("Exception"); } -static uc_value_t *exception_prototype = NULL; - static uc_value_t * uc_vm_exception_new(uc_vm_t *vm, uc_exception_type_t type, const char *message, uc_value_t *stacktrace) { + uc_value_t *exception_prototype = uc_vm_registry_get(vm, "vm.exception.proto"); uc_value_t *exo; if (exception_prototype == NULL) { @@ -790,6 +796,8 @@ uc_vm_exception_new(uc_vm_t *vm, uc_exception_type_t type, const char *message, ucv_object_add(exception_prototype, "tostring", ucv_cfunction_new("tostring", uc_vm_exception_tostring)); + + uc_vm_registry_set(vm, "vm.exception.proto", exception_prototype); } exo = ucv_object_new(vm); @@ -2222,7 +2230,7 @@ uc_vm_object_iterator_next(uc_vm_t *vm, uc_vm_insn_t insn, iter->table = obj->table; iter->u.pos = obj->table->head; - uc_list_insert(&uc_object_iterators, &iter->list); + uc_list_insert(&uc_thread_context_get()->object_iterators, &iter->list); } else if (ucv_type(k) == UC_RESOURCE && res->type == &uc_vm_object_iterator_type && res->data != NULL) { -- cgit v1.2.3 From f9d2faf67de643911f7b9bcdbab1ab2d7d108dff Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 2 Dec 2024 12:56:19 +0100 Subject: vm: reset signals when freeing VM When invoking `uc_vm_free()` on a VM with enabled `.setup_signal_handlers` configuration, reset system signal handlers back to their default actions. Signed-off-by: Jo-Philipp Wich --- vm.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'vm.c') diff --git a/vm.c b/vm.c index ce9c217..1c40307 100644 --- a/vm.c +++ b/vm.c @@ -185,6 +185,26 @@ uc_vm_signal_handlers_setup(uc_vm_t *vm) tctx->signal_handler_vm = vm; } +static void +uc_vm_signal_handlers_reset(uc_vm_t *vm) +{ + uc_thread_context_t *tctx = uc_thread_context_get(); + struct sigaction sa = { 0 }; + size_t signo; + + if (vm != tctx->signal_handler_vm) + return; + + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + + for (signo = 0; signo < ucv_array_length(vm->signal.handler); signo++) + if (ucv_is_callable(ucv_array_get(vm->signal.handler, signo))) + sigaction(signo, &sa, NULL); + + tctx->signal_handler_vm = NULL; +} + void uc_vm_init(uc_vm_t *vm, uc_parse_config_t *config) { vm->exception.type = EXCEPTION_NONE; @@ -217,6 +237,8 @@ void uc_vm_free(uc_vm_t *vm) uc_upvalref_t *ref; size_t i; + uc_vm_signal_handlers_reset(vm); + ucv_put(vm->exception.stacktrace); free(vm->exception.message); -- cgit v1.2.3