From 511ed0874d1fb16e926216783f86a9c8cec043c4 Mon Sep 17 00:00:00 2001
From: Matt Birkholz <puck@birchwood-abbey.net>
Date: Sun, 19 Jul 2015 10:31:14 -0700
Subject: [PATCH] Forward SIGCHLD to the io-waiter.

Set/clear the new variable smp_io_blocked around calls to poll/select
so that subprocess_death (SIGCHLD) can wake a blocked processor
without having to ask Scheme which (if any) is running the io-waiter.
Wake the processor with a timer interrupt withOUT fiddling next_timer.
---
 src/microcode/ossmp.h   |  1 +
 src/microcode/prossmp.c |  3 +++
 src/microcode/uxio.c    | 16 ++++++++++++++++
 src/microcode/uxproc.c  | 31 ++++++++++++++++++++++++++++++-
 4 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/src/microcode/ossmp.h b/src/microcode/ossmp.h
index da4b85a02..4eafb5094 100644
--- a/src/microcode/ossmp.h
+++ b/src/microcode/ossmp.h
@@ -58,6 +58,7 @@ struct processor {
 };
 
 extern processor_t *processors;
+extern processor_t *smp_io_blocked;
 extern __thread processor_t *self;
 extern processor_t *gc_processor;
 
diff --git a/src/microcode/prossmp.c b/src/microcode/prossmp.c
index eba3173ec..162fc8356 100644
--- a/src/microcode/prossmp.c
+++ b/src/microcode/prossmp.c
@@ -60,6 +60,9 @@ static processor_t *threads_processor = NULL;
 /* The current pthread's processor. */
 __thread processor_t *self;
 
+/* The io-waiter's processor when it is blocked in test-select-registry. */
+processor_t *smp_io_blocked = NULL;
+
 extern int saved_processor_count;
 extern int saved_processor_heap_size;
 extern int saved_stack_size;
diff --git a/src/microcode/uxio.c b/src/microcode/uxio.c
index 027f7c7e5..5736e4eb1 100644
--- a/src/microcode/uxio.c
+++ b/src/microcode/uxio.c
@@ -33,6 +33,14 @@ USA.
 Tchannel OS_channel_table_size;
 struct channel * channel_table;
 
+#ifdef ENABLE_SMP
+#  define SMP_IO_BLOCKED smp_io_blocked = self
+#  define SMP_IO_UNBLOCKED smp_io_blocked = NULL
+#else
+#  define SMP_IO_BLOCKED do {} while (false)
+#  define SMP_IO_UNBLOCKED do {} while (false)
+#endif
+
 #ifndef HAVE_POLL
 #ifdef HAVE_SELECT
 static struct timeval zero_timeout;
@@ -600,17 +608,21 @@ safe_poll (struct pollfd *fds, nfds_t nfds, int blockp)
 	}
       else
 	{
+	  SMP_IO_BLOCKED;
 	  n = (UX_ppoll (fds, nfds, NULL, &old));
+	  SMP_IO_UNBLOCKED;
 	}
       UX_sigprocmask (SIG_SETMASK, &old, NULL);
     }
 #else /* not HAVE_PPOLL */
     {
+      SMP_IO_BLOCKED;
       INTERRUPTABLE_EXTENT
 	(n, (((OS_process_any_status_change ())
 	      || ((GET_INT_CODE) != 0))
 	     ? ((errno = EINTR), (-1))
 	     : (UX_poll (fds, nfds, (blockp ? INFTIM : 0)))));
+      SMP_IO_UNBLOCKED;
     }
 #endif
 
@@ -814,18 +826,22 @@ safe_select (int nfds, SELECT_TYPE *readfds, SELECT_TYPE *writefds, int blockp)
 	}
       else
 	{
+	  SMP_IO_BLOCKED;
 	  n = (UX_pselect (nfds, readfds, writefds, NULL, NULL, &old));
+	  SMP_IO_UNBLOCKED;
 	}
       UX_sigprocmask (SIG_SETMASK, &old, NULL);
     }
 #else /* not HAVE_PSELECT */
     {
+      SMP_IO_BLOCKED;
       INTERRUPTABLE_EXTENT
 	(n, (((OS_process_any_status_change ())
 	      || ((GET_INT_CODE) != 0))
 	     ? ((errno = EINTR), (-1))
 	     : (UX_select (nfds, readfds, writefds, NULL,
 			   (blockp ? NULL : &zero_timeout)))));
+      SMP_IO_UNBLOCKED;
     }
 #endif
 
diff --git a/src/microcode/uxproc.c b/src/microcode/uxproc.c
index 9ae288029..9dc32b367 100644
--- a/src/microcode/uxproc.c
+++ b/src/microcode/uxproc.c
@@ -58,6 +58,12 @@ static Tprocess foreground_child_process;
 static long process_tick;
 static long sync_tick;
 
+#ifdef ENABLE_SMP
+#  ifdef ENABLE_DEBUGGING_TOOLS
+#    define ENABLE_SMP_DEBUGGING 1
+#  endif
+#endif
+
 #define NEW_RAW_STATUS(process, status, reason) do			\
 {									\
   (PROCESS_RAW_STATUS (process)) = (status);				\
@@ -719,7 +725,14 @@ find_process (pid_t pid)
 static void
 subprocess_death (pid_t pid, int * status)
 {
-  Tprocess process = (find_process (pid));
+  Tprocess process;
+
+#ifdef ENABLE_SMP_DEBUGGING
+  if (smp_trace_p)
+    outf_error_line (";%d subprocess_death: %d blocked", self->id,
+		     (smp_io_blocked != NULL ? smp_io_blocked->id : -1));
+#endif
+  process = (find_process (pid));
   if (process != NO_PROCESS)
     {
       if (WIFEXITED (*status))
@@ -732,6 +745,22 @@ subprocess_death (pid_t pid, int * status)
 	NEW_RAW_STATUS
 	  (process, process_status_signalled, (WTERMSIG (*status)));
     }
+#ifdef ENABLE_SMP
+  if (smp_io_blocked != NULL && smp_io_blocked != self)
+    {
+# ifdef ENABLE_SMP_DEBUGGING
+      if (smp_trace_p)
+	outf_error_line (";%d subprocess_death: interrupting %d",
+			 self->id, smp_io_blocked->id);
+# endif
+      pthread_kill (smp_io_blocked->pthread, SIGALRM);
+# ifdef ENABLE_SMP_DEBUGGING
+      if (smp_trace_p)
+	outf_error_line (";%d subprocess_death: interrupted %d",
+			 self->id, smp_io_blocked->id);
+# endif
+    }
+#endif
 }
 
 static void
-- 
2.25.1