mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-16 06:12:25 -08:00
The environment of a thread is now allocated and managed by the parent thread. This decreases the time that passes since a thread is started till it is interruptible.
This commit is contained in:
parent
8382e4e800
commit
84f90aa585
2 changed files with 61 additions and 35 deletions
12
src/c/main.d
12
src/c/main.d
|
|
@ -261,12 +261,12 @@ void
|
|||
_ecl_dealloc_env(cl_env_ptr env)
|
||||
{
|
||||
/*
|
||||
* Environment cleanup
|
||||
* Environment cleanup. This is only required when the environment is
|
||||
* allocated using mmap or some other method. We could do more, cleaning
|
||||
* up stacks, etc, but we actually do not do it because that would need
|
||||
* a lisp environment set up -- the allocator assumes one -- and we
|
||||
* may have already cleaned up the value of ecl_process_env()
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
_ecl_big_clear(env->big_register[i]);
|
||||
}
|
||||
#if defined(ECL_USE_MPROTECT)
|
||||
if (munmap(env, sizeof(*env)))
|
||||
ecl_internal_error("Unable to deallocate environment structure.");
|
||||
|
|
@ -274,8 +274,6 @@ _ecl_dealloc_env(cl_env_ptr env)
|
|||
# if defined(ECL_USE_GUARD_PAGE)
|
||||
if (VirtualFree(env, sizeof(*env), MEM_RELEASE))
|
||||
ecl_internal_error("Unable to deallocate environment structure.");
|
||||
# else
|
||||
ecl_dealloc(env);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,14 +121,16 @@ thread_cleanup(void *aux)
|
|||
* mp_process_kill().
|
||||
*/
|
||||
cl_object process = (cl_object)aux;
|
||||
mp_giveup_lock(process->process.exit_lock);
|
||||
cl_env_ptr env = process->process.env;
|
||||
process->process.active = 0;
|
||||
process->process.env = NULL;
|
||||
ecl_disable_interrupts_env(env);
|
||||
mp_giveup_lock(process->process.exit_lock);
|
||||
THREAD_OP_LOCK();
|
||||
cl_core.processes = ecl_remove_eq(process, cl_core.processes);
|
||||
THREAD_OP_UNLOCK();
|
||||
if (process->process.env)
|
||||
_ecl_dealloc_env(process->process.env);
|
||||
process->process.env = NULL;
|
||||
ecl_set_process_env(NULL);
|
||||
if (env) _ecl_dealloc_env(env);
|
||||
}
|
||||
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
|
|
@ -139,26 +141,19 @@ thread_entry_point(void *arg)
|
|||
#endif
|
||||
{
|
||||
cl_object process = (cl_object)arg;
|
||||
cl_env_ptr env;
|
||||
cl_env_ptr env = process->process.env;
|
||||
|
||||
ecl_set_process_env(NULL);
|
||||
process->process.active = 2;
|
||||
/* 1) Setup the environment for the execution of the thread */
|
||||
ecl_set_process_env(env = process->process.env);
|
||||
#ifndef ECL_WINDOWS_THREADS
|
||||
pthread_cleanup_push(thread_cleanup, (void *)process);
|
||||
#endif
|
||||
/* 1) Setup the environment for the execution of the thread */
|
||||
process->process.env = env = _ecl_alloc_env();
|
||||
env->own_process = process;
|
||||
ecl_set_process_env(env);
|
||||
THREAD_OP_LOCK();
|
||||
cl_core.processes = CONS(process, cl_core.processes);
|
||||
THREAD_OP_UNLOCK();
|
||||
ecl_init_env(env);
|
||||
ecl_cs_set_org(env);
|
||||
env->bindings_hash = process->process.initial_bindings;
|
||||
ecl_enable_interrupts_env(env);
|
||||
env->trap_fpe_bits = process->process.trap_fpe_bits;
|
||||
si_trap_fpe(@'last', Ct);
|
||||
ecl_enable_interrupts_env(env);
|
||||
|
||||
/* 2) Execute the code. The CATCH_ALL point is the destination
|
||||
* provides us with an elegant way to exit the thread: we just
|
||||
|
|
@ -360,27 +355,51 @@ mp_process_yield(void)
|
|||
cl_object
|
||||
mp_process_enable(cl_object process)
|
||||
{
|
||||
cl_object output;
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
HANDLE code;
|
||||
DWORD threadId;
|
||||
|
||||
if (mp_process_active_p(process) != Cnil)
|
||||
/*
|
||||
* We try to grab the process exit lock. If we achieve it that
|
||||
* means the 1) process is not running or in the finalization
|
||||
* or 2) it is in the initialization phase. The second case we
|
||||
* can distinguish because process.active != 0. The first one
|
||||
* is ok.
|
||||
*/
|
||||
cl_env_ptr process_env;
|
||||
int ok;
|
||||
if (Null(mp_get_lock_nowait(process->process.exit_lock))) {
|
||||
FEerror("Cannot enable the running process ~A.", 1, process);
|
||||
return;
|
||||
}
|
||||
if (process->process.active) {
|
||||
mp_giveup_lock(process->process.exit_lock);
|
||||
FEerror("Cannot enable the running process ~A.", 1, process);
|
||||
return;
|
||||
}
|
||||
process_env = _ecl_alloc_env();
|
||||
ecl_init_env(process_env);
|
||||
process_env->trap_fpe_bits = process->process.trap_fpe_bits;
|
||||
process_env->bindings_hash = process->process.initial_bindings;
|
||||
process_env->own_process = process;
|
||||
|
||||
process->process.env = process_env;
|
||||
process->process.parent = mp_current_process();
|
||||
process->process.trap_fpe_bits =
|
||||
process->process.parent->process.env->trap_fpe_bits;
|
||||
process->process.active = 2;
|
||||
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
{
|
||||
HANDLE code;
|
||||
DWORD threadId;
|
||||
|
||||
code = (HANDLE)CreateThread(NULL, 0, thread_entry_point, process, 0, &threadId);
|
||||
output = (process->process.thread = code)? process : Cnil;
|
||||
ok = (process->process.thread = code);
|
||||
}
|
||||
#else
|
||||
{
|
||||
int code;
|
||||
pthread_attr_t pthreadattr;
|
||||
|
||||
pthread_attr_init(&pthreadattr);
|
||||
pthread_attr_setdetachstate(&pthreadattr, PTHREAD_CREATE_DETACHED);
|
||||
if (mp_process_active_p(process) != Cnil)
|
||||
FEerror("Cannot enable the running process ~A.", 1, process);
|
||||
process->process.parent = mp_current_process();
|
||||
/*
|
||||
* We launch the thread with the signal mask specified in cl_core.
|
||||
* The reason is that we might need to block certain signals
|
||||
|
|
@ -395,11 +414,20 @@ mp_process_enable(cl_object process)
|
|||
pthread_sigmask(SIG_SETMASK, &previous, NULL);
|
||||
}
|
||||
#else
|
||||
code = pthread_create(&process->process.thread, &pthreadattr, thread_entry_point, process);
|
||||
code = pthread_create(&process->process.thread, &pthreadattr,
|
||||
thread_entry_point, process);
|
||||
#endif
|
||||
output = code? Cnil : process;
|
||||
ok = (code == 0);
|
||||
}
|
||||
#endif
|
||||
@(return output)
|
||||
if (!ok) {
|
||||
process->process.active = 0;
|
||||
process->process.env = NULL;
|
||||
_ecl_dealloc_env(process_env);
|
||||
}
|
||||
mp_giveup_lock(process->process.exit_lock);
|
||||
|
||||
@(return (ok? Ct : Cnil))
|
||||
}
|
||||
|
||||
cl_object
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue