emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scratch/igc ceec5ace134: Avoid MPS being interrupted by signals


From: Pip Cet
Subject: scratch/igc ceec5ace134: Avoid MPS being interrupted by signals
Date: Sun, 22 Dec 2024 17:17:05 -0500 (EST)

branch: scratch/igc
commit ceec5ace134081b64dbf46c4fb5702ef5209c5fd
Author: Pip Cet <pipcet@protonmail.com>
Commit: Pip Cet <pipcet@protonmail.com>

    Avoid MPS being interrupted by signals
    
    * src/igc.c (make_igc): Save signal mask.
    (gc_signal_handler_can_run, gc_maybe_quit): New functions.
    * src/lisp.h (gc_maybe_quit, gc_signal_handler_can_run):
    New functions.
    (maybe_quit): Call `gc_maybe_quit'.
    * src/sysdep.c (deliver_process_signal, deliver_thread_signal):
    Call `gc_signal_handler_can_run'.
---
 src/igc.c    | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lisp.h   | 12 ++++++++++++
 src/sysdep.c |  4 ++++
 3 files changed, 65 insertions(+)

diff --git a/src/igc.c b/src/igc.c
index eb72406e529..136667aefea 100644
--- a/src/igc.c
+++ b/src/igc.c
@@ -805,6 +805,15 @@ struct igc
 
   /* Registered threads.  */
   struct igc_thread_list *threads;
+
+  /* Flag to indicate a signal might be pending.  */
+  int signals_pending;
+  /* Per-signal flags.  These are `int' to reduce the chance of
+   * corruption when accessed non-atomically.  */
+  int pending_signals[64];
+  /* The real signal mask we want to restore after handling pending
+   * signals.  */
+  sigset_t signal_mask;
 };
 
 static bool process_one_message (struct igc *gc);
@@ -4593,6 +4602,7 @@ make_igc (void)
   gc->weak_hash_pool = make_pool_awl (gc, gc->weak_hash_fmt, 
weak_hash_find_dependent);
   gc->immovable_fmt = make_dflt_fmt (gc);
   gc->immovable_pool = make_pool_ams (gc, gc->immovable_fmt);
+  sigprocmask(SIG_BLOCK, NULL, &gc->signal_mask);
 
 #ifndef IN_MY_FORK
   root_create_pure (gc);
@@ -4903,6 +4913,45 @@ igc_busy_p (void)
   return mps_arena_busy (global_igc->arena);
 }
 
+/* Return false if this is an inconvenient time to receive signal SIG;
+ * also arrange for it to be re-raised at a more convenient time in that
+ * case.  */
+bool
+gc_signal_handler_can_run (int sig)
+{
+  eassume (sig >= 0);
+  eassert (sig < ARRAYELTS (global_igc->pending_signals));
+  if (igc_busy_p ())
+    {
+      sigset_t sigs;
+      global_igc->signals_pending = 1;
+      global_igc->pending_signals[sig] = 1;
+      sigemptyset (&sigs);
+      sigaddset (&sigs, sig);
+      pthread_sigmask (SIG_BLOCK, &sigs, NULL);
+      /* We cannot raise (sig) here, because there are platforms where
+       * it doesn't work.  */
+      return false;
+    }
+  return true;
+}
+
+/* Called from `maybe_quit'.  This assumes no signals are blocked.  */
+void
+gc_maybe_quit (void)
+{
+  while (global_igc->signals_pending)
+    {
+      global_igc->signals_pending = 0;
+      for (int i = 0; i < ARRAYELTS (global_igc->pending_signals); i++)
+       if (global_igc->pending_signals[i])
+         {
+           global_igc->pending_signals[i] = 0;
+           raise (i);
+         }
+      pthread_sigmask (SIG_SETMASK, &global_igc->signal_mask, NULL);
+    }
+}
 
 DEFUN ("igc--add-extra-dependency", Figc__add_extra_dependency,
        Sigc__add_extra_dependency, 3, 3, 0,
diff --git a/src/lisp.h b/src/lisp.h
index c469793467c..ba688482832 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -46,7 +46,17 @@ INLINE_HEADER_BEGIN
 
 #ifdef HAVE_MPS
 union gc_header;
+extern void gc_maybe_quit (void);
+extern bool gc_signal_handler_can_run (int);
 #else
+INLINE void gc_maybe_quit (void)
+{
+}
+
+INLINE bool gc_signal_handler_can_run (int sig)
+{
+  return true;
+}
 union gc_header { };
 #endif
 
@@ -4232,6 +4242,8 @@ maybe_quit (void)
 {
   if (!NILP (Vquit_flag) || pending_signals)
     probably_quit ();
+
+  gc_maybe_quit ();
 }
 
 /* Process a quit rarely, based on a counter COUNT, for efficiency.
diff --git a/src/sysdep.c b/src/sysdep.c
index bb4892af4af..9270bfa97d9 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -1737,6 +1737,8 @@ static pthread_t main_thread_id;
 void
 deliver_process_signal (int sig, signal_handler_t handler)
 {
+  if (!gc_signal_handler_can_run (sig))
+    return;
   /* Preserve errno, to avoid race conditions with signal handlers that
      might change errno.  Races can occur even in single-threaded hosts.  */
   int old_errno = errno;
@@ -1772,6 +1774,8 @@ static int thread_backtrace_npointers;
 static void
 deliver_thread_signal (int sig, signal_handler_t handler)
 {
+  if (!gc_signal_handler_can_run (sig))
+    return;
   int old_errno = errno;
 
 #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD



reply via email to

[Prev in Thread] Current Thread [Next in Thread]