/* 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
{
if (scheme_source != NULL)
return (initted);
+ init_signal_handling ();
g_thread_init (NULL);
gdk_threads_init ();
gdk_threads_enter ();
trace (";yield_gtk: runnable at %.1f\n", OS_real_time_clock ());
}
\f
-
/* Gtk Select Registries -- GSLists of GPollFDs. */
/* SELECT_MODE_ -> GIOCondition */
{
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);
+}
#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;
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
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);
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'