Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / scmsigs.c
index d9b36c5..497da2f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2004, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2004, 2006, 2007, 2008, 2009, 2011, 2013 Free Software Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
 #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/threads.h"
-
-#include "libguile/validate.h"
-#include "libguile/scmsigs.h"
-
-#ifdef HAVE_IO_H
-#include <io.h>  /* for mingw _pipe() */
-#endif
-
 #ifdef HAVE_PROCESS_H
 #include <process.h>    /* for mingw */
 #endif
 #include <sys/time.h>
 #endif
 
-#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 pipe(fd) _pipe (fd, 256, O_BINARY)
-#endif
-
 #include <full-write.h>
 
+#include "libguile/_scm.h"
+
+#include "libguile/async.h"
+#include "libguile/eval.h"
+#include "libguile/root.h"
+#include "libguile/vectors.h"
+#include "libguile/threads.h"
+
+#include "libguile/validate.h"
+#include "libguile/scmsigs.h"
+
 
 \f
 
@@ -148,22 +135,69 @@ take_signal (int signum)
 #endif
 }
 
+struct signal_pipe_data
+{
+  char sigbyte;
+  ssize_t n;
+  int err;
+};
+
+#ifndef HAVE_GC_GET_SUSPEND_SIGNAL
+static int
+GC_get_suspend_signal (void)
+{
+#if defined SIG_SUSPEND
+  return SIG_SUSPEND;
+#elif defined SIGPWR
+  return SIGPWR;
+#elif defined SIGLOST
+  return SIGLOST;
+#elif defined _SIGRTMIN
+  return _SIGRTMIN + 6;
+#elif defined SIGRTMIN
+  return SIGRTMIN + 6;
+#elif defined __GLIBC__
+  return 32+6;
+#else
+  return SIGUSR1;
+#endif
+}
+#endif /* HAVE_GC_GET_SUSPEND_SIGNAL */
+
+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
 signal_delivery_thread (void *data)
 {
-  int n, sig;
-  char sigbyte;
+  int sig;
 #if HAVE_PTHREAD_SIGMASK  /* not on mingw, see notes above */
   sigset_t all_sigs;
   sigfillset (&all_sigs);
+  /* On libgc 7.1 and earlier, GC_do_blocking doesn't actually do
+     anything.  So in that case, libgc will want to suspend the signal
+     delivery thread, so we need to allow it to do so by unmasking the
+     suspend signal.  */
+  sigdelset (&all_sigs, GC_get_suspend_signal ());
   scm_i_pthread_sigmask (SIG_SETMASK, &all_sigs, NULL);
 #endif
 
   while (1)
     {
-      n = read (signal_pipe[0], &sigbyte, 1);
-      sig = sigbyte;
-      if (n == 1 && sig >= 0 && sig < NSIG)
+      struct signal_pipe_data sigdata;
+
+      scm_without_guile (read_signal_pipe_data, &sigdata);
+      
+      sig = sigdata.sigbyte;
+      if (sigdata.n == 1 && sig >= 0 && sig < NSIG)
        {
          SCM h, t;
 
@@ -172,9 +206,9 @@ signal_delivery_thread (void *data)
          if (scm_is_true (h))
            scm_system_async_mark_for_thread (h, t);
        }
-      else if (n == 0)
+      else if (sigdata.n == 0)
        break; /* the signal pipe was closed. */
-      else if (n < 0 && errno != EINTR)
+      else if (sigdata.n < 0 && sigdata.err != EINTR)
        perror ("error in signal delivery thread");
     }
 
@@ -188,7 +222,7 @@ start_signal_delivery_thread (void)
 
   scm_i_pthread_mutex_lock (&signal_delivery_thread_mutex);
 
-  if (pipe (signal_pipe) != 0)
+  if (pipe2 (signal_pipe, O_CLOEXEC) != 0)
     scm_syserror (NULL);
   signal_thread = scm_spawn_thread (signal_delivery_thread, NULL,
                                    scm_handle_by_message,
@@ -340,7 +374,10 @@ SCM_DEFINE (scm_sigaction_for_thread, "sigaction", 1, 3, 0,
          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_is_false (handler))
     {
@@ -481,6 +518,7 @@ SCM_DEFINE (scm_restore_signals, "restore-signals", 0, 0, 0,
 }
 #undef FUNC_NAME
 
+#if defined HAVE_ALARM && 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"
@@ -496,6 +534,7 @@ SCM_DEFINE (scm_alarm, "alarm", 1, 0, 0,
   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,
@@ -665,10 +704,8 @@ scm_init_scmsigs ()
   signal_handlers =
     SCM_VARIABLE_LOC (scm_c_define ("signal-handlers",
                                  scm_c_make_vector (NSIG, SCM_BOOL_F)));
-  signal_handler_asyncs =
-    scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F));
-  signal_handler_threads =
-    scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F));
+  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++)
     {