* 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.
This commit is contained in:
parent
20882d5067
commit
bb4ba12242
|
@ -32,6 +32,42 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <errno.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 {
|
struct signalhandler_list {
|
||||||
int tripped;
|
int tripped;
|
||||||
object *func;
|
object *func;
|
||||||
|
@ -40,9 +76,9 @@ struct signalhandler_list {
|
||||||
static struct signalhandler_list sig_list[NSIG];
|
static struct signalhandler_list sig_list[NSIG];
|
||||||
static int tripped = 0; /* Speed up sigcheck() when none tripped */
|
static int tripped = 0; /* Speed up sigcheck() when none tripped */
|
||||||
|
|
||||||
static object *default_sig_object;
|
static object *sig_dfl_object;
|
||||||
static object *default_ignore_object;
|
static object *sig_ign_object;
|
||||||
static object *default_int_object;
|
static object *default_int_handler_object;
|
||||||
|
|
||||||
static object *
|
static object *
|
||||||
default_int_handler(self, arg)
|
default_int_handler(self, arg)
|
||||||
|
@ -57,8 +93,15 @@ static RETSIGTYPE
|
||||||
signal_handler(sig_num)
|
signal_handler(sig_num)
|
||||||
int sig_num;
|
int sig_num;
|
||||||
{
|
{
|
||||||
tripped++;
|
#ifdef WITH_THREAD
|
||||||
sig_list[sig_num].tripped = 1;
|
/* 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);
|
(void *)signal(sig_num, &signal_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,13 +117,19 @@ signal_signal(self, args)
|
||||||
RETSIGTYPE (*func)();
|
RETSIGTYPE (*func)();
|
||||||
if (!getargs(args, "(iO)", &sig_num, &obj))
|
if (!getargs(args, "(iO)", &sig_num, &obj))
|
||||||
return NULL;
|
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) {
|
if (sig_num < 1 || sig_num >= NSIG) {
|
||||||
err_setstr(ValueError, "signal number out of range");
|
err_setstr(ValueError, "signal number out of range");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (obj == default_ignore_object)
|
if (obj == sig_ign_object)
|
||||||
func = SIG_IGN;
|
func = SIG_IGN;
|
||||||
else if (obj == default_sig_object)
|
else if (obj == sig_dfl_object)
|
||||||
func = SIG_DFL;
|
func = SIG_DFL;
|
||||||
else if (!is_methodobject(obj) &&
|
else if (!is_methodobject(obj) &&
|
||||||
!is_funcobject(obj) &&
|
!is_funcobject(obj) &&
|
||||||
|
@ -91,12 +140,14 @@ signal_signal(self, args)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
func = signal_handler;
|
func = signal_handler;
|
||||||
|
if (signal(sig_num, func) == SIG_ERR) {
|
||||||
|
err_errno(RuntimeError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
old_handler = sig_list[sig_num].func;
|
old_handler = sig_list[sig_num].func;
|
||||||
/* XXX is it always correct to clear tripped? */
|
|
||||||
sig_list[sig_num].tripped = 0;
|
sig_list[sig_num].tripped = 0;
|
||||||
INCREF(obj);
|
INCREF(obj);
|
||||||
sig_list[sig_num].func = obj;
|
sig_list[sig_num].func = obj;
|
||||||
signal(sig_num, func);
|
|
||||||
return old_handler;
|
return old_handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +173,8 @@ signal_getsignal(self, args)
|
||||||
/* List of functions defined in the module */
|
/* List of functions defined in the module */
|
||||||
|
|
||||||
static struct methodlist signal_methods[] = {
|
static struct methodlist signal_methods[] = {
|
||||||
{"signal", signal_signal},
|
{"signal", signal_signal},
|
||||||
{"getsignal", signal_getsignal},
|
{"getsignal", signal_getsignal},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,21 +184,28 @@ initsignal()
|
||||||
object *m, *d, *x;
|
object *m, *d, *x;
|
||||||
object *b_dict;
|
object *b_dict;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
#ifdef WITH_THREAD
|
||||||
|
main_thread = get_thread_ident();
|
||||||
|
main_pid = getpid();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Create the module and add the functions */
|
/* Create the module and add the functions */
|
||||||
m = initmodule("signal", signal_methods);
|
m = initmodule("signal", signal_methods);
|
||||||
|
|
||||||
/* Add some symbolic constants to the module */
|
/* Add some symbolic constants to the module */
|
||||||
d = getmoduledict(m);
|
d = getmoduledict(m);
|
||||||
|
|
||||||
default_sig_object = newintobject((long)SIG_DFL);
|
sig_dfl_object = newintobject((long)SIG_DFL);
|
||||||
dictinsert(d, "SIG_IGN", default_sig_object);
|
dictinsert(d, "SIG_DFL", sig_dfl_object);
|
||||||
default_ignore_object = newintobject((long)SIG_IGN);
|
sig_ign_object = newintobject((long)SIG_IGN);
|
||||||
dictinsert(d, "SIG_DFL", default_ignore_object);
|
dictinsert(d, "SIG_IGN", sig_ign_object);
|
||||||
default_int_object = newmethodobject("default_int_handler",
|
dictinsert(d, "NSIG", newintobject((long)NSIG));
|
||||||
default_int_handler,
|
default_int_handler_object = newmethodobject("default_int_handler",
|
||||||
(object *)NULL,
|
default_int_handler,
|
||||||
0);
|
(object *)NULL,
|
||||||
dictinsert(d, "default_int_handler", default_int_object);
|
0);
|
||||||
|
dictinsert(d, "default_int_handler", default_int_handler_object);
|
||||||
|
|
||||||
sig_list[0].tripped = 0;
|
sig_list[0].tripped = 0;
|
||||||
for (i = 1; i < NSIG; i++) {
|
for (i = 1; i < NSIG; i++) {
|
||||||
|
@ -156,18 +214,18 @@ initsignal()
|
||||||
signal(i, t);
|
signal(i, t);
|
||||||
sig_list[i].tripped = 0;
|
sig_list[i].tripped = 0;
|
||||||
if (t == SIG_DFL)
|
if (t == SIG_DFL)
|
||||||
sig_list[i].func = default_sig_object;
|
sig_list[i].func = sig_dfl_object;
|
||||||
else if (t == SIG_IGN)
|
else if (t == SIG_IGN)
|
||||||
sig_list[i].func = default_ignore_object;
|
sig_list[i].func = sig_ign_object;
|
||||||
else
|
else
|
||||||
sig_list[i].func = None; /* None of our business */
|
sig_list[i].func = None; /* None of our business */
|
||||||
INCREF(sig_list[i].func);
|
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 */
|
/* Install default int handler */
|
||||||
DECREF(sig_list[SIGINT].func);
|
DECREF(sig_list[SIGINT].func);
|
||||||
sig_list[SIGINT].func = default_int_object;
|
sig_list[SIGINT].func = default_int_handler_object;
|
||||||
INCREF(default_int_object);
|
INCREF(default_int_handler_object);
|
||||||
signal(SIGINT, &signal_handler);
|
signal(SIGINT, &signal_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,6 +377,10 @@ sigcheck()
|
||||||
object *f;
|
object *f;
|
||||||
if (!tripped)
|
if (!tripped)
|
||||||
return 0;
|
return 0;
|
||||||
|
#ifdef WITH_THREAD
|
||||||
|
if (get_thread_ident() != main_thread)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
f = getframe();
|
f = getframe();
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
f = None;
|
f = None;
|
||||||
|
@ -356,6 +418,10 @@ int
|
||||||
intrcheck()
|
intrcheck()
|
||||||
{
|
{
|
||||||
if (sig_list[SIGINT].tripped) {
|
if (sig_list[SIGINT].tripped) {
|
||||||
|
#ifdef WITH_THREAD
|
||||||
|
if (get_thread_ident() != main_thread)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
sig_list[SIGINT].tripped = 0;
|
sig_list[SIGINT].tripped = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue