process.d: get start_stop_spinlock in thread_cleanup instead of thread_entry_point

Getting this lock in thread_entry_point was problematic: when the
thread was killed from another thread the catch point in
thread_entry_point was reached and the call to ecl_get_spinlock was
skipped. This lead to threads exiting without protection and to
segfaults.
This commit is contained in:
Marius Gerbershagen 2020-04-12 20:34:23 +02:00
parent 8d2b8d0ce1
commit 42fdbba968

View file

@ -187,13 +187,14 @@ thread_cleanup(void *aux)
* executed, never use pthread_cancel() to kill a process, but
* rather use the lisp functions mp_interrupt_process() and
* mp_process_kill().
*
* NOTE: to avoid race conditions, this method must be executed
* while process.start_stop_spinlock is held.
*/
cl_object process = (cl_object)aux;
cl_env_ptr env = process->process.env;
/* The following flags will disable all interrupts. */
if (env) {
ecl_get_spinlock(env, &process->process.start_stop_spinlock);
}
AO_store_full((AO_t*)&process->process.phase, ECL_PROCESS_EXITING);
if (env) {
ecl_clear_bignum_registers(env);
@ -216,7 +217,9 @@ thread_cleanup(void *aux)
mp_barrier_unblock(3, process->process.exit_barrier, @':disable', ECL_T);
ecl_set_process_env(NULL);
if (env) _ecl_dealloc_env(env);
AO_store_release((AO_t*)&process->process.phase, ECL_PROCESS_INACTIVE);
ecl_giveup_spinlock(&process->process.start_stop_spinlock);
}
#ifdef ECL_WINDOWS_THREADS
@ -282,9 +285,6 @@ static DWORD WINAPI thread_entry_point(void *arg)
/* ABORT restart. */
process->process.exit_values = args;
} ECL_RESTART_CASE_END;
/* This will disable interrupts during the exit
* so that the unwinding is not interrupted. */
ecl_get_spinlock(env, &process->process.start_stop_spinlock);
process->process.phase = ECL_PROCESS_EXITING;
ecl_bds_unwind1(env);
} ECL_CATCH_ALL_END;
@ -295,13 +295,9 @@ static DWORD WINAPI thread_entry_point(void *arg)
*/
#ifdef ECL_WINDOWS_THREADS
thread_cleanup(process);
#else
pthread_cleanup_pop(1);
#endif
ecl_giveup_spinlock(&process->process.start_stop_spinlock);
#ifdef ECL_WINDOWS_THREADS
return 1;
#else
pthread_cleanup_pop(1);
return NULL;
#endif
}
@ -436,9 +432,7 @@ ecl_release_current_thread(void)
int cleanup = env->cleanup;
cl_object own_process = env->own_process;
ecl_get_spinlock(env, &own_process->process.start_stop_spinlock);
thread_cleanup(own_process);
ecl_giveup_spinlock(&own_process->process.start_stop_spinlock);
#ifdef GBC_BOEHM
if (cleanup) {
GC_unregister_my_thread();