From 001422e3b9c3d3596217a4fa21264ffcfc72048c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Kochma=C5=84ski?= Date: Tue, 3 Dec 2024 14:12:58 +0100 Subject: [PATCH] modules: [2/n] introduce ecl_module_unixint --- src/c/main.d | 45 +------------- src/c/process.d | 4 -- src/c/unixint.d | 152 +++++++++++++++++++++++++++++++++++++++++++---- src/h/internal.h | 9 ++- 4 files changed, 145 insertions(+), 65 deletions(-) diff --git a/src/c/main.d b/src/c/main.d index f0e0c76ba..3e7e649f1 100644 --- a/src/c/main.d +++ b/src/c/main.d @@ -42,25 +42,6 @@ const char *ecl_self; static int ARGC; static char **ARGV; -static void -init_env_int(cl_env_ptr env) -{ - env->interrupt_struct = ecl_alloc(sizeof(*env->interrupt_struct)); - env->interrupt_struct->pending_interrupt = ECL_NIL; -#ifdef ECL_THREADS - ecl_mutex_init(&env->interrupt_struct->signal_queue_lock, FALSE); -#endif -#ifdef ECL_WINDOWS_THREADS - env->interrupt_struct->inside_interrupt = false; -#endif - { - int size = ecl_option_values[ECL_OPT_SIGNAL_QUEUE_SIZE]; - env->interrupt_struct->signal_queue = cl_make_list(1, ecl_make_fixnum(size)); - } - env->fault_address = env; - env->trap_fpe_bits = 0; -} - static void init_env_ffi(cl_env_ptr env) { @@ -103,7 +84,6 @@ ecl_init_first_env(cl_env_ptr the_env) ecl_cs_init(env); #endif ecl_cs_init(the_env); - init_env_int(the_env); init_env_aux(the_env); init_env_ffi(the_env); init_stacks(the_env); @@ -113,7 +93,6 @@ void ecl_init_env(cl_env_ptr env) { ecl_modules_init_env(env); - init_env_int(env); init_env_aux(env); init_env_ffi(env); init_stacks(env); @@ -125,9 +104,6 @@ _ecl_dealloc_env(cl_env_ptr env) env->own_process = ECL_NIL; ecl_modules_free_env(env); free_stacks(env); -#ifdef ECL_THREADS - ecl_mutex_destroy(&env->interrupt_struct->signal_queue_lock); -#endif #if defined(ECL_USE_MPROTECT) if (munmap(env, sizeof(*env))) ecl_internal_error("Unable to deallocate environment structure."); @@ -179,27 +155,10 @@ _ecl_alloc_env(cl_env_ptr parent) #endif output->own_process = ECL_NIL; output->c_stack.org = NULL; - { - size_t bytes = ecl_core.default_sigmask_bytes; - if (bytes == 0) { - output->default_sigmask = 0; - } else if (parent) { - output->default_sigmask = ecl_alloc_atomic(bytes); - memcpy(output->default_sigmask, parent->default_sigmask, bytes); - } else { - output->default_sigmask = ecl_core.first_env->default_sigmask; - } - } for (cl_index i = 0; i < ECL_BIGNUM_REGISTER_NUMBER; i++) { output->big_register[i] = ECL_NIL; } output->method_cache = output->slot_cache = NULL; - output->interrupt_struct = NULL; - /* - * An uninitialized environment _always_ disables interrupts. They - * are activated later on by the thread entry point or init_unixint(). - */ - output->disable_interrupts = 1; return output; } @@ -333,8 +292,8 @@ cl_boot(int argc, char **argv) ecl_self = argv[0]; ecl_add_module(ecl_module_gc); + ecl_add_module(ecl_module_unixint); - init_unixint(0); init_big(); /* @@ -609,7 +568,7 @@ cl_boot(int argc, char **argv) /* Jump to top level */ ECL_SET(@'*package*', cl_core.user_package); - init_unixint(1); + ecl_module_unixint->module.enable(); return 1; } diff --git a/src/c/process.d b/src/c/process.d index 89827f590..496598dda 100644 --- a/src/c/process.d +++ b/src/c/process.d @@ -192,7 +192,6 @@ ecl_disown_cpu() cl_env_ptr the_env = ecl_process_env_unsafe(); if (the_env == NULL) return; - ecl_disable_interrupts_env(the_env); ecl_modules_free_cpu(the_env); #ifdef ECL_WINDOWS_THREADS CloseHandle(the_env->thread); @@ -337,9 +336,6 @@ init_process(void) #endif ecl_set_process_env(the_env); the_env->c_stack.org = NULL; - the_env->default_sigmask = NULL; the_env->method_cache = NULL; the_env->slot_cache = NULL; - the_env->interrupt_struct = NULL; - the_env->disable_interrupts = 1; } diff --git a/src/c/unixint.d b/src/c/unixint.d index dc385e30b..561c0470f 100644 --- a/src/c/unixint.d +++ b/src/c/unixint.d @@ -629,6 +629,7 @@ asynchronous_signal_servicing_thread() pipe(signal_thread_pipe); ecl_mutex_unlock(&signal_thread_lock); signal_thread_msg.process = ECL_NIL; + ECL_UNWIND_PROTECT_BEGIN(the_env); for (;;) { cl_object signal_code; signal_thread_msg.process = ECL_NIL; @@ -655,12 +656,14 @@ asynchronous_signal_servicing_thread() signal_code); } } + ECL_UNWIND_PROTECT_EXIT; # if defined(ECL_USE_MPROTECT) /* We might have protected our own environment */ mprotect(the_env, sizeof(*the_env), PROT_READ | PROT_WRITE); # endif /* ECL_USE_MPROTECT */ close(signal_thread_pipe[0]); close(signal_thread_pipe[1]); + ECL_UNWIND_PROTECT_END; ecl_return0(the_env); } #endif /* ECL_THREADS && !ECL_MS_WINDOWS_HOST */ @@ -1337,7 +1340,7 @@ install_asynchronous_signal_handlers() * synchronous signals and spawns a new thread to handle each of them. */ static void -install_signal_handling_thread() +install_signal_handling_thread(void) { #if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK) ecl_process_env()->default_sigmask = &main_thread_sigmask; @@ -1355,6 +1358,18 @@ install_signal_handling_thread() #endif } +static void +uninstall_signal_handling_thread(void) +{ +#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK) + if (ecl_option_values[ECL_OPT_SIGNAL_HANDLING_THREAD] + && signal_thread_process->process.phase == ECL_PROCESS_ACTIVE) { + mp_process_kill(signal_thread_process); + mp_process_join(signal_thread_process); + } +#endif +} + /* * This routine sets up handlers for all exceptions, such as access to * restricted regions of memory. They have to be set up before we call @@ -1482,17 +1497,128 @@ create_signal_code_constants() #endif } -void -init_unixint(int pass) +/* -- module definition ------------------------------------------------------ */ + +static cl_object +create_unixint(void) { - if (pass == 0) { - install_asynchronous_signal_handlers(); - install_synchronous_signal_handlers(); - } else { - create_signal_code_constants(); - install_fpe_signal_handlers(); - install_signal_handling_thread(); - ECL_SET(@'ext::*interrupts-enabled*', ECL_T); - ecl_process_env()->disable_interrupts = 0; - } + cl_env_ptr the_env = ecl_core.first_env; + the_env->default_sigmask = NULL; + the_env->interrupt_struct = NULL; + ecl_disable_interrupts_env(the_env); + /* Install handlers */ + install_asynchronous_signal_handlers(); + install_synchronous_signal_handlers(); + return ECL_NIL; } + +static cl_object +enable_unixint(void) +{ + create_signal_code_constants(); + install_fpe_signal_handlers(); + install_signal_handling_thread(); + ECL_SET(@'ext::*interrupts-enabled*', ECL_T); + ecl_process_env()->disable_interrupts = 0; + return ECL_NIL; +} + +static cl_object +init_env_unixint(cl_env_ptr the_env) +{ + cl_env_ptr parent_env = ecl_process_env_unsafe(); + size_t bytes = ecl_core.default_sigmask_bytes; + if (bytes == 0) { + the_env->default_sigmask = 0; + } else if (parent_env) { + the_env->default_sigmask = ecl_alloc_atomic(bytes); + memcpy(the_env->default_sigmask, parent_env->default_sigmask, bytes); + } else { + the_env->default_sigmask = ecl_core.first_env->default_sigmask; + } + the_env->interrupt_struct = ecl_alloc(sizeof(*the_env->interrupt_struct)); + the_env->interrupt_struct->pending_interrupt = ECL_NIL; +#ifdef ECL_THREADS + ecl_mutex_init(&the_env->interrupt_struct->signal_queue_lock, FALSE); +#endif +#ifdef ECL_WINDOWS_THREADS + the_env->interrupt_struct->inside_interrupt = false; +#endif + { + int size = ecl_option_values[ECL_OPT_SIGNAL_QUEUE_SIZE]; + the_env->interrupt_struct->signal_queue = cl_make_list(1, ecl_make_fixnum(size)); + } + the_env->fault_address = the_env; + the_env->trap_fpe_bits = 0; + /* An fresh environment _always_ disables interrupts. They are activated later + * on by the thread entry point or ecl_module_unixint. */ + ecl_disable_interrupts_env(the_env); + return ECL_NIL; +} + +static cl_object +init_cpu_unixint(cl_env_ptr the_env) +{ + return ECL_NIL; +} + +static cl_object +free_cpu_unixint(cl_env_ptr the_env) +{ + ecl_disable_interrupts_env(the_env); + return ECL_NIL; +} + +static cl_object +free_env_unixint(cl_env_ptr the_env) +{ +#ifdef ECL_THREADS + ecl_mutex_destroy(&the_env->interrupt_struct->signal_queue_lock); +#endif + the_env->trap_fpe_bits = 0; + si_trap_fpe(@'last', ECL_NIL); + return ECL_NIL; +} + +static cl_object +disable_unixint(void) +{ + cl_env_ptr the_env = ecl_core.first_env; + ecl_disable_interrupts_env(the_env); + ECL_SET(ECL_INTERRUPTS_ENABLED, ECL_NIL); + return ECL_NIL; +} + +static cl_object +destroy_unixint(void) +{ + uninstall_signal_handling_thread(); + /* FIXME this is messy. */ + /* remove_signal_code_constants(); */ + return ECL_NIL; +} + +/* KLUDGE UNIXINT and MEM_GC are interwened - GC expects stop_world to work and + unixint relies on the GC to allocate its internal structures. + + When we start add MEM_GC module before UNIXINT and enable GC after both are + created. That is enough to get GC going. Finally we enable UNIXINT. + + When we adopt a new cpu we first disable MEM_GC, then initialize UNIXINT + (allocator works fine despite GC collector being disabled), then initialize + GC to register the current thread and enable the GC. -- jd 2024-12-05 */ + +ecl_def_ct_base_string(str_unixint, "UNIXINT", 7, static, const); +static struct ecl_module module_unixint = { + .name = str_unixint, + .create = create_unixint, + .enable = enable_unixint, + .init_env = init_env_unixint, + .init_cpu = init_cpu_unixint, + .free_cpu = free_cpu_unixint, + .free_env = free_env_unixint, + .disable = disable_unixint, + .destroy = destroy_unixint +}; + +cl_object ecl_module_unixint = (cl_object)&module_unixint; diff --git a/src/h/internal.h b/src/h/internal.h index 689e8e31f..b8950c990 100755 --- a/src/h/internal.h +++ b/src/h/internal.h @@ -23,6 +23,10 @@ extern "C" { #define unlikely_if(x) if (ecl_unlikely(x)) /* booting */ +extern ECL_API cl_object ecl_module_dummy; +extern ECL_API cl_object ecl_module_gc; +extern ECL_API cl_object ecl_module_unixint; + extern void init_all_symbols(void); extern void init_backq(void); extern void init_big(); @@ -37,7 +41,6 @@ extern void init_read(void); extern cl_object init_stacks(cl_env_ptr); extern cl_object free_stacks(cl_env_ptr); -extern void init_unixint(int pass); extern void init_unixtime(void); extern void init_compiler(void); extern void init_process(void); @@ -63,10 +66,6 @@ extern cl_object ecl_alloc_bytecodes(cl_index data_size, cl_index code_size); extern cl_index ecl_object_byte_size(cl_type t); extern cl_index ecl_next_stamp(); -/* modules.c */ -extern ECL_API cl_object ecl_module_dummy; -extern ECL_API cl_object ecl_module_gc; - /* array.d */ #ifdef ECL_DEFINE_AET_SIZE