From ad6414327f7e6c919a6e67b3dcc9c28130b6d6c6 Mon Sep 17 00:00:00 2001 From: Matt Birkholz Date: Sun, 24 Jul 2011 08:31:49 -0700 Subject: [PATCH] Forward async signals to the scheme_thread. Tagged the relevant(?) signos with new signal_descriptor flag ASYNC. --- src/gtk/gtkio.c.stay | 153 ++++++++++++++++++++++++++++++++++++++++-- src/microcode/uxsig.c | 55 +++++++++------ src/microcode/uxsig.h | 2 + 3 files changed, 184 insertions(+), 26 deletions(-) diff --git a/src/gtk/gtkio.c.stay b/src/gtk/gtkio.c.stay index 198e3db6e..deb35e234 100644 --- a/src/gtk/gtkio.c.stay +++ b/src/gtk/gtkio.c.stay @@ -23,17 +23,30 @@ USA. /* SchemeSource -- the custom GSource that runs Scheme in an idle task. */ +#include "scheme.h" +#include "option.h" +#include "ux.h" +#include "ossig.h" +#include "osctty.h" +#include "ostty.h" +#include "ostop.h" #include "osio.h" #include "osenv.h" #include "osproc.h" #include "osscheme.h" -#define MIT_SCHEME /* Avoid re-declaring things included above. */ -#include "pruxffi.h" +#include "uxtrap.h" +#include "uxsig.h" +#include "uxutil.h" +#include "critsec.h" + +#include #include #include +#define MIT_SCHEME /* Avoid re-declaring things included above. */ +#include "pruxffi.h" -extern void Interpret (int pop_return_p); extern void alienate_float_environment (void); +static void init_signal_handling (void); struct _SchemeSource { @@ -351,6 +364,7 @@ start_gtk (int *argc, char ***argv) if (scheme_source != NULL) return (initted); + init_signal_handling (); g_thread_init (NULL); gdk_threads_init (); gdk_threads_enter (); @@ -426,7 +440,6 @@ yield_gtk (void) trace (";yield_gtk: runnable at %.1f\n", OS_real_time_clock ()); } - /* Gtk Select Registries -- GSLists of GPollFDs. */ /* SELECT_MODE_ -> GIOCondition */ @@ -547,3 +560,135 @@ gtk_select_trace (gboolean trace_p) { tracing_gtk_select = trace_p; } + +/* signal_forwarder + + This signal handler can run in any thread because it forwards the + signal to the scheme_thread. When the handler (subsequently) finds + itself running in the scheme_thread, it invokes the original + handler. */ + +extern void OS_syserr_names (unsigned long * length, const char *** names); +static const char * errno_name (int err); +static void complain (const char *format, ...); + +static pthread_t scheme_thread; +static GSList *old_handlers = NULL; +struct handler_record +{ + int signo; + Tsignal_handler handler; +}; + +#ifdef HAVE_SIGACTION_SIGINFO_SIGNALS +void +signal_forwarder (int signo, siginfo_t *siginfo, void *ptr) +#else +REGSIGTYPE +signal_forwarder (int signo) +#endif +{ + pthread_t self; + + self = pthread_self (); + if (self == scheme_thread) + { + GSList * scan; + + scan = old_handlers; + while (scan != NULL) + { + struct handler_record * old = scan->data; + if (old->signo == signo) + { + trace ("signal_forwarder: running handler\n"); +#ifdef HAVE_SIGACTION_SIGINFO_SIGNALS + (old->handler)(signo, siginfo, ptr); +#else + (old->handler)(signo); +#endif + return; + } + scan = scan->next; + } + complain (";signal_forwarder: no handler for signo %d\n", signo); + } + else + { + int err; + + trace (";signal_forwarder: forwarding signo %d\n", signo); + err = pthread_kill (scheme_thread, signo); + if (err != 0) + { + complain (";signal_forwarder: pthread_kill failed: %s\n", + errno_name (err)); + sleep (1); + } + } +} + +void +init_signal_forwarder (int signo) +{ + int err; + struct handler_record *hrec; + Tsignal_handler handler; + struct sigaction act; + + err = sigaction (signo, 0, (&act)); + if (err != 0) + complain ("init_signal_forwarder: sigaction access failed\n"); +#ifdef HAVE_SIGACTION_SIGINFO_SIGNALS + handler = act.sa_sigaction; +#else + handler = act.sa_handler; +#endif + if ((handler == ((Tsignal_handler) SIG_DFL)) + || (handler == (Tsignal_handler) SIG_IGN)) + return; + +#ifdef HAVE_SIGACTION_SIGINFO_SIGNALS + act.sa_sigaction = &signal_forwarder; +#else + act.sa_handler = &signal_forwarder; +#endif + + err = sigaction (signo, &act, 0); + if (err != 0) + complain ("init_signal_forwarder: sigaction modify failed\n"); + + hrec = g_malloc (sizeof (struct handler_record)); + hrec->signo = signo; + hrec->handler = handler; + old_handlers = g_slist_prepend (old_handlers, hrec); +} + +void +init_signal_handling (void) +{ + scheme_thread = pthread_self (); + foreach_async_signal (&init_signal_forwarder); +} + +static const char * +errno_name (int err) +{ + unsigned long length; + const char ** names; + OS_syserr_names (&length, &names); + if (err < length) + return names[err]; + else + return "unknown errno"; +} + +static void +complain (const char *format, ...) +{ + va_list args; + va_start (args, format); + voutf_console (format, args); + outf_flush_console (); + va_end (args); +} diff --git a/src/microcode/uxsig.c b/src/microcode/uxsig.c index cc97c6e64..959f7458c 100644 --- a/src/microcode/uxsig.c +++ b/src/microcode/uxsig.c @@ -247,6 +247,7 @@ struct signal_descriptor #define NOBLOCK 2 #define NOCATCH 4 #define CORE_DUMP 8 +#define ASYNC 16 /* Not a trap; thread-indeterminate. */ static struct signal_descriptor * signal_descriptors; static unsigned int signal_descriptors_length; @@ -302,6 +303,16 @@ find_signal_name (int signo) sprintf (buffer, "unknown signal %d", signo); return ((const char *) buffer); } + +void +foreach_async_signal (void(*func)(int signo)) +{ + struct signal_descriptor * scan = signal_descriptors; + struct signal_descriptor * end = (scan + signal_descriptors_length); + for (; (scan < end); scan += 1) + if ((scan -> flags) && ASYNC) + func (scan -> signo); +} #if (SIGABRT == SIGIOT) # undef SIGABRT @@ -322,12 +333,12 @@ initialize_signal_descriptors (void) fflush (stderr); termination_init_error (); } - defsignal (SIGHUP, "SIGHUP", dfl_terminate, 0); - defsignal (SIGINT, "SIGINT", dfl_terminate, 0); - defsignal (SIGQUIT, "SIGQUIT", dfl_terminate, CORE_DUMP); + defsignal (SIGHUP, "SIGHUP", dfl_terminate, ASYNC); + defsignal (SIGINT, "SIGINT", dfl_terminate, ASYNC); + defsignal (SIGQUIT, "SIGQUIT", dfl_terminate, (ASYNC | CORE_DUMP)); defsignal (SIGILL, "SIGILL", dfl_terminate, CORE_DUMP); defsignal (SIGTRAP, "SIGTRAP", dfl_terminate, CORE_DUMP); - defsignal (SIGIOT, "SIGIOT", dfl_terminate, CORE_DUMP); + defsignal (SIGIOT, "SIGIOT", dfl_terminate, (ASYNC | CORE_DUMP)); defsignal (SIGEMT, "SIGEMT", dfl_terminate, CORE_DUMP); #ifdef HAVE_SIGFPE defsignal (SIGFPE, "SIGFPE", dfl_terminate, CORE_DUMP); @@ -337,27 +348,27 @@ initialize_signal_descriptors (void) defsignal (SIGSEGV, "SIGSEGV", dfl_terminate, CORE_DUMP); defsignal (SIGSYS, "SIGSYS", dfl_terminate, CORE_DUMP); defsignal (SIGPIPE, "SIGPIPE", dfl_terminate, 0); - defsignal (SIGALRM, "SIGALRM", dfl_terminate, 0); - defsignal (SIGTERM, "SIGTERM", dfl_terminate, 0); - defsignal (SIGUSR1, "SIGUSR1", dfl_terminate, 0); - defsignal (SIGUSR2, "SIGUSR2", dfl_terminate, 0); - defsignal (SIGABRT, "SIGABRT", dfl_terminate, CORE_DUMP); - defsignal (SIGIO, "SIGIO", dfl_ignore, 0); - defsignal (SIGURG, "SIGURG", dfl_ignore, 0); - defsignal (SIGVTALRM, "SIGVTALRM", dfl_terminate, 0); + defsignal (SIGALRM, "SIGALRM", dfl_terminate, ASYNC); + defsignal (SIGTERM, "SIGTERM", dfl_terminate, ASYNC); + defsignal (SIGUSR1, "SIGUSR1", dfl_terminate, ASYNC); + defsignal (SIGUSR2, "SIGUSR2", dfl_terminate, ASYNC); + defsignal (SIGABRT, "SIGABRT", dfl_terminate, (ASYNC | CORE_DUMP)); + defsignal (SIGIO, "SIGIO", dfl_ignore, ASYNC); + defsignal (SIGURG, "SIGURG", dfl_ignore, ASYNC); + defsignal (SIGVTALRM, "SIGVTALRM", dfl_terminate, ASYNC); defsignal (SIGPROF, "SIGPROF", dfl_terminate, 0); defsignal (SIGSTOP, "SIGSTOP", dfl_stop, (NOIGNORE | NOBLOCK | NOCATCH)); - defsignal (SIGTSTP, "SIGTSTP", dfl_stop, 0); + defsignal (SIGTSTP, "SIGTSTP", dfl_stop, ASYNC); defsignal (SIGCONT, "SIGCONT", dfl_ignore, (NOIGNORE | NOBLOCK)); - defsignal (SIGCHLD, "SIGCHLD", dfl_ignore, 0); - defsignal (SIGTTIN, "SIGTTIN", dfl_stop, 0); - defsignal (SIGTTOU, "SIGTTOU", dfl_stop, 0); - defsignal (SIGLOST, "SIGLOST", dfl_terminate, 0); - defsignal (SIGXCPU, "SIGXCPU", dfl_terminate, 0); - defsignal (SIGXFSZ, "SIGXFSZ", dfl_terminate, 0); - defsignal (SIGPWR, "SIGPWR", dfl_ignore, 0); - defsignal (SIGWINDOW, "SIGWINDOW", dfl_ignore, 0); - defsignal (SIGWINCH, "SIGWINCH", dfl_ignore, 0); + defsignal (SIGCHLD, "SIGCHLD", dfl_ignore, ASYNC); + defsignal (SIGTTIN, "SIGTTIN", dfl_stop, ASYNC); + defsignal (SIGTTOU, "SIGTTOU", dfl_stop, ASYNC); + defsignal (SIGLOST, "SIGLOST", dfl_terminate, ASYNC); + defsignal (SIGXCPU, "SIGXCPU", dfl_terminate, ASYNC); + defsignal (SIGXFSZ, "SIGXFSZ", dfl_terminate, ASYNC); + defsignal (SIGPWR, "SIGPWR", dfl_ignore, ASYNC); + defsignal (SIGWINDOW, "SIGWINDOW", dfl_ignore, ASYNC); + defsignal (SIGWINCH, "SIGWINCH", dfl_ignore, ASYNC); } #define CONTROL_B_INTERRUPT_CHAR 'B' diff --git a/src/microcode/uxsig.h b/src/microcode/uxsig.h index cccd2ed71..544703f7b 100644 --- a/src/microcode/uxsig.h +++ b/src/microcode/uxsig.h @@ -146,4 +146,6 @@ extern void ta_abort_handler (void *); #define record_signal_delivery(signo) #endif +extern void foreach_async_signal (void(*func)(int signo)); + #endif /* SCM_UXSIG_H */ -- 2.25.1