diff --git a/gdb/extension.c b/gdb/extension.c
index ec1aa138872..47f56914802 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -33,6 +33,7 @@
 #include "guile/guile.h"
 #include <array>
 #include "inferior.h"
+#include "gdbsupport/scoped_signal_handler.h"
 
 static script_sourcer_func source_gdb_script;
 static objfile_script_sourcer_func source_gdb_objfile_script;
@@ -297,28 +298,6 @@ ext_lang_auto_load_enabled (const struct extension_language_defn *extlang)
 }
 
 
-/* RAII class used to temporarily return SIG to its default handler.  */
-
-template<int SIG>
-struct scoped_default_signal
-{
-  scoped_default_signal ()
-  { m_old_sig_handler = signal (SIG, SIG_DFL); }
-
-  ~scoped_default_signal ()
-  { signal (SIG, m_old_sig_handler); }
-
-  DISABLE_COPY_AND_ASSIGN (scoped_default_signal);
-
-private:
-  /* The previous signal handler that needs to be restored.  */
-  sighandler_t m_old_sig_handler;
-};
-
-/* Class to temporarily return SIGINT to its default handler.  */
-
-using scoped_default_sigint = scoped_default_signal<SIGINT>;
-
 /* Functions that iterate over all extension languages.
    These only iterate over external extension languages, not including
    GDB's own extension/scripting language, unless otherwise indicated.  */
@@ -334,7 +313,7 @@ ext_lang_initialization (void)
       if (extlang->ops != nullptr
 	  && extlang->ops->initialize != NULL)
 	{
-	  scoped_default_sigint set_sigint_to_default_handler;
+	  scoped_signal_handler<SIGINT> set_sigint_to_default_handler (SIG_DFL);
 	  extlang->ops->initialize (extlang);
 	}
     }
diff --git a/gdb/record-full.c b/gdb/record-full.c
index d48718a2793..7d7959ffe68 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -39,6 +39,7 @@
 #include "infrun.h"
 #include "gdbsupport/gdb_unlinker.h"
 #include "gdbsupport/byte-vector.h"
+#include "gdbsupport/scoped_signal_handler.h"
 #include "async-event.h"
 #include "top.h"
 #include "valprint.h"
@@ -1159,6 +1160,7 @@ record_full_wait_1 (struct target_ops *ops,
 {
   scoped_restore restore_operation_disable
     = record_full_gdb_operation_disable_set ();
+  scoped_signal_handler<SIGINT> interrupt_handler (record_full_sig_handler);
 
   if (record_debug)
     gdb_printf (gdb_stdlog,
@@ -1179,7 +1181,6 @@ record_full_wait_1 (struct target_ops *ops,
     }
 
   record_full_get_sig = 0;
-  signal (SIGINT, record_full_sig_handler);
 
   record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
 
@@ -1468,8 +1469,6 @@ record_full_wait_1 (struct target_ops *ops,
 	}
     }
 
-  signal (SIGINT, handle_sigint);
-
   return inferior_ptid;
 }
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 2932efc3fc0..28a262d7182 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -19,6 +19,7 @@
 
 #include <ctype.h>
 #include "gdbsupport/gdb_wait.h"
+#include "gdbsupport/scoped_signal_handler.h"
 #include "event-top.h"
 #include "gdbthread.h"
 #include "fnmatch.h"
@@ -3467,18 +3468,7 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout)
   if (timeout > 0)
     {
 #ifdef SIGALRM
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
-      struct sigaction sa, old_sa;
-
-      sa.sa_handler = sigalrm_handler;
-      sigemptyset (&sa.sa_mask);
-      sa.sa_flags = 0;
-      sigaction (SIGALRM, &sa, &old_sa);
-#else
-      sighandler_t ofunc;
-
-      ofunc = signal (SIGALRM, sigalrm_handler);
-#endif
+      scoped_signal_handler<SIGALRM> alarm_restore (sigalrm_handler);
 
       alarm (timeout);
 #endif
@@ -3487,11 +3477,6 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout)
 
 #ifdef SIGALRM
       alarm (0);
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
-      sigaction (SIGALRM, &old_sa, NULL);
-#else
-      signal (SIGALRM, ofunc);
-#endif
 #endif
     }
   else
diff --git a/gdbsupport/scoped_signal_handler.h b/gdbsupport/scoped_signal_handler.h
new file mode 100644
index 00000000000..c6c207a1019
--- /dev/null
+++ b/gdbsupport/scoped_signal_handler.h
@@ -0,0 +1,71 @@
+/* RAII class to install a separate handler for a given signal
+
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 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.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef SCOPED_SIGNAL_HANDLER_H
+#define SCOPED_SIGNAL_HANDLER_H
+
+#include <signal.h>
+
+/* RAII class to set a signal handler for a scope, that will take care of
+   unsetting the handler when the scope is left.
+   This class will try to use sigaction whenever available, following the
+   recommendation on the man page for signal, and only fallback to signal
+   if necessary.  */
+template <int SIG>
+class scoped_signal_handler
+{
+public:
+  scoped_signal_handler (sighandler_t handler)
+  {
+#if defined (HAVE_SIGACTION)
+    struct sigaction act;
+
+    act.sa_handler = handler;
+    sigemptyset (&act.sa_mask);
+    act.sa_flags = 0;
+    sigaction (SIG, &act, &m_prev_handler);
+#else
+    /* The return of the function call is the previous signal handler, or
+       SIG_ERR if the function doesn't succeed.  */
+    m_prev_handler = signal (SIG, handler);
+    /* According to the GNU libc manual, the only way signal fails is if
+       the signum given is invalid, so we should be safe to assert.  */
+    gdb_assert (m_prev_handler != SIG_ERR);
+#endif
+  }
+
+  ~scoped_signal_handler ()
+  {
+#if defined (HAVE_SIGACTION)
+    sigaction (SIG, &m_prev_handler, nullptr);
+#else
+    signal (SIG, m_prev_handler);
+#endif
+  }
+
+  DISABLE_COPY_AND_ASSIGN (scoped_signal_handler);
+private:
+#if defined (HAVE_SIGACTION)
+  struct sigaction m_prev_handler;
+#else
+  typedef sighandler_t m_prev_handler;
+#endif
+};
+
+#endif /* SCOPED_SIGNAL_HANDLER_H  */
