summaryrefslogtreecommitdiffstats
path: root/Modules/signalmodule.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1994-06-23 11:25:45 (GMT)
committerGuido van Rossum <guido@python.org>1994-06-23 11:25:45 (GMT)
commitbb4ba12242052fe708462d2f53729b49828882dc (patch)
treeef189d9d243d85cd1ca48ff49b59b85f2248a099 /Modules/signalmodule.c
parent20882d506754da0c84684e32ba060c627ee19e09 (diff)
downloadcpython-bb4ba12242052fe708462d2f53729b49828882dc.zip
cpython-bb4ba12242052fe708462d2f53729b49828882dc.tar.gz
cpython-bb4ba12242052fe708462d2f53729b49828882dc.tar.bz2
* 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.
Diffstat (limited to 'Modules/signalmodule.c')
-rw-r--r--Modules/signalmodule.c116
1 files changed, 91 insertions, 25 deletions
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index c36a9cf..211ebe7 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 <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;
}