From bb4ba12242052fe708462d2f53729b49828882dc Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 23 Jun 1994 11:25:45 +0000 Subject: [PATCH] * Modules/signalmodule.c: added thread compatibility (only main thread uses signals); much improved efficiency; intrcheck() doesn't call sigcheck() but only tests and clears the SIGINT tripped flag. --- Modules/signalmodule.c | 116 ++++++++++++++++++++++++++++++++--------- 1 file changed, 91 insertions(+), 25 deletions(-) diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index c36a9cf07dc..211ebe7cc35 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -32,6 +32,42 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#ifndef SIG_ERR +#define SIG_ERR ((RETSIGTYPE (*)())-1) +#endif + +/* + NOTES ON THE INTERACTION BETWEEN SIGNALS AND THREADS + + When threads are supported, we want the following semantics: + + - only the main thread can set a signal handler + - any thread can get a signal handler + - signals are only delivered to the main thread + + I.e. we don't support "synchronous signals" like SIGFPE (catching + this doesn't make much sense in Python anyway) nor do we support + signals as a means of inter-thread communication, since not all + thread implementations support that (at least our thread library + doesn't). + + We still have the problem that in some implementations signals + generated by the keyboard (e.g. SIGINT) are delivered to all + threads (e.g. SGI), while in others (e.g. Solaris) such signals are + delivered to one random thread (an intermediate possibility would + be to deliver it to the main thread -- POSIX???). For now, we have + a working implementation that works in all three cases -- the + handler ignores signals if getpid() isn't the same as in the main + thread. XXX This is a hack. + +*/ + +#ifdef WITH_THREAD +#include "thread.h" +static long main_thread; +static pid_t main_pid; +#endif + struct signalhandler_list { int tripped; object *func; @@ -40,9 +76,9 @@ struct signalhandler_list { static struct signalhandler_list sig_list[NSIG]; static int tripped = 0; /* Speed up sigcheck() when none tripped */ -static object *default_sig_object; -static object *default_ignore_object; -static object *default_int_object; +static object *sig_dfl_object; +static object *sig_ign_object; +static object *default_int_handler_object; static object * default_int_handler(self, arg) @@ -57,8 +93,15 @@ static RETSIGTYPE signal_handler(sig_num) int sig_num; { - tripped++; - sig_list[sig_num].tripped = 1; +#ifdef WITH_THREAD + /* See NOTES section above */ + if (getpid() == main_pid) { +#endif + tripped++; + sig_list[sig_num].tripped = 1; +#ifdef WITH_THREAD + } +#endif (void *)signal(sig_num, &signal_handler); } @@ -74,13 +117,19 @@ signal_signal(self, args) RETSIGTYPE (*func)(); if (!getargs(args, "(iO)", &sig_num, &obj)) return NULL; +#ifdef WITH_THREAD + if (get_thread_ident() != main_thread) { + err_setstr(ValueError, "signal only works in main thread"); + return NULL; + } +#endif if (sig_num < 1 || sig_num >= NSIG) { err_setstr(ValueError, "signal number out of range"); return NULL; } - if (obj == default_ignore_object) + if (obj == sig_ign_object) func = SIG_IGN; - else if (obj == default_sig_object) + else if (obj == sig_dfl_object) func = SIG_DFL; else if (!is_methodobject(obj) && !is_funcobject(obj) && @@ -91,12 +140,14 @@ signal_signal(self, args) } else func = signal_handler; + if (signal(sig_num, func) == SIG_ERR) { + err_errno(RuntimeError); + return NULL; + } old_handler = sig_list[sig_num].func; - /* XXX is it always correct to clear tripped? */ sig_list[sig_num].tripped = 0; INCREF(obj); sig_list[sig_num].func = obj; - signal(sig_num, func); return old_handler; } @@ -122,8 +173,8 @@ signal_getsignal(self, args) /* List of functions defined in the module */ static struct methodlist signal_methods[] = { - {"signal", signal_signal}, - {"getsignal", signal_getsignal}, + {"signal", signal_signal}, + {"getsignal", signal_getsignal}, {NULL, NULL} /* sentinel */ }; @@ -133,21 +184,28 @@ initsignal() object *m, *d, *x; object *b_dict; int i; + +#ifdef WITH_THREAD + main_thread = get_thread_ident(); + main_pid = getpid(); +#endif + /* Create the module and add the functions */ m = initmodule("signal", signal_methods); /* Add some symbolic constants to the module */ d = getmoduledict(m); - default_sig_object = newintobject((long)SIG_DFL); - dictinsert(d, "SIG_IGN", default_sig_object); - default_ignore_object = newintobject((long)SIG_IGN); - dictinsert(d, "SIG_DFL", default_ignore_object); - default_int_object = newmethodobject("default_int_handler", - default_int_handler, - (object *)NULL, - 0); - dictinsert(d, "default_int_handler", default_int_object); + sig_dfl_object = newintobject((long)SIG_DFL); + dictinsert(d, "SIG_DFL", sig_dfl_object); + sig_ign_object = newintobject((long)SIG_IGN); + dictinsert(d, "SIG_IGN", sig_ign_object); + dictinsert(d, "NSIG", newintobject((long)NSIG)); + default_int_handler_object = newmethodobject("default_int_handler", + default_int_handler, + (object *)NULL, + 0); + dictinsert(d, "default_int_handler", default_int_handler_object); sig_list[0].tripped = 0; for (i = 1; i < NSIG; i++) { @@ -156,18 +214,18 @@ initsignal() signal(i, t); sig_list[i].tripped = 0; if (t == SIG_DFL) - sig_list[i].func = default_sig_object; + sig_list[i].func = sig_dfl_object; else if (t == SIG_IGN) - sig_list[i].func = default_ignore_object; + sig_list[i].func = sig_ign_object; else sig_list[i].func = None; /* None of our business */ INCREF(sig_list[i].func); } - if (sig_list[SIGINT].func == default_sig_object) { + if (sig_list[SIGINT].func == sig_dfl_object) { /* Install default int handler */ DECREF(sig_list[SIGINT].func); - sig_list[SIGINT].func = default_int_object; - INCREF(default_int_object); + sig_list[SIGINT].func = default_int_handler_object; + INCREF(default_int_handler_object); signal(SIGINT, &signal_handler); } @@ -319,6 +377,10 @@ sigcheck() object *f; if (!tripped) return 0; +#ifdef WITH_THREAD + if (get_thread_ident() != main_thread) + return 0; +#endif f = getframe(); if (f == NULL) f = None; @@ -356,6 +418,10 @@ int intrcheck() { if (sig_list[SIGINT].tripped) { +#ifdef WITH_THREAD + if (get_thread_ident() != main_thread) + return 0; +#endif sig_list[SIGINT].tripped = 0; return 1; }