diff --git a/src/CHANGELOG b/src/CHANGELOG index 1087d95c8..6dd91c805 100755 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -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 *** diff --git a/src/c/main.d b/src/c/main.d index d48f4d3f9..45e6cdecc 100644 --- a/src/c/main.d +++ b/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 */ diff --git a/src/c/symbols_list.h b/src/c/symbols_list.h index 43577b02f..8a1732502 100755 --- a/src/c/symbols_list.h +++ b/src/c/symbols_list.h @@ -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}, diff --git a/src/c/symbols_list2.h b/src/c/symbols_list2.h index 557636e7b..73cba053c 100644 --- a/src/c/symbols_list2.h +++ b/src/c/symbols_list2.h @@ -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}, diff --git a/src/c/threads/process.d b/src/c/threads/process.d index 9743ca8f5..0729d0432 100644 --- a/src/c/threads/process.d +++ b/src/c/threads/process.d @@ -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); diff --git a/src/c/unixint.d b/src/c/unixint.d index 770cc2a01..8c1045599 100644 --- a/src/c/unixint.d +++ b/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 diff --git a/src/h/external.h b/src/h/external.h index 9f83db9f3..12d16a35c 100755 --- a/src/h/external.h +++ b/src/h/external.h @@ -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;