mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-15 05:43:19 -08:00
Improved EXT:CATCH-SIGNAL to handle not running processes, threads and better use of sigprocmask.
This commit is contained in:
parent
ccfb2673f9
commit
bc7be9bb98
7 changed files with 137 additions and 61 deletions
|
|
@ -94,6 +94,17 @@ ECL 11.7.1:
|
|||
- Initialization of random number generator is done using only 16 bytes from
|
||||
/dev/urandom (Phillip Marek).
|
||||
|
||||
- Each thread keeps a copy of the process sigmask (POSIX) and it is inherited
|
||||
by children thread. The sigmask can be manipulated by the function
|
||||
EXT:CATCH-SIGNAL which has the signature
|
||||
(ext:catch-signal signal-code action &key process)
|
||||
The ACTION is one of :IGNORE, :DEFAULT, :CATCH, determining what ECL does
|
||||
when it receives the signal, or it can be :MASK/:UNMASK to determine whether
|
||||
the process is blocking the signal or not. The optional argument :PROCESS
|
||||
only applies to :MASK/:UNMASK and it can be the current process, some
|
||||
process that has not been activated or any other value (indicating that
|
||||
the function has a global effect, as sigprocmask).
|
||||
|
||||
;;; Local Variables: ***
|
||||
;;; mode:text ***
|
||||
;;; fill-column:79 ***
|
||||
|
|
|
|||
14
src/c/main.d
14
src/c/main.d
|
|
@ -233,6 +233,19 @@ _ecl_alloc_env()
|
|||
}
|
||||
# endif
|
||||
#endif
|
||||
{
|
||||
size_t bytes = cl_core.default_sigmask_bytes;
|
||||
if (bytes == 0) {
|
||||
output->default_sigmask = 0;
|
||||
} else if (ecl_get_option(ECL_OPT_BOOTED)) {
|
||||
output->default_sigmask = ecl_alloc_atomic(bytes);
|
||||
memcpy(output->default_sigmask,
|
||||
ecl_process_env()->default_sigmask,
|
||||
bytes);
|
||||
} else {
|
||||
output->default_sigmask = cl_core.default_sigmask;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* An uninitialized environment _always_ disables interrupts. They
|
||||
* are activated later on by the thread entry point or init_unixint().
|
||||
|
|
@ -404,6 +417,7 @@ struct cl_core_struct cl_core = {
|
|||
Cnil, /* signal_queue */
|
||||
|
||||
NULL, /* default_sigmask */
|
||||
0, /* default_sigmask_bytes */
|
||||
|
||||
#ifdef ECL_THREADS
|
||||
0, /* last_var_index */
|
||||
|
|
|
|||
|
|
@ -1305,6 +1305,7 @@ cl_symbols[] = {
|
|||
{KEY_ "BASE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "BLOCK", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "CAPITALIZE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "CATCH", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "CASE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "CIRCLE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "COMPILE-TOPLEVEL", KEYWORD, NULL, -1, OBJNULL},
|
||||
|
|
@ -1347,6 +1348,7 @@ cl_symbols[] = {
|
|||
{KEY_ "IF-DOES-NOT-EXIST", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "IF-EXISTS", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "IF-OUTPUT-EXISTS", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "IGNORE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "IMPORT-FROM", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "INCLUDE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "INHERITED", KEYWORD, NULL, -1, OBJNULL},
|
||||
|
|
@ -1370,6 +1372,7 @@ cl_symbols[] = {
|
|||
{KEY_ "LOCAL",KEYWORD,NULL,-1,OBJNULL},
|
||||
{KEY_ "LOCKABLE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "LOAD-TOPLEVEL", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "MASK", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "MISER-WIDTH", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "NAME", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "NAMED", KEYWORD, NULL, -1, OBJNULL},
|
||||
|
|
@ -1392,6 +1395,7 @@ cl_symbols[] = {
|
|||
{KEY_ "PRINT-FUNCTION", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "PRINT-OBJECT", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "PROBE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "PROCESS", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "RADIX", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "READABLY", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "REHASH-SIZE", KEYWORD, NULL, -1, OBJNULL},
|
||||
|
|
@ -1417,6 +1421,7 @@ cl_symbols[] = {
|
|||
{KEY_ "TEST-NOT", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "TYPE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "UNSPECIFIC", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "UNMASK", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "UP", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "UPCASE", KEYWORD, NULL, -1, OBJNULL},
|
||||
{KEY_ "USE", KEYWORD, NULL, -1, OBJNULL},
|
||||
|
|
|
|||
|
|
@ -1305,6 +1305,7 @@ cl_symbols[] = {
|
|||
{KEY_ "BASE",NULL},
|
||||
{KEY_ "BLOCK",NULL},
|
||||
{KEY_ "CAPITALIZE",NULL},
|
||||
{KEY_ "CATCH",NULL},
|
||||
{KEY_ "CASE",NULL},
|
||||
{KEY_ "CIRCLE",NULL},
|
||||
{KEY_ "COMPILE-TOPLEVEL",NULL},
|
||||
|
|
@ -1347,6 +1348,7 @@ cl_symbols[] = {
|
|||
{KEY_ "IF-DOES-NOT-EXIST",NULL},
|
||||
{KEY_ "IF-EXISTS",NULL},
|
||||
{KEY_ "IF-OUTPUT-EXISTS",NULL},
|
||||
{KEY_ "IGNORE",NULL},
|
||||
{KEY_ "IMPORT-FROM",NULL},
|
||||
{KEY_ "INCLUDE",NULL},
|
||||
{KEY_ "INHERITED",NULL},
|
||||
|
|
@ -1370,6 +1372,7 @@ cl_symbols[] = {
|
|||
{KEY_ "LOCAL",NULL},
|
||||
{KEY_ "LOCKABLE",NULL},
|
||||
{KEY_ "LOAD-TOPLEVEL",NULL},
|
||||
{KEY_ "MASK",NULL},
|
||||
{KEY_ "MISER-WIDTH",NULL},
|
||||
{KEY_ "NAME",NULL},
|
||||
{KEY_ "NAMED",NULL},
|
||||
|
|
@ -1392,6 +1395,7 @@ cl_symbols[] = {
|
|||
{KEY_ "PRINT-FUNCTION",NULL},
|
||||
{KEY_ "PRINT-OBJECT",NULL},
|
||||
{KEY_ "PROBE",NULL},
|
||||
{KEY_ "PROCESS",NULL},
|
||||
{KEY_ "RADIX",NULL},
|
||||
{KEY_ "READABLY",NULL},
|
||||
{KEY_ "REHASH-SIZE",NULL},
|
||||
|
|
@ -1417,6 +1421,7 @@ cl_symbols[] = {
|
|||
{KEY_ "TEST-NOT",NULL},
|
||||
{KEY_ "TYPE",NULL},
|
||||
{KEY_ "UNSPECIFIC",NULL},
|
||||
{KEY_ "UNMASK",NULL},
|
||||
{KEY_ "UP",NULL},
|
||||
{KEY_ "UPCASE",NULL},
|
||||
{KEY_ "USE",NULL},
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ mp_process_enable(cl_object process)
|
|||
#ifdef HAVE_SIGPROCMASK
|
||||
{
|
||||
sigset_t previous;
|
||||
pthread_sigmask(SIG_SETMASK, cl_core.default_sigmask, &previous);
|
||||
pthread_sigmask(SIG_SETMASK, process_env->default_sigmask, &previous);
|
||||
code = pthread_create(&process->process.thread, &pthreadattr,
|
||||
thread_entry_point, process);
|
||||
pthread_sigmask(SIG_SETMASK, &previous, NULL);
|
||||
|
|
|
|||
156
src/c/unixint.d
156
src/c/unixint.d
|
|
@ -199,6 +199,7 @@ static struct {
|
|||
};
|
||||
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
static sigset_t main_thread_sigmask;
|
||||
# define handler_fn_protype(name, sig, info, aux) name(sig, info, aux)
|
||||
# define call_handler(name, sig, info, aux) name(sig, info, aux)
|
||||
# define reinstall_signal(x,y) mysignal(x,y)
|
||||
|
|
@ -206,21 +207,26 @@ static struct {
|
|||
static void
|
||||
mysignal(int code, void (*handler)(int, siginfo_t *, void*))
|
||||
{
|
||||
struct sigaction new_action, old_action;
|
||||
struct sigaction action;
|
||||
sigaction(code, NULL, &action);
|
||||
if (handler == SIG_IGN || handler == SIG_DFL) {
|
||||
action.sa_handler = handler;
|
||||
} else {
|
||||
#ifdef SA_SIGINFO
|
||||
new_action.sa_sigaction = handler;
|
||||
new_action.sa_flags = SA_SIGINFO;
|
||||
action.sa_sigaction = handler;
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
# if 0 && defined(SA_ONSTACK)
|
||||
if (code == SIGSEGV) {
|
||||
new_action.sa_flags |= SA_ONSTACK;
|
||||
}
|
||||
if (code == SIGSEGV) {
|
||||
action.sa_flags |= SA_ONSTACK;
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
new_action.sa_handler = handler;
|
||||
new_action.sa_flags = 0;
|
||||
action.sa_handler = handler;
|
||||
action.sa_flags = 0;
|
||||
#endif
|
||||
sigfillset(&new_action.sa_mask);
|
||||
sigaction(code, &new_action, &old_action);
|
||||
sigfillset(&action.sa_mask);
|
||||
}
|
||||
sigaction(code, &action, NULL);
|
||||
}
|
||||
#else /* HAVE_SIGPROCMASK */
|
||||
# define handler_fn_protype(name, sig, info, aux) name(sig)
|
||||
|
|
@ -359,9 +365,9 @@ unblock_signal(int signal)
|
|||
* ECL's default sigmask.
|
||||
*/
|
||||
# ifdef ECL_THREADS
|
||||
pthread_sigmask(SIG_SETMASK, cl_core.default_sigmask, NULL);
|
||||
pthread_sigmask(SIG_SETMASK, ecl_process_env()->default_sigmask, NULL);
|
||||
# else
|
||||
sigprocmask(SIG_SETMASK, cl_core.default_sigmask, NULL);
|
||||
sigprocmask(SIG_SETMASK, ecl_process_env()->default_sigmask, NULL);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
|
@ -661,7 +667,74 @@ ecl_check_pending_interrupts(void)
|
|||
}
|
||||
}
|
||||
|
||||
@(defun ext::catch-signal (code flag &key local)
|
||||
static cl_object
|
||||
do_catch_signal(int code, cl_object action, cl_object process)
|
||||
{
|
||||
if (action == Cnil || action == @':ignore') {
|
||||
mysignal(code, SIG_IGN);
|
||||
return Ct;
|
||||
} else if (action == @':default') {
|
||||
mysignal(code, SIG_DFL);
|
||||
return Ct;
|
||||
} else if (action == Ct || action == @':catch') {
|
||||
if (code == SIGSEGV) {
|
||||
mysignal(code, sigsegv_handler);
|
||||
}
|
||||
#ifdef SIGBUS
|
||||
else if (code == SIGBUS) {
|
||||
mysignal(code, sigbus_handler);
|
||||
}
|
||||
#endif
|
||||
#ifdef SIGCHLD
|
||||
else if (code == SIGCHLD) {
|
||||
# ifndef ECL_THREADS
|
||||
mysignal(SIGCHLD, non_evil_signal_handler);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
mysignal(code, non_evil_signal_handler);
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
# ifdef ECL_THREADS
|
||||
if (type_of(process) == t_process) {
|
||||
cl_env_ptr env = process->process.env;
|
||||
sigset_t *handled_set = (sigset_t *)env->default_sigmask;
|
||||
if (action == @':mask') {
|
||||
sigaddset(handled_set, code);
|
||||
} else if (action == @':unmask') {
|
||||
sigdelset(handled_set, code);
|
||||
} else {
|
||||
return do_catch_signal(code, Ct, process);
|
||||
}
|
||||
if (env == ecl_process_env()) {
|
||||
pthread_sigmask(SIG_SETMASK, handled_set, NULL);
|
||||
}
|
||||
return Ct;
|
||||
}
|
||||
# endif
|
||||
{
|
||||
sigset_t handled_set;
|
||||
sigprocmask(SIG_SETMASK, NULL, &handled_set);
|
||||
if (action == @':mask') {
|
||||
sigaddset(&handled_set, code);
|
||||
printf(";;; %d masked\n", code);
|
||||
} else if (action == @':unmask') {
|
||||
sigdelset(&handled_set, code);
|
||||
printf(";;; %d unmasked\n", code);
|
||||
} else {
|
||||
return do_catch_signal(code, Ct, process);
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &handled_set, NULL);
|
||||
return Ct;
|
||||
}
|
||||
#else
|
||||
return Cnil;
|
||||
#endif
|
||||
}
|
||||
|
||||
@(defun ext::catch-signal (code flag &key process)
|
||||
@
|
||||
{
|
||||
cl_object output = Cnil;
|
||||
|
|
@ -687,40 +760,7 @@ ecl_check_pending_interrupts(void)
|
|||
#endif
|
||||
for (i = 0; known_signals[i].code >= 0; i++) {
|
||||
if (known_signals[i].code == code_int) {
|
||||
output = Ct;
|
||||
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
|
||||
if (!Null(local)) {
|
||||
sigset_t handled_set;
|
||||
pthread_sigmask(SIG_SETMASK, NULL, &handled_set);
|
||||
if (Null(flag)) {
|
||||
sigdelset(&handled_set, code_int);
|
||||
} else {
|
||||
sigaddset(&handled_set, code_int);
|
||||
}
|
||||
pthread_sigmask(SIG_SETMASK, &handled_set, NULL);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (Null(flag)) {
|
||||
signal(code_int, SIG_DFL);
|
||||
} else if (code_int == SIGSEGV) {
|
||||
mysignal(code_int, sigsegv_handler);
|
||||
}
|
||||
#ifdef SIGBUS
|
||||
else if (code_int == SIGBUS) {
|
||||
mysignal(code_int, sigbus_handler);
|
||||
}
|
||||
#endif
|
||||
#ifdef SIGCHLD
|
||||
else if (code_int == SIGCHLD) {
|
||||
#ifndef ECL_THREADS
|
||||
mysignal(SIGCHLD, non_evil_signal_handler);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
mysignal(code_int, non_evil_signal_handler);
|
||||
}
|
||||
output = do_catch_signal(code_int, flag, process);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1039,17 +1079,17 @@ install_asynchronous_signal_handlers()
|
|||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
static sigset_t sigmask;
|
||||
sigset_t *sigmask = cl_core.default_sigmask = &main_thread_sigmask;
|
||||
cl_core.default_sigmask_bytes = sizeof(sigset_t);
|
||||
# ifdef ECL_THREADS
|
||||
pthread_sigmask(SIG_SETMASK, NULL, &sigmask);
|
||||
pthread_sigmask(SIG_SETMASK, NULL, sigmask);
|
||||
# else
|
||||
sigprocmask(SIG_SETMASK, NULL, &sigmask);
|
||||
sigprocmask(SIG_SETMASK, NULL, sigmask);
|
||||
# endif
|
||||
#endif
|
||||
cl_core.default_sigmask = NULL;
|
||||
#ifdef SIGINT
|
||||
if (ecl_get_option(ECL_OPT_TRAP_SIGINT)) {
|
||||
async_handler(SIGINT, non_evil_signal_handler, &sigmask);
|
||||
async_handler(SIGINT, non_evil_signal_handler, sigmask);
|
||||
}
|
||||
#endif
|
||||
#ifdef SIGCHLD
|
||||
|
|
@ -1057,16 +1097,15 @@ install_asynchronous_signal_handlers()
|
|||
/* We have to set the process signal handler explicitly,
|
||||
* because on many platforms the default is SIG_IGN. */
|
||||
mysignal(SIGCHLD, lisp_signal_handler);
|
||||
async_handler(SIGCHLD, lisp_signal_handler, &sigmask);
|
||||
async_handler(SIGCHLD, lisp_signal_handler, sigmask);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
# if defined(ECL_THREADS)
|
||||
pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
|
||||
pthread_sigmask(SIG_SETMASK, sigmask, NULL);
|
||||
# else
|
||||
sigprocmask(SIG_SETMASK, &sigmask, NULL);
|
||||
sigprocmask(SIG_SETMASK, sigmask, NULL);
|
||||
# endif
|
||||
cl_core.default_sigmask = &sigmask;
|
||||
#endif
|
||||
#ifdef ECL_WINDOWS_THREADS
|
||||
old_W32_exception_filter =
|
||||
|
|
@ -1086,6 +1125,7 @@ static void
|
|||
install_signal_handling_thread()
|
||||
{
|
||||
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
|
||||
ecl_process_env()->default_sigmask = &main_thread_sigmask;
|
||||
if (ecl_get_option(ECL_OPT_SIGNAL_HANDLING_THREAD)) {
|
||||
cl_object fun =
|
||||
ecl_make_cfun((cl_objectfn_fixed)
|
||||
|
|
@ -1128,8 +1168,8 @@ install_process_interrupt_handler()
|
|||
}
|
||||
mysignal(signal, non_evil_signal_handler);
|
||||
#ifdef HAVE_SIGROCMASK
|
||||
sigdelset(cl_core.default_sigmask, signal);
|
||||
pthread_sigmask(SIG_SETMASK, cl_core.default_sigmask, NULL);
|
||||
sigdelset(ecl_process_env()->default_sigmask, signal);
|
||||
pthread_sigmask(SIG_SETMASK, ecl_process_env()->default_sigmask, NULL);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ struct cl_env_struct {
|
|||
cl_object own_process;
|
||||
#endif
|
||||
cl_object pending_interrupt;
|
||||
void *default_sigmask;
|
||||
|
||||
/* The following is a hash table for caching invocations of
|
||||
generic functions. In a multithreaded environment we must
|
||||
|
|
@ -231,8 +232,8 @@ struct cl_core_struct {
|
|||
cl_object signal_queue_lock;
|
||||
#endif
|
||||
cl_object signal_queue;
|
||||
|
||||
void *default_sigmask;
|
||||
void *default_sigmask;
|
||||
cl_index default_sigmask_bytes;
|
||||
|
||||
#ifdef ECL_THREADS
|
||||
cl_index last_var_index;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue