]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
* Modules/signalmodule.c: added thread compatibility (only main
authorGuido van Rossum <guido@python.org>
Thu, 23 Jun 1994 11:25:45 +0000 (11:25 +0000)
committerGuido van Rossum <guido@python.org>
Thu, 23 Jun 1994 11:25:45 +0000 (11:25 +0000)
thread uses signals); much improved efficiency; intrcheck()
doesn't call sigcheck() but only tests and clears the SIGINT
tripped flag.

Modules/signalmodule.c

index c36a9cf07dc045a6f6b03e039e5a393449075f0e..211ebe7cc35fb8788ed51b41f70ec7352ad10b26 100644 (file)
@@ -32,6 +32,42 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <signal.h>
 #include <errno.h>
 
+#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;
        }