build: Don't include <config.h> in native programs when cross-compiling.
[bpt/guile.git] / libguile / scmsigs.c
index 97375e8..f404b6a 100644 (file)
@@ -1,89 +1,57 @@
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2004, 2006,
+ *   2007, 2008, 2009, 2011, 2013, 2014 Free Software Foundation, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- *
- * As a special exception, the Free Software Foundation gives permission
- * for additional uses of the text contained in its release of GUILE.
- *
- * The exception is that, if you link the GUILE library with other files
- * to produce an executable, this does not by itself cause the
- * resulting executable to be covered by the GNU General Public License.
- * Your use of that executable is in no way restricted on account of
- * linking the GUILE library code into it.
- *
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
- *
- * This exception applies only to the code released by the
- * Free Software Foundation under the name GUILE.  If you copy
- * code from other Free Software Foundation releases into a copy of
- * GUILE, as the General Public License permits, the exception does
- * not apply to the code that you add in this way.  To avoid misleading
- * anyone as to the status of such modified files, you must delete
- * this exception notice from them.
- *
- * If you write modifications of your own for GUILE, it is your choice
- * whether to permit this exception to apply to your modifications.
- * If you do not wish that, delete this exception notice.  */
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
 
 
 \f
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <fcntl.h>      /* for mingw */
 #include <signal.h>
+#include <stdio.h>
 #include <errno.h>
 
-#include "libguile/_scm.h"
-
-#include "libguile/async.h"
-#include "libguile/eval.h"
-#include "libguile/root.h"
-#include "libguile/vectors.h"
-
-#include "libguile/validate.h"
-#include "libguile/scmsigs.h"
+#ifdef HAVE_PROCESS_H
+#include <process.h>    /* for mingw */
+#endif
 
-#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#endif
 
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 
-/* The thread system has its own sleep and usleep functions.  */
-#ifndef USE_THREADS
+#include <full-write.h>
 
-#if defined(MISSING_SLEEP_DECL)
-int sleep ();
-#endif
+#include "libguile/_scm.h"
 
-#if defined(HAVE_USLEEP) && defined(MISSING_USLEEP_DECL)
-int usleep ();
-#endif
+#include "libguile/async.h"
+#include "libguile/eval.h"
+#include "libguile/root.h"
+#include "libguile/vectors.h"
+#include "libguile/threads.h"
 
-#endif
+#include "libguile/validate.h"
+#include "libguile/scmsigs.h"
 
-#ifdef __MINGW32__
-#include <windows.h>
-#define alarm(sec) (0)
-/* This weird comma expression is because Sleep is void under Windows. */
-#define sleep(sec) (Sleep ((sec) * 1000), 0)
-#define usleep(usec) (Sleep ((usec) / 1000), 0)
-#define kill(pid, sig) raise (sig)
-#endif
 
 \f
 
@@ -102,18 +70,33 @@ int usleep ();
 \f
 
 /* take_signal is installed as the C signal handler whenever a Scheme
-   handler is set.  when a signal arrives, take_signal marks the corresponding
-   element of got_signal and marks signal_async.  the thunk in signal_async
-   (sys_deliver_signals) will be run at the next opportunity, outside a
-   critical section. sys_deliver_signals runs each Scheme handler for
-   which got_signal is set.  */
+   handler is set.  When a signal arrives, take_signal will write a
+   byte into the 'signal pipe'.  The 'signal delivery thread' will
+   read this pipe and queue the appropriate asyncs.
 
-static SCM signal_async;
+   When Guile is built without threads, the signal handler will
+   install the async directly.
+*/
 
-static char got_signal[NSIG];
 
-/* a Scheme vector of handler procedures.  */
+/* Scheme vectors with information about a signal.  signal_handlers
+   contains the handler procedure or #f, signal_handler_asyncs
+   contains the thunk to be marked as an async when the signal arrives
+   (or the cell with the thunk in a singlethreaded Guile), and
+   signal_handler_threads points to the thread that a signal should be
+   delivered to.
+*/
 static SCM *signal_handlers;
+static SCM signal_handler_asyncs;
+static SCM signal_handler_threads;
+
+/* The signal delivery thread.  */
+scm_i_thread *scm_i_signal_delivery_thread = NULL;
+
+/* The mutex held when launching the signal delivery thread.  */
+static scm_i_pthread_mutex_t signal_delivery_thread_mutex =
+  SCM_I_PTHREAD_MUTEX_INITIALIZER;
+
 
 /* saves the original C handlers, when a new handler is installed.
    set to SIG_ERR if the original handler is installed.  */
@@ -123,115 +106,252 @@ static struct sigaction orig_handlers[NSIG];
 static SIGRETTYPE (*orig_handlers[NSIG])(int);
 #endif
 
+static SCM
+close_1 (SCM proc, SCM arg)
+{
+  return scm_primitive_eval_x (scm_list_3 (scm_sym_lambda, SCM_EOL,
+                                          scm_list_2 (proc, arg)));
+}
+
+#if SCM_USE_PTHREAD_THREADS
+/* On mingw there's no notion of inter-process signals, only a raise()
+   within the process itself which apparently invokes the registered handler
+   immediately.  Not sure how well the following code will cope in this
+   case.  It builds but it may not offer quite the same scheme-level
+   semantics as on a proper system.  If you're relying on much in the way of
+   signal handling on mingw you probably lose anyway.  */
+
+static int signal_pipe[2];
+
 static SIGRETTYPE
 take_signal (int signum)
 {
-  got_signal[signum] = 1;
-  scm_system_async_mark_from_signal_handler (signal_async);
+  char sigbyte = signum;
+  full_write (signal_pipe[1], &sigbyte, 1);
+
+#ifndef HAVE_SIGACTION
+  signal (signum, take_signal);
+#endif
 }
 
+struct signal_pipe_data
+{
+  char sigbyte;
+  ssize_t n;
+  int err;
+};
+
+static void*
+read_signal_pipe_data (void * data)
+{
+  struct signal_pipe_data *sdata = data;
+  
+  sdata->n = read (signal_pipe[0], &sdata->sigbyte, 1);
+  sdata->err = errno;
+
+  return NULL;
+}
+  
 static SCM
-sys_deliver_signals (void)
+signal_delivery_thread (void *data)
 {
-  int i;
+  int sig;
+#if HAVE_PTHREAD_SIGMASK  /* not on mingw, see notes above */
+  sigset_t all_sigs;
+  sigfillset (&all_sigs);
+  scm_i_pthread_sigmask (SIG_SETMASK, &all_sigs, NULL);
+#endif
 
-  for (i = 0; i < NSIG; i++)
+  while (1)
     {
-      if (got_signal[i])
+      struct signal_pipe_data sigdata;
+
+      scm_without_guile (read_signal_pipe_data, &sigdata);
+      
+      sig = sigdata.sigbyte;
+      if (sigdata.n == 1 && sig >= 0 && sig < NSIG)
        {
-         /* The flag is reset before calling the handler in case the
-            handler doesn't return.  If the handler doesn't return
-            but leaves other signals flagged, they their handlers
-            will be applied some time later when the async is checked
-            again.  It would probably be better to reset the flags
-            after doing a longjmp.  */
-         got_signal[i] = 0;
+         SCM h, t;
+
+         h = SCM_SIMPLE_VECTOR_REF (signal_handler_asyncs, sig);
+         t = SCM_SIMPLE_VECTOR_REF (signal_handler_threads, sig);
+         if (scm_is_true (h))
+           scm_system_async_mark_for_thread (h, t);
+       }
+      else if (sigdata.n == 0)
+       break; /* the signal pipe was closed. */
+      else if (sigdata.n < 0 && sigdata.err != EINTR)
+       perror ("error in signal delivery thread");
+    }
+
+  return SCM_UNSPECIFIED; /* not reached unless all other threads exited */
+}
+
+static void
+start_signal_delivery_thread (void)
+{
+  SCM signal_thread;
+
+  scm_i_pthread_mutex_lock (&signal_delivery_thread_mutex);
+
+  if (pipe2 (signal_pipe, O_CLOEXEC) != 0)
+    scm_syserror (NULL);
+  signal_thread = scm_spawn_thread (signal_delivery_thread, NULL,
+                                   scm_handle_by_message,
+                                   "signal delivery thread");
+  scm_i_signal_delivery_thread = SCM_I_THREAD_DATA (signal_thread);
+
+  scm_i_pthread_mutex_unlock (&signal_delivery_thread_mutex);
+}
+
+void
+scm_i_ensure_signal_delivery_thread ()
+{
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_i_pthread_once (&once, start_signal_delivery_thread);
+}
+
+#else /* !SCM_USE_PTHREAD_THREADS */
+
+static SIGRETTYPE
+take_signal (int signum)
+{
+  SCM cell = SCM_SIMPLE_VECTOR_REF (signal_handler_asyncs, signum);
+  scm_i_thread *t = SCM_I_CURRENT_THREAD;
+
+  if (scm_is_false (SCM_CDR (cell)))
+    {
+      SCM_SETCDR (cell, t->active_asyncs);
+      t->active_asyncs = cell;
+      t->pending_asyncs = 1;
+    }
+
 #ifndef HAVE_SIGACTION
-         signal (i, take_signal);
+  signal (signum, take_signal);
 #endif
-         scm_call_1 (SCM_VELTS (*signal_handlers)[i], SCM_MAKINUM (i));
-       }
+}
+
+void
+scm_i_ensure_signal_delivery_thread ()
+{
+  return;
+}
+
+#endif /* !SCM_USE_PTHREAD_THREADS */
+
+static void
+install_handler (int signum, SCM thread, SCM handler)
+{
+  if (scm_is_false (handler))
+    {
+      SCM_SIMPLE_VECTOR_SET (*signal_handlers, signum, SCM_BOOL_F);
+      SCM_SIMPLE_VECTOR_SET (signal_handler_asyncs, signum, SCM_BOOL_F);
     }
-  return SCM_UNSPECIFIED;
+  else
+    {
+      SCM async = close_1 (handler, scm_from_int (signum));
+#if !SCM_USE_PTHREAD_THREADS
+      async = scm_cons (async, SCM_BOOL_F);
+#endif
+      SCM_SIMPLE_VECTOR_SET (*signal_handlers, signum, handler);
+      SCM_SIMPLE_VECTOR_SET (signal_handler_asyncs, signum, async);
+    }
+
+  SCM_SIMPLE_VECTOR_SET (signal_handler_threads, signum, thread);
+}
+
+SCM
+scm_sigaction (SCM signum, SCM handler, SCM flags)
+{
+  return scm_sigaction_for_thread (signum, handler, flags, SCM_UNDEFINED);
 }
 
 /* user interface for installation of signal handlers.  */
-SCM_DEFINE (scm_sigaction, "sigaction", 1, 2, 0,
-           (SCM signum, SCM handler, SCM flags),
+SCM_DEFINE (scm_sigaction_for_thread, "sigaction", 1, 3, 0,
+           (SCM signum, SCM handler, SCM flags, SCM thread),
            "Install or report the signal handler for a specified signal.\n\n"
            "@var{signum} is the signal number, which can be specified using the value\n"
            "of variables such as @code{SIGINT}.\n\n"
-           "If @var{action} is omitted, @code{sigaction} returns a pair: the\n"
+           "If @var{handler} is omitted, @code{sigaction} returns a pair: the\n"
            "CAR is the current\n"
            "signal hander, which will be either an integer with the value @code{SIG_DFL}\n"
            "(default action) or @code{SIG_IGN} (ignore), or the Scheme procedure which\n"
            "handles the signal, or @code{#f} if a non-Scheme procedure handles the\n"
            "signal.  The CDR contains the current @code{sigaction} flags for the handler.\n\n"
-           "If @var{action} is provided, it is installed as the new handler for\n"
-           "@var{signum}.  @var{action} can be a Scheme procedure taking one\n"
+           "If @var{handler} is provided, it is installed as the new handler for\n"
+           "@var{signum}.  @var{handler} can be a Scheme procedure taking one\n"
            "argument, or the value of @code{SIG_DFL} (default action) or\n"
            "@code{SIG_IGN} (ignore), or @code{#f} to restore whatever signal handler\n"
-           "was installed before @code{sigaction} was first used.  Flags can\n"
-           "optionally be specified for the new handler (@code{SA_RESTART} will\n"
-           "always be added if it's available and the system is using restartable\n"
-           "system calls.)  The return value is a pair with information about the\n"
+           "was installed before @code{sigaction} was first used.  When\n"
+           "a scheme procedure has been specified, that procedure will run\n"
+           "in the given @var{thread}.   When no thread has been given, the\n"
+           "thread that made this call to @code{sigaction} is used.\n"
+           "Flags can optionally be specified for the new handler.\n"
+           "The return value is a pair with information about the\n"
            "old handler as described above.\n\n"
            "This interface does not provide access to the \"signal blocking\"\n"
            "facility.  Maybe this is not needed, since the thread support may\n"
            "provide solutions to the problem of consistent access to data\n"
            "structures.")
-#define FUNC_NAME s_scm_sigaction
+#define FUNC_NAME s_scm_sigaction_for_thread
 {
   int csig;
 #ifdef HAVE_SIGACTION
   struct sigaction action;
   struct sigaction old_action;
 #else
-  SIGRETTYPE (* chandler) (int);
+  SIGRETTYPE (* chandler) (int) = SIG_DFL;
   SIGRETTYPE (* old_chandler) (int);
 #endif
   int query_only = 0;
   int save_handler = 0;
-  SCM *scheme_handlers = SCM_VELTS (*signal_handlers);
+      
   SCM old_handler;
 
-  SCM_VALIDATE_INUM_COPY (1,signum,csig);
+  csig = scm_to_signed_integer (signum, 0, NSIG-1);
+
 #if defined(HAVE_SIGACTION)
-#if defined(SA_RESTART) && defined(HAVE_RESTARTABLE_SYSCALLS)
-  /* don't allow SA_RESTART to be omitted if HAVE_RESTARTABLE_SYSCALLS
-     is defined, since libguile would be likely to produce spurious
-     EINTR errors.  */
-  action.sa_flags = SA_RESTART;
-#else
   action.sa_flags = 0;
-#endif
   if (!SCM_UNBNDP (flags))
-    {
-      SCM_VALIDATE_INUM (3,flags);
-      action.sa_flags |= SCM_INUM (flags);
-    }
+    action.sa_flags |= scm_to_int (flags);
   sigemptyset (&action.sa_mask);
 #endif
-  SCM_DEFER_INTS;
-  old_handler = scheme_handlers[csig];
+
+  if (SCM_UNBNDP (thread))
+    thread = scm_current_thread ();
+  else
+    {
+      SCM_VALIDATE_THREAD (4, thread);
+      if (scm_c_thread_exited_p (thread))
+       SCM_MISC_ERROR ("thread has already exited", SCM_EOL);
+    }
+
+  scm_i_ensure_signal_delivery_thread ();
+
+  SCM_CRITICAL_SECTION_START;
+  old_handler = SCM_SIMPLE_VECTOR_REF (*signal_handlers, csig);
   if (SCM_UNBNDP (handler))
     query_only = 1;
-  else if (SCM_EQ_P (scm_integer_p (handler), SCM_BOOL_T))
+  else if (scm_is_integer (handler))
     {
-      if (SCM_NUM2LONG (2, handler) == (long) SIG_DFL
-         || SCM_NUM2LONG (2, handler) == (long) SIG_IGN)
+      long handler_int = scm_to_long (handler);
+
+      if (handler_int == (long) SIG_DFL || handler_int == (long) SIG_IGN)
        {
 #ifdef HAVE_SIGACTION
-         action.sa_handler = (SIGRETTYPE (*) (int)) SCM_INUM (handler);
+         action.sa_handler = (SIGRETTYPE (*) (int)) handler_int;
 #else
-         chandler = (SIGRETTYPE (*) (int)) SCM_INUM (handler);
+         chandler = (SIGRETTYPE (*) (int)) handler_int;
 #endif
-         scheme_handlers[csig] = SCM_BOOL_F;
+         install_handler (csig, SCM_BOOL_F, SCM_BOOL_F);
        }
       else
-       SCM_OUT_OF_RANGE (2, handler);
+       {
+         SCM_CRITICAL_SECTION_END;
+         SCM_OUT_OF_RANGE (2, handler);
+       }
     }
-  else if (SCM_FALSEP (handler))
+  else if (scm_is_false (handler))
     {
       /* restore the default handler.  */
 #ifdef HAVE_SIGACTION
@@ -241,7 +361,7 @@ SCM_DEFINE (scm_sigaction, "sigaction", 1, 2, 0,
        {
          action = orig_handlers[csig];
          orig_handlers[csig].sa_handler = SIG_ERR;
-         scheme_handlers[csig] = SCM_BOOL_F;
+         install_handler (csig, SCM_BOOL_F, SCM_BOOL_F);
        }
 #else
       if (orig_handlers[csig] == SIG_ERR)
@@ -250,13 +370,13 @@ SCM_DEFINE (scm_sigaction, "sigaction", 1, 2, 0,
        {
          chandler = orig_handlers[csig];
          orig_handlers[csig] = SIG_ERR;
-         scheme_handlers[csig] = SCM_BOOL_F;
+         install_handler (csig, SCM_BOOL_F, SCM_BOOL_F);
        }
 #endif
     }
   else
     {
-      SCM_VALIDATE_NIM (2,handler);
+      SCM_VALIDATE_PROC (2, handler);
 #ifdef HAVE_SIGACTION
       action.sa_handler = take_signal;
       if (orig_handlers[csig].sa_handler == SIG_ERR)
@@ -266,7 +386,7 @@ SCM_DEFINE (scm_sigaction, "sigaction", 1, 2, 0,
       if (orig_handlers[csig] == SIG_ERR)
        save_handler = 1;
 #endif
-      scheme_handlers[csig] = handler;
+      install_handler (csig, thread, handler);
     }
 
   /* XXX - Silently ignore setting handlers for `program error signals'
@@ -313,9 +433,9 @@ SCM_DEFINE (scm_sigaction, "sigaction", 1, 2, 0,
        orig_handlers[csig] = old_action;
     }
   if (old_action.sa_handler == SIG_DFL || old_action.sa_handler == SIG_IGN)
-    old_handler = scm_long2num ((long) old_action.sa_handler);
-  SCM_ALLOW_INTS;
-  return scm_cons (old_handler, SCM_MAKINUM (old_action.sa_flags));
+    old_handler = scm_from_long ((long) old_action.sa_handler);
+  SCM_CRITICAL_SECTION_END;
+  return scm_cons (old_handler, scm_from_int (old_action.sa_flags));
 #else
   if (query_only)
     {
@@ -332,9 +452,9 @@ SCM_DEFINE (scm_sigaction, "sigaction", 1, 2, 0,
        orig_handlers[csig] = old_chandler;
     }
   if (old_chandler == SIG_DFL || old_chandler == SIG_IGN)
-    old_handler = scm_long2num ((long) old_chandler);
-  SCM_ALLOW_INTS;
-  return scm_cons (old_handler, SCM_MAKINUM (0));
+    old_handler = scm_from_long ((long) old_chandler);
+  SCM_CRITICAL_SECTION_END;
+  return scm_cons (old_handler, scm_from_int (0));
 #endif
 }
 #undef FUNC_NAME
@@ -346,8 +466,6 @@ SCM_DEFINE (scm_restore_signals, "restore-signals", 0, 0, 0,
 #define FUNC_NAME s_scm_restore_signals
 {
   int i;
-  SCM *scheme_handlers = SCM_VELTS (*signal_handlers);
-
   for (i = 0; i < NSIG; i++)
     {
 #ifdef HAVE_SIGACTION
@@ -356,7 +474,7 @@ SCM_DEFINE (scm_restore_signals, "restore-signals", 0, 0, 0,
          if (sigaction (i, &orig_handlers[i], NULL) == -1)
            SCM_SYSERROR;
          orig_handlers[i].sa_handler = SIG_ERR;
-         scheme_handlers[i] = SCM_BOOL_F;
+         SCM_SIMPLE_VECTOR_SET (*signal_handlers, i, SCM_BOOL_F);
        }
 #else
       if (orig_handlers[i] != SIG_ERR)
@@ -364,7 +482,7 @@ SCM_DEFINE (scm_restore_signals, "restore-signals", 0, 0, 0,
          if (signal (i, orig_handlers[i]) == SIG_ERR)
            SCM_SYSERROR;
          orig_handlers[i] = SIG_ERR;
-         scheme_handlers[i] = SCM_BOOL_F;
+         SCM_SIMPLE_VECTOR_SET (*signal_handlers, i, SCM_BOOL_F);        
        }
 #endif
     }
@@ -372,6 +490,7 @@ SCM_DEFINE (scm_restore_signals, "restore-signals", 0, 0, 0,
 }
 #undef FUNC_NAME
 
+#if HAVE_DECL_ALARM
 SCM_DEFINE (scm_alarm, "alarm", 1, 0, 0,
            (SCM i),
            "Set a timer to raise a @code{SIGALRM} signal after the specified\n"
@@ -384,12 +503,10 @@ SCM_DEFINE (scm_alarm, "alarm", 1, 0, 0,
            "no previous alarm, the return value is zero.")
 #define FUNC_NAME s_scm_alarm
 {
-  unsigned int j;
-  SCM_VALIDATE_INUM (1,i);
-  j = alarm (SCM_INUM (i));
-  return SCM_MAKINUM (j);
+  return scm_from_uint (alarm (scm_to_uint (i)));
 }
 #undef FUNC_NAME
+#endif /* HAVE_ALARM */
 
 #ifdef HAVE_SETITIMER
 SCM_DEFINE (scm_setitimer, "setitimer", 5, 0, 0,
@@ -430,10 +547,10 @@ SCM_DEFINE (scm_setitimer, "setitimer", 5, 0, 0,
   if(rv != 0)
     SCM_SYSERROR;
 
-  return scm_list_2(scm_cons(scm_long2num(old_timer.it_interval.tv_sec),
-                             scm_long2num(old_timer.it_interval.tv_usec)),
-                    scm_cons(scm_long2num(old_timer.it_value.tv_sec),
-                             scm_long2num(old_timer.it_value.tv_usec)));
+  return scm_list_2 (scm_cons (scm_from_long (old_timer.it_interval.tv_sec),
+                              scm_from_long (old_timer.it_interval.tv_usec)),
+                    scm_cons (scm_from_long (old_timer.it_value.tv_sec),
+                              scm_from_long (old_timer.it_value.tv_usec)));
 }
 #undef FUNC_NAME
 #endif /* HAVE_SETITIMER */
@@ -466,10 +583,10 @@ SCM_DEFINE (scm_getitimer, "getitimer", 1, 0, 0,
   if(rv != 0)
     SCM_SYSERROR;
   
-  return scm_list_2(scm_cons(scm_long2num(old_timer.it_interval.tv_sec),
-                             scm_long2num(old_timer.it_interval.tv_usec)),
-                    scm_cons(scm_long2num(old_timer.it_value.tv_sec),
-                             scm_long2num(old_timer.it_value.tv_usec)));
+  return scm_list_2 (scm_cons (scm_from_long (old_timer.it_interval.tv_sec),
+                              scm_from_long (old_timer.it_interval.tv_usec)),
+                    scm_cons (scm_from_long (old_timer.it_value.tv_sec),
+                              scm_from_long (old_timer.it_value.tv_usec)));
 }
 #undef FUNC_NAME
 #endif /* HAVE_GETITIMER */
@@ -492,49 +609,33 @@ SCM_DEFINE (scm_sleep, "sleep", 1, 0, 0,
            (SCM i),
            "Wait for the given number of seconds (an integer) or until a signal\n"
            "arrives.  The return value is zero if the time elapses or the number\n"
-           "of seconds remaining otherwise.")
+           "of seconds remaining otherwise.\n"
+           "\n"
+           "See also @code{usleep}.")
 #define FUNC_NAME s_scm_sleep
 {
-  unsigned long j;
-  SCM_VALIDATE_INUM_MIN (1,i,0);
-#ifdef USE_THREADS
-  j = scm_thread_sleep (SCM_INUM(i));
-#else
-  j = sleep (SCM_INUM(i));
-#endif
-  return scm_ulong2num (j);
+  return scm_from_uint (scm_std_sleep (scm_to_uint (i)));
 }
 #undef FUNC_NAME
 
-#if defined(USE_THREADS) || defined(HAVE_USLEEP) || defined(__MINGW32__)
 SCM_DEFINE (scm_usleep, "usleep", 1, 0, 0,
            (SCM i),
-           "Sleep for I microseconds.  @code{usleep} is not available on\n"
-           "all platforms.")
+           "Wait the given period @var{usecs} microseconds (an integer).\n"
+           "If a signal arrives the wait stops and the return value is the\n"
+           "time remaining, in microseconds.  If the period elapses with no\n"
+           "signal the return is zero.\n"
+           "\n"
+           "On most systems the process scheduler is not microsecond accurate and\n"
+           "the actual period slept by @code{usleep} may be rounded to a system\n"
+           "clock tick boundary.  Traditionally such ticks were 10 milliseconds\n"
+           "apart, and that interval is often still used.\n"
+           "\n"
+           "See also @code{sleep}.")
 #define FUNC_NAME s_scm_usleep
 {
-  SCM_VALIDATE_INUM_MIN (1,i,0);
-
-#ifdef USE_THREADS
-  /* If we have threads, we use the thread system's sleep function.  */
-  {
-    unsigned long j = scm_thread_usleep (SCM_INUM (i));
-    return scm_ulong2num (j);
-  }
-#else
-#ifdef USLEEP_RETURNS_VOID
-  usleep (SCM_INUM (i));
-  return SCM_INUM0;
-#else
-  {
-    int j = usleep (SCM_INUM (i));
-    return SCM_MAKINUM (j);
-  }
-#endif
-#endif
+  return scm_from_ulong (scm_std_usleep (scm_to_ulong (i)));
 }
 #undef FUNC_NAME
-#endif /* USE_THREADS || HAVE_USLEEP || __MINGW32__ */
 
 SCM_DEFINE (scm_raise, "raise", 1, 0, 0,
            (SCM sig),
@@ -542,85 +643,70 @@ SCM_DEFINE (scm_raise, "raise", 1, 0, 0,
            "@var{sig} is as described for the kill procedure.")
 #define FUNC_NAME s_scm_raise
 {
-  SCM_VALIDATE_INUM (1,sig);
-  SCM_DEFER_INTS;
-  if (kill (getpid (), (int) SCM_INUM (sig)) != 0)
+  if (raise (scm_to_int (sig)) != 0)
     SCM_SYSERROR;
-  SCM_ALLOW_INTS;
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
 
 \f
 
+void
+scm_i_close_signal_pipe()
+{
+  /* SIGNAL_DELIVERY_THREAD_MUTEX is only locked while the signal delivery
+     thread is being launched.  The thread that calls this function is
+     already holding the thread admin mutex, so if the delivery thread hasn't
+     been launched at this point, it never will be before shutdown.  */
+  scm_i_pthread_mutex_lock (&signal_delivery_thread_mutex);
+
+#if SCM_USE_PTHREAD_THREADS
+  if (scm_i_signal_delivery_thread != NULL)
+    close (signal_pipe[1]);
+#endif
+
+  scm_i_pthread_mutex_unlock (&signal_delivery_thread_mutex);
+}
+
 void
 scm_init_scmsigs ()
 {
-  SCM thunk;
   int i;
 
   signal_handlers =
     SCM_VARIABLE_LOC (scm_c_define ("signal-handlers",
                                  scm_c_make_vector (NSIG, SCM_BOOL_F)));
-  /* XXX - use scm_c_make_gsubr here instead of `define'? */
-  thunk = scm_c_define_gsubr ("%deliver-signals", 0, 0, 0,
-                             sys_deliver_signals);
-  signal_async = scm_system_async (thunk);
+  signal_handler_asyncs = scm_c_make_vector (NSIG, SCM_BOOL_F);
+  signal_handler_threads = scm_c_make_vector (NSIG, SCM_BOOL_F);
 
   for (i = 0; i < NSIG; i++)
     {
-      got_signal[i] = 0;
 #ifdef HAVE_SIGACTION
       orig_handlers[i].sa_handler = SIG_ERR;
 
 #else
       orig_handlers[i] = SIG_ERR;
 #endif
-
-#ifdef HAVE_RESTARTABLE_SYSCALLS
-      /* If HAVE_RESTARTABLE_SYSCALLS is defined, it's important that
-        signals really are restartable.  don't rely on the same
-        run-time that configure got: reset the default for every signal.
-      */
-#ifdef HAVE_SIGINTERRUPT
-      siginterrupt (i, 0);
-#elif defined(SA_RESTART)
-      {
-       struct sigaction action;
-
-       sigaction (i, NULL, &action);
-       if (!(action.sa_flags & SA_RESTART))
-         {
-           action.sa_flags |= SA_RESTART;
-           sigaction (i, &action, NULL);
-         }
-      }
-#endif
-      /* if neither siginterrupt nor SA_RESTART are available we may
-        as well assume that signals are always restartable.  */
-#endif
     }
 
-  scm_c_define ("NSIG", scm_long2num (NSIG));
-  scm_c_define ("SIG_IGN", scm_long2num ((long) SIG_IGN));
-  scm_c_define ("SIG_DFL", scm_long2num ((long) SIG_DFL));
+  scm_c_define ("NSIG", scm_from_long (NSIG));
+  scm_c_define ("SIG_IGN", scm_from_long ((long) SIG_IGN));
+  scm_c_define ("SIG_DFL", scm_from_long ((long) SIG_DFL));
 #ifdef SA_NOCLDSTOP
-  scm_c_define ("SA_NOCLDSTOP", scm_long2num (SA_NOCLDSTOP));
+  scm_c_define ("SA_NOCLDSTOP", scm_from_long (SA_NOCLDSTOP));
 #endif
 #ifdef SA_RESTART
-  scm_c_define ("SA_RESTART", scm_long2num (SA_RESTART));
+  scm_c_define ("SA_RESTART", scm_from_long (SA_RESTART));
 #endif
 
 #if defined(HAVE_SETITIMER) || defined(HAVE_GETITIMER)
   /* Stuff needed by setitimer and getitimer. */
-  scm_c_define ("ITIMER_REAL", SCM_MAKINUM (ITIMER_REAL));
-  scm_c_define ("ITIMER_VIRTUAL", SCM_MAKINUM (ITIMER_VIRTUAL));
-  scm_c_define ("ITIMER_PROF", SCM_MAKINUM (ITIMER_PROF));
+  scm_c_define ("ITIMER_REAL", scm_from_int (ITIMER_REAL));
+  scm_c_define ("ITIMER_VIRTUAL", scm_from_int (ITIMER_VIRTUAL));
+  scm_c_define ("ITIMER_PROF", scm_from_int (ITIMER_PROF));
 #endif /* defined(HAVE_SETITIMER) || defined(HAVE_GETITIMER) */
 
-#ifndef SCM_MAGIC_SNARFER
 #include "libguile/scmsigs.x"
-#endif
 }