mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-03-11 07:20:29 -07:00
process: abstract away create thread, exit thread and sigmask
Previously we've opencoded calls to these functions, although they may be nicely abstracted with static inline functions. This change improves code readibility and portability.
This commit is contained in:
parent
54602cc23a
commit
e2681805f3
8 changed files with 104 additions and 89 deletions
|
|
@ -175,6 +175,7 @@ ecl_thread_internal_error(const char *s)
|
|||
"Exitting thread.\n");
|
||||
fflush(stderr);
|
||||
ecl_thread_exit();
|
||||
_ecl_unexpected_return();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ ecl_spawn_cpu(cl_object process)
|
|||
{
|
||||
cl_env_ptr the_env = ecl_process_env();
|
||||
cl_env_ptr new_env = NULL;
|
||||
int ok = 1;
|
||||
int code = 0;
|
||||
/* Allocate and initialize the new cpu env. */
|
||||
{
|
||||
new_env = _ecl_alloc_env(the_env);
|
||||
|
|
@ -234,53 +234,30 @@ ecl_spawn_cpu(cl_object process)
|
|||
}
|
||||
/* Spawn the thread */
|
||||
ecl_disable_interrupts_env(the_env);
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
#if !defined(ECL_WINDOWS_THREADS) && defined(HAVE_SIGPROCMASK)
|
||||
{
|
||||
HANDLE code;
|
||||
DWORD threadId;
|
||||
|
||||
code = (HANDLE)CreateThread(NULL, 0, thread_entry_point, new_env, 0, &threadId);
|
||||
new_env->thread = code;
|
||||
ok = code != NULL;
|
||||
/* Block all asynchronous signals until the thread is completely set up. The
|
||||
* synchronous signals SIGSEGV and SIGBUS are needed by the gc and and can't
|
||||
* be blocked. */
|
||||
sigset_t new, previous;
|
||||
sigfillset(&new);
|
||||
sigdelset(&new, SIGSEGV);
|
||||
sigdelset(&new, SIGBUS);
|
||||
ecl_sigmask(SIG_BLOCK, &new, &previous);
|
||||
code = ecl_thread_create(new_env, thread_entry_point);
|
||||
ecl_sigmask(SIG_SETMASK, &previous, NULL);
|
||||
}
|
||||
#else /* ECL_WINDOWS_THREADS */
|
||||
{
|
||||
int code;
|
||||
pthread_attr_t pthreadattr;
|
||||
|
||||
pthread_attr_init(&pthreadattr);
|
||||
pthread_attr_setdetachstate(&pthreadattr, PTHREAD_CREATE_DETACHED);
|
||||
/*
|
||||
* Block all asynchronous signals until the thread is completely
|
||||
* set up. The synchronous signals SIGSEGV and SIGBUS are needed
|
||||
* by the gc and thus can't be blocked.
|
||||
*/
|
||||
# ifdef HAVE_SIGPROCMASK
|
||||
{
|
||||
sigset_t new, previous;
|
||||
sigfillset(&new);
|
||||
sigdelset(&new, SIGSEGV);
|
||||
sigdelset(&new, SIGBUS);
|
||||
pthread_sigmask(SIG_BLOCK, &new, &previous);
|
||||
code = pthread_create(&new_env->thread, &pthreadattr,
|
||||
thread_entry_point, new_env);
|
||||
pthread_sigmask(SIG_SETMASK, &previous, NULL);
|
||||
}
|
||||
# else
|
||||
code = pthread_create(&new_env->thread, &pthreadattr,
|
||||
thread_entry_point, new_env);
|
||||
# endif
|
||||
ok = (code == 0);
|
||||
}
|
||||
#endif /* ECL_WINDOWS_THREADS */
|
||||
#else
|
||||
code = ecl_thread_create(new_env, thread_entry_point);
|
||||
#endif
|
||||
/* Deal with the fallout of the thread creation. */
|
||||
if (!ok) {
|
||||
if (code != 0) {
|
||||
process->process.env = NULL;
|
||||
ecl_modules_free_env(new_env);
|
||||
_ecl_dealloc_env(new_env);
|
||||
}
|
||||
ecl_enable_interrupts_env(the_env);
|
||||
return ok ? new_env : NULL;
|
||||
return code ? NULL : new_env;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ run_process(cl_narg narg, ...)
|
|||
#ifdef HAVE_SIGPROCMASK
|
||||
{
|
||||
sigset_t *new = (sigset_t*)the_env->default_sigmask;
|
||||
pthread_sigmask(SIG_SETMASK, new, NULL);
|
||||
ecl_sigmask(SIG_SETMASK, new, NULL);
|
||||
}
|
||||
#endif
|
||||
process->process.phase = ECL_PROCESS_ACTIVE;
|
||||
|
|
@ -124,7 +124,7 @@ run_process(cl_narg narg, ...)
|
|||
sigset_t new[1];
|
||||
sigemptyset(new);
|
||||
sigaddset(new, ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL]);
|
||||
pthread_sigmask(SIG_BLOCK, new, NULL);
|
||||
ecl_sigmask(SIG_BLOCK, new, NULL);
|
||||
}
|
||||
#endif
|
||||
process->process.env = NULL;
|
||||
|
|
@ -196,7 +196,7 @@ ecl_release_current_thread(void)
|
|||
sigset_t new[1];
|
||||
sigemptyset(new);
|
||||
sigaddset(new, ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL]);
|
||||
pthread_sigmask(SIG_BLOCK, new, NULL);
|
||||
ecl_sigmask(SIG_BLOCK, new, NULL);
|
||||
}
|
||||
#endif
|
||||
process->process.phase = ECL_PROCESS_INACTIVE;
|
||||
|
|
@ -424,8 +424,8 @@ mp_get_sigmask(void)
|
|||
sigset_t *mask_ptr = (sigset_t*)data->vector.self.b8;
|
||||
sigset_t no_signals;
|
||||
sigemptyset(&no_signals);
|
||||
if (pthread_sigmask(SIG_BLOCK, &no_signals, mask_ptr))
|
||||
FElibc_error("MP:GET-SIGMASK failed in a call to pthread_sigmask", 0);
|
||||
if (ecl_sigmask(SIG_BLOCK, &no_signals, mask_ptr))
|
||||
FElibc_error("MP:GET-SIGMASK failed in a call to ecl_sigmask", 0);
|
||||
@(return data);
|
||||
}
|
||||
|
||||
|
|
@ -433,8 +433,8 @@ static cl_object
|
|||
mp_set_sigmask(cl_object data)
|
||||
{
|
||||
sigset_t *mask_ptr = (sigset_t*)data->vector.self.b8;
|
||||
if (pthread_sigmask(SIG_SETMASK, mask_ptr, NULL))
|
||||
FElibc_error("MP:SET-SIGMASK failed in a call to pthread_sigmask", 0);
|
||||
if (ecl_sigmask(SIG_SETMASK, mask_ptr, NULL))
|
||||
FElibc_error("MP:SET-SIGMASK failed in a call to ecl_sigmask", 0);
|
||||
@(return data);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -455,8 +455,8 @@ mp_block_signals(void)
|
|||
* can thus never be blocked */
|
||||
sigdelset(&all_signals, SIGSEGV);
|
||||
sigdelset(&all_signals, SIGBUS);
|
||||
if (pthread_sigmask(SIG_SETMASK, &all_signals, NULL))
|
||||
FElibc_error("MP:BLOCK-SIGNALS failed in a call to pthread_sigmask",0);
|
||||
if (ecl_sigmask(SIG_SETMASK, &all_signals, NULL))
|
||||
FElibc_error("MP:BLOCK-SIGNALS failed in a call to ecl_sigmask",0);
|
||||
@(return previous);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
* sections of code which are interruptible, and in which it is safe
|
||||
* for the handler to run arbitrary code, protect anything else. In
|
||||
* principle this "marking" can be done using POSIX functions such as
|
||||
* pthread_sigmask() or sigprocmask().
|
||||
* pthread_sigmask() or sigprocmask() abstracted with ecl_sigmask().
|
||||
*
|
||||
* However in practice this is slow, as it involves at least a
|
||||
* function call, resolving thread-local variables, etc, etc, and it
|
||||
|
|
@ -307,11 +307,7 @@ unblock_signal(cl_env_ptr the_env, int signal)
|
|||
* We do not really "unblock" the signal, but rather restore
|
||||
* ECL's default sigmask.
|
||||
*/
|
||||
# ifdef ECL_THREADS
|
||||
pthread_sigmask(SIG_SETMASK, the_env->default_sigmask, NULL);
|
||||
# else
|
||||
sigprocmask(SIG_SETMASK, the_env->default_sigmask, NULL);
|
||||
# endif
|
||||
ecl_sigmask(SIG_SETMASK, the_env->default_sigmask, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -619,7 +615,7 @@ asynchronous_signal_servicing_thread()
|
|||
sigdelset(&handled_set, SIGSEGV);
|
||||
sigdelset(&handled_set, SIGBUS);
|
||||
}
|
||||
pthread_sigmask(SIG_BLOCK, &handled_set, NULL);
|
||||
ecl_sigmask(SIG_BLOCK, &handled_set, NULL);
|
||||
}
|
||||
/*
|
||||
* We create the object for communication. We need a lock to prevent other
|
||||
|
|
@ -909,25 +905,25 @@ do_catch_signal(int code, cl_object action, cl_object process)
|
|||
return ECL_T;
|
||||
} else {
|
||||
sigset_t handled_set;
|
||||
pthread_sigmask(SIG_SETMASK, NULL, &handled_set);
|
||||
ecl_sigmask(SIG_SETMASK, NULL, &handled_set);
|
||||
if (action == @':mask') {
|
||||
sigaddset(&handled_set, code);
|
||||
} else {
|
||||
sigdelset(&handled_set, code);
|
||||
}
|
||||
pthread_sigmask(SIG_SETMASK, &handled_set, NULL);
|
||||
ecl_sigmask(SIG_SETMASK, &handled_set, NULL);
|
||||
return ECL_T;
|
||||
}
|
||||
# else
|
||||
{
|
||||
sigset_t handled_set;
|
||||
sigprocmask(SIG_SETMASK, NULL, &handled_set);
|
||||
ecl_sigmask(SIG_SETMASK, NULL, &handled_set);
|
||||
if (action == @':mask') {
|
||||
sigaddset(&handled_set, code);
|
||||
} else {
|
||||
sigdelset(&handled_set, code);
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &handled_set, NULL);
|
||||
ecl_sigmask(SIG_SETMASK, &handled_set, NULL);
|
||||
return ECL_T;
|
||||
}
|
||||
# endif /* !ECL_THREADS */
|
||||
|
|
@ -1304,11 +1300,7 @@ install_asynchronous_signal_handlers()
|
|||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t *sigmask = ecl_core.first_env->default_sigmask = &main_thread_sigmask;
|
||||
ecl_core.default_sigmask_bytes = sizeof(sigset_t);
|
||||
# ifdef ECL_THREADS
|
||||
pthread_sigmask(SIG_SETMASK, NULL, sigmask);
|
||||
# else
|
||||
sigprocmask(SIG_SETMASK, NULL, sigmask);
|
||||
# endif
|
||||
ecl_sigmask(SIG_SETMASK, NULL, sigmask);
|
||||
#endif
|
||||
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
|
||||
ecl_mutex_init(&signal_thread_lock, TRUE);
|
||||
|
|
@ -1319,11 +1311,7 @@ install_asynchronous_signal_handlers()
|
|||
}
|
||||
#endif
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
# if defined(ECL_THREADS)
|
||||
pthread_sigmask(SIG_SETMASK, sigmask, NULL);
|
||||
# else
|
||||
sigprocmask(SIG_SETMASK, sigmask, NULL);
|
||||
# endif
|
||||
ecl_sigmask(SIG_SETMASK, sigmask, NULL);
|
||||
#endif
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
old_W32_exception_filter =
|
||||
|
|
@ -1417,7 +1405,7 @@ install_synchronous_signal_handlers()
|
|||
mysignal(signal, process_interrupt_handler);
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigdelset(&main_thread_sigmask, signal);
|
||||
pthread_sigmask(SIG_SETMASK, &main_thread_sigmask, NULL);
|
||||
ecl_sigmask(SIG_SETMASK, &main_thread_sigmask, NULL);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -62,9 +62,6 @@
|
|||
# include <windows.h>
|
||||
# endif
|
||||
# ifdef ECL_THREADS
|
||||
typedef HANDLE pthread_t;
|
||||
typedef HANDLE pthread_mutex_t;
|
||||
typedef HANDLE pthread_cond_t; /*Dummy, not really used*/
|
||||
# undef ERROR
|
||||
# ifdef GBC_BOEHM
|
||||
# define CreateThread GC_CreateThread
|
||||
|
|
|
|||
|
|
@ -742,13 +742,6 @@ extern void ecl_cs_set_size(cl_env_ptr env, cl_index n);
|
|||
#ifdef ECL_THREADS
|
||||
extern ECL_API cl_object mp_suspend_loop();
|
||||
extern ECL_API cl_object mp_break_suspend_loop();
|
||||
|
||||
# ifdef ECL_WINDOWS_THREADS
|
||||
# define ecl_thread_exit() ExitThread(0);
|
||||
# else
|
||||
# define ecl_thread_exit() pthread_exit(NULL);
|
||||
# endif /* ECL_WINDOWS_THREADS */
|
||||
|
||||
#endif
|
||||
|
||||
/* time.d */
|
||||
|
|
@ -918,6 +911,27 @@ extern void ecl_interrupt_process(cl_object process, cl_object function);
|
|||
|
||||
#include <ecl/threads.h>
|
||||
|
||||
/* sigmask */
|
||||
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
# include <signal.h>
|
||||
# ifdef ECL_THREADS
|
||||
static inline int
|
||||
ecl_sigmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
return pthread_sigmask(how, set, oldset);
|
||||
}
|
||||
# else
|
||||
static inline int
|
||||
ecl_sigmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
return sigprocmask(how, set, oldset);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* global locks */
|
||||
|
||||
#ifdef ECL_THREADS
|
||||
# define ECL_WITH_GLOBAL_LOCK_BEGIN(the_env) \
|
||||
ECL_WITH_NATIVE_LOCK_BEGIN(the_env, &ecl_core.global_lock)
|
||||
|
|
|
|||
|
|
@ -14,11 +14,10 @@
|
|||
#ifndef ECL_STACK_RESIZE_H
|
||||
#define ECL_STACK_RESIZE_H
|
||||
|
||||
/* We can't block interrupts with ecl_disable_interrupts() and write
|
||||
* in the thread local environment if we use fast interrupt dispatch
|
||||
* via mprotect(), so we have to use sigprocmask instead. No
|
||||
* performance problems, since this is only used for stack
|
||||
* resizing. */
|
||||
/* We can't block interrupts with ecl_disable_interrupts() and write in the
|
||||
* thread local environment if we use fast interrupt dispatch via mprotect(), so
|
||||
* we have to use sigprocmask instead. No performance problems, since this is
|
||||
* only used for stack resizing. */
|
||||
#if defined(ECL_THREADS) && defined(ECL_USE_MPROTECT)
|
||||
# ifdef HAVE_SIGPROCMASK
|
||||
# include <signal.h>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ECL_MUTEX_H
|
||||
#define ECL_MUTEX_H
|
||||
#ifndef ECL_THREADS_H
|
||||
#define ECL_THREADS_H
|
||||
|
||||
#include <errno.h>
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
|
|
@ -38,6 +38,45 @@
|
|||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
/* Windows can't into typedefs in parameter lists. */
|
||||
/* typedef DWORD WINAPI (*ecl_thread_entry)(void *ptr); */
|
||||
static inline int
|
||||
ecl_thread_create(cl_env_ptr the_env, /* ecl_thread_entry */ void* fun)
|
||||
{
|
||||
HANDLE code;
|
||||
DWORD threadId;
|
||||
code = (HANDLE)CreateThread(NULL, 0, fun, the_env, 0, &threadId);
|
||||
the_env->thread = code;
|
||||
/* NULL handle is a failure. */
|
||||
return (code != NULL) ? 0 : 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ecl_thread_exit()
|
||||
{
|
||||
ExitThread(0);
|
||||
}
|
||||
#else /* ECL_WINDOWS_THREADS */
|
||||
typedef void* (*ecl_thread_entry)(void *ptr);
|
||||
|
||||
static inline int
|
||||
ecl_thread_create(cl_env_ptr the_env, ecl_thread_entry fun)
|
||||
{
|
||||
pthread_attr_t pthreadattr;
|
||||
pthread_attr_init(&pthreadattr);
|
||||
pthread_attr_setdetachstate(&pthreadattr, PTHREAD_CREATE_DETACHED);
|
||||
return pthread_create(&the_env->thread, &pthreadattr, fun, the_env);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ecl_thread_exit()
|
||||
{
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
#endif /* ECL_WINDOWS_THREADS */
|
||||
|
||||
|
||||
#if !defined(ECL_WINDOWS_THREADS)
|
||||
|
||||
#define ECL_MUTEX_SUCCESS 0
|
||||
|
|
@ -734,6 +773,6 @@ ecl_rwlock_lock_write(ecl_rwlock_t *rwlock)
|
|||
|
||||
#endif /* ECL_WINDOWS_THREADS */
|
||||
|
||||
#endif /* ECL_MUTEX_H */
|
||||
#endif /* ECL_THREADS_H */
|
||||
|
||||
#endif /* ECL_THREADS */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue