mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2025-12-15 15:21:03 -08:00
modules: [2/n] introduce ecl_module_unixint
This commit is contained in:
parent
05255a56e9
commit
10c03bedfc
4 changed files with 145 additions and 65 deletions
45
src/c/main.d
45
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)
|
||||
{
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
152
src/c/unixint.d
152
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue