modules: [2/n] introduce ecl_module_unixint

This commit is contained in:
Daniel Kochmański 2024-12-03 14:12:58 +01:00
parent 05255a56e9
commit 10c03bedfc
4 changed files with 145 additions and 65 deletions

View file

@ -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)
{
@ -102,7 +83,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);
@ -112,7 +92,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);
@ -124,9 +103,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.");
@ -178,27 +154,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;
}
@ -331,8 +290,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();
/*
@ -606,7 +565,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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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