Forward async signals to the scheme_thread.
authorMatt Birkholz <matt@birkholz.chandler.az.us>
Sun, 24 Jul 2011 15:31:49 +0000 (08:31 -0700)
committerMatt Birkholz <matt@birkholz.chandler.az.us>
Sun, 24 Jul 2011 15:31:49 +0000 (08:31 -0700)
Tagged the relevant(?) signos with new signal_descriptor flag ASYNC.

src/gtk/gtkio.c.stay
src/microcode/uxsig.c
src/microcode/uxsig.h

index 198e3db6ea629e111d9adcb2765659635e3488c1..deb35e234256bee661b57206b65cde37a30bab53 100644 (file)
@@ -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 <pthread.h>
 #include <glib.h>
 #include <gtk/gtk.h>
+#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 ());
 }
 \f
-
 /* Gtk Select Registries -- GSLists of GPollFDs. */
 
 /* SELECT_MODE_ -> GIOCondition */
@@ -547,3 +560,135 @@ gtk_select_trace (gboolean trace_p)
 {
   tracing_gtk_select = trace_p;
 }
+\f
+/* 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);
+}
index cc97c6e64478baf0040b7d494075b36e9cd9176e..959f7458c2a018addf6e2d0d87870d686b402b0d 100644 (file)
@@ -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);
+}
 \f
 #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);
 }
 \f
 #define CONTROL_B_INTERRUPT_CHAR 'B'
index cccd2ed71f6395a7403ed71667efc083e68f03f9..544703f7be044c46198f60098bad9128119c2b2d 100644 (file)
@@ -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 */