diff --git a/include/ucode/types.h b/include/ucode/types.h index bf8b9f25..85c3eb8a 100644 --- a/include/ucode/types.h +++ b/include/ucode/types.h @@ -206,11 +206,6 @@ typedef struct { uc_declare_vector(uc_resource_types_t, uc_resource_type_t *); - -/* Object iteration */ - -extern uc_list_t uc_object_iterators; - typedef struct { uc_list_t list; struct lh_table *table; @@ -270,6 +265,19 @@ uc_search_path_free(uc_search_path_t *search_path) { } +/* TLS data */ + +typedef struct { + /* VM owning installed signal handlers */ + uc_vm_t *signal_handler_vm; + + /* Object iteration */ + uc_list_t object_iterators; +} uc_thread_context_t; + +__hidden uc_thread_context_t *uc_thread_context_get(void); + + /* VM definitions */ typedef enum { @@ -388,6 +396,7 @@ uc_value_t *ucv_array_push(uc_value_t *, uc_value_t *); uc_value_t *ucv_array_shift(uc_value_t *); uc_value_t *ucv_array_unshift(uc_value_t *, uc_value_t *); void ucv_array_sort(uc_value_t *, int (*)(const void *, const void *)); +void ucv_array_sort_r(uc_value_t *, int (*)(uc_value_t *, uc_value_t *, void *), void *); bool ucv_array_delete(uc_value_t *, size_t, size_t); bool ucv_array_set(uc_value_t *, size_t, uc_value_t *); size_t ucv_array_length(uc_value_t *); @@ -396,6 +405,7 @@ uc_value_t *ucv_object_new(uc_vm_t *); uc_value_t *ucv_object_get(uc_value_t *, const char *, bool *); bool ucv_object_add(uc_value_t *, const char *, uc_value_t *); void ucv_object_sort(uc_value_t *, int (*)(const void *, const void *)); +void ucv_object_sort_r(uc_value_t *, int (*)(const char *, uc_value_t *, const char *, uc_value_t *, void *), void *); bool ucv_object_delete(uc_value_t *, const char *); size_t ucv_object_length(uc_value_t *); diff --git a/include/ucode/util.h b/include/ucode/util.h index cc92e339..1360d286 100644 --- a/include/ucode/util.h +++ b/include/ucode/util.h @@ -267,4 +267,32 @@ uc_vector_extend_(char **base, size_t itemsize, size_t count, size_t add) iter != NULL && iter >= (vec)->entries; \ iter--) +#ifdef __APPLE__ + +# define uc_vector_sort_cb(fn_, optype_, udtype_, ...) \ + int fn_(void *ud, const void *k1, const void *k2) { \ + optype_ v1 = *(optype_ *)k1; \ + optype_ v2 = *(optype_ *)k2; \ + udtype_ ctx = (udtype_)ud; \ + __VA_ARGS__ \ + } + +# define uc_vector_sort(v_, cmp_, ud_) \ + qsort_r((v_)->entries, (v_)->count, sizeof((v_)->entries[0]), ud_, cmp_) + +#else + +# define uc_vector_sort_cb(fn_, optype_, udtype_, ...) \ + int fn_(const void *k1, const void *k2, void *ud) { \ + optype_ v1 = *(optype_ *)k1; \ + optype_ v2 = *(optype_ *)k2; \ + udtype_ ctx = (udtype_)ud; \ + __VA_ARGS__ \ + } + +# define uc_vector_sort(v_, cmp_, ud_) \ + qsort_r((v_)->entries, (v_)->count, sizeof((v_)->entries[0]), cmp_, ud_) + +#endif + #endif /* UCODE_UTIL_H */ diff --git a/tests/custom/03_stdlib/60_gc b/tests/custom/03_stdlib/60_gc index 28c0d00c..44e5d9e2 100644 --- a/tests/custom/03_stdlib/60_gc +++ b/tests/custom/03_stdlib/60_gc @@ -45,11 +45,11 @@ Returns an object count if the given operation is `count`. -- End -- -- Expect stdout -- -Count #1: 6 -Count #2: 7 -Count #3: 6 -Count #4: 7 -Count #5: 6 +Count #1: 5 +Count #2: 6 +Count #3: 5 +Count #4: 6 +Count #5: 5 -- End -- @@ -84,24 +84,24 @@ Testing enabling the automatic collector. -- End -- -- Expect stdout -- -Count #1: 7 -Count #2: 14 -Count #3: 14 -Count #4: 14 -Count #5: 14 -Count #6: 14 -Count #7: 14 -Count #8: 14 -Count #9: 14 -Count #10: 14 -Count #11: 14 -Count #12: 24 -Count #13: 34 -Count #14: 44 -Count #15: 54 -Count #16: 64 -Count #17: 74 -Count #18: 84 -Count #19: 94 -Count #20: 104 +Count #1: 6 +Count #2: 12 +Count #3: 12 +Count #4: 12 +Count #5: 12 +Count #6: 12 +Count #7: 12 +Count #8: 12 +Count #9: 12 +Count #10: 12 +Count #11: 12 +Count #12: 22 +Count #13: 32 +Count #14: 42 +Count #15: 52 +Count #16: 62 +Count #17: 72 +Count #18: 82 +Count #19: 92 +Count #20: 102 -- End -- diff --git a/types.c b/types.c index 26f588e8..5dbf6a86 100644 --- a/types.c +++ b/types.c @@ -29,11 +29,6 @@ #include "ucode/vm.h" #include "ucode/program.h" -uc_list_t uc_object_iterators = { - .prev = &uc_object_iterators, - .next = &uc_object_iterators -}; - static char *uc_default_search_path[] = { LIB_SEARCH_PATH }; uc_parse_config_t uc_default_parse_config = { @@ -785,6 +780,28 @@ ucv_array_unshift(uc_value_t *uv, uc_value_t *item) return item; } +typedef struct { + int (*cmp)(uc_value_t *, uc_value_t *, void *); + void *ud; +} array_sort_ctx_t; + +static uc_vector_sort_cb(ucv_array_sort_r_cb, uc_value_t *, array_sort_ctx_t *, { + return ctx->cmp(v1, v2, ctx->ud); +}); + +void +ucv_array_sort_r(uc_value_t *uv, + int (*cmp)(uc_value_t *, uc_value_t *, void *), void *ud) +{ + array_sort_ctx_t ctx = { .cmp = cmp, .ud = ud }; + uc_array_t *array = (uc_array_t *)uv; + + if (ucv_type(uv) != UC_ARRAY || array->count <= 1) + return; + + uc_vector_sort(array, ucv_array_sort_r_cb, &ctx); +} + void ucv_array_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) { @@ -876,7 +893,7 @@ ucv_array_length(uc_value_t *uv) static void ucv_free_object_entry(struct lh_entry *entry) { - uc_list_foreach(item, &uc_object_iterators) { + uc_list_foreach(item, &uc_thread_context_get()->object_iterators) { uc_object_iterator_t *iter = (uc_object_iterator_t *)item; if (iter->u.pos == entry) @@ -933,7 +950,7 @@ ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val) /* insert will rehash table, backup affected iterator states */ if (rehash) { - uc_list_foreach(item, &uc_object_iterators) { + uc_list_foreach(item, &uc_thread_context_get()->object_iterators) { uc_object_iterator_t *iter = (uc_object_iterator_t *)item; if (iter->table != object->table) @@ -957,7 +974,7 @@ ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val) /* restore affected iterator state pointer after rehash */ if (rehash) { - uc_list_foreach(item, &uc_object_iterators) { + uc_list_foreach(item, &uc_thread_context_get()->object_iterators) { uc_object_iterator_t *iter = (uc_object_iterator_t *)item; if (iter->table != object->table) @@ -985,8 +1002,29 @@ ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val) return true; } -void -ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) + +typedef struct { + int (*cmp)(const void *, const void *); + int (*cmpr)(const char *, uc_value_t *, const char *, uc_value_t *, void *); + void *ud; +} object_sort_ctx_t; + +static uc_vector_sort_cb(ucv_object_sort_cb, const void *, object_sort_ctx_t *, { + (void)v1; + (void)v2; + + return ctx->cmp(k1, k2); +}); + +static uc_vector_sort_cb(ucv_object_sort_r_cb, const struct lh_entry *, object_sort_ctx_t *, { + return ctx->cmpr( + v1 ? lh_entry_k(v1) : NULL, v1 ? lh_entry_v(v1) : NULL, + v2 ? lh_entry_k(v2) : NULL, v2 ? lh_entry_v(v2) : NULL, + ctx->ud); +}); + +static void +ucv_object_sort_common(uc_value_t *uv, object_sort_ctx_t *ctx) { uc_object_t *object = (uc_object_t *)uv; struct lh_table *t; @@ -1007,7 +1045,8 @@ ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) if (!keys.entries) return; - qsort(keys.entries, keys.count, sizeof(keys.entries[0]), cmp); + uc_vector_sort(&keys, + ctx->cmpr ? ucv_object_sort_r_cb : ucv_object_sort_cb, ctx); for (i = 0; i < keys.count; i++) { e = keys.entries[i]; @@ -1027,6 +1066,25 @@ ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) uc_vector_clear(&keys); } +void +ucv_object_sort_r(uc_value_t *uv, + int (*cmp)(const char *, uc_value_t *, + const char *, uc_value_t *, void *), + void *ud) +{ + object_sort_ctx_t ctx = { .cmp = NULL, .cmpr = cmp, .ud = ud }; + + ucv_object_sort_common(uv, &ctx); +} + +void +ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) +{ + object_sort_ctx_t ctx = { .cmp = cmp, .cmpr = NULL, .ud = NULL }; + + ucv_object_sort_common(uv, &ctx); +} + bool ucv_object_delete(uc_value_t *uv, const char *key) { @@ -2418,3 +2476,18 @@ uc_search_path_init(uc_search_path_t *search_path) for (i = 0; i < ARRAY_SIZE(uc_default_search_path); i++) uc_vector_push(search_path, xstrdup(uc_default_search_path[i])); } + + +static __thread uc_thread_context_t *tls_ctx; + +uc_thread_context_t * +uc_thread_context_get(void) +{ + if (tls_ctx == NULL) { + tls_ctx = xalloc(sizeof(*tls_ctx)); + tls_ctx->object_iterators.prev = &tls_ctx->object_iterators; + tls_ctx->object_iterators.next = &tls_ctx->object_iterators; + } + + return tls_ctx; +} diff --git a/vm.c b/vm.c index 9488288a..1c40307c 100644 --- a/vm.c +++ b/vm.c @@ -145,37 +145,64 @@ 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; +} + +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) @@ -210,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); @@ -778,11 +807,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 +818,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 +2252,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) {