forked from Imagelibrary/binutils-gdb
scoped_ignore_signal: Use sigprocmask+sigtimedwait instead of signal
The problem with using signal(...) to temporarily ignore a signal, is that that changes the the signal disposition for the whole process. If multiple threads do it at the same time, you have a race. Fix this by using sigprocmask + sigtimedwait to implement the ignoring instead, if available, which I think probably means everywhere except Windows nowadays. This way, we only change the signal mask for the current thread, so there's no race. Change-Id: Idfe3fb08327ef8cae926f3de9ee81c56a83b1738 gdbsupport/ChangeLog: yyyy-mm-dd Pedro Alves <pedro@palves.net> * scoped_ignore_signal.h (scoped_ignore_signal::scoped_ignore_signal) [HAVE_SIGPROCMASK]: Use sigprocmask to block the signal instead of changing the signal disposition for the whole process. (scoped_ignore_signal::~scoped_ignore_signal) [HAVE_SIGPROCMASK]: Use sigtimedwait and sigprocmask to flush and unblock the signal.
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2021-06-17 Pedro Alves <pedro@palves.net>
|
||||
|
||||
* scoped_ignore_signal.h
|
||||
(scoped_ignore_signal::scoped_ignore_signal)
|
||||
[HAVE_SIGPROCMASK]: Use sigprocmask to block the signal instead of
|
||||
changing the signal disposition for the whole process.
|
||||
(scoped_ignore_signal::~scoped_ignore_signal) [HAVE_SIGPROCMASK]:
|
||||
Use sigtimedwait and sigprocmask to flush and unblock the signal.
|
||||
|
||||
2021-06-17 Pedro Alves <pedro@palves.net>
|
||||
|
||||
* scoped_ignore_sigttou.h: New file, moved from gdb/ and renamed.
|
||||
|
||||
@@ -22,7 +22,10 @@
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/* RAII class used to ignore a signal in a scope. */
|
||||
/* RAII class used to ignore a signal in a scope. If sigprocmask is
|
||||
supported, then the signal is only ignored by the calling thread.
|
||||
Otherwise, the signal disposition is set to SIG_IGN, which affects
|
||||
the whole process. */
|
||||
|
||||
template <int Sig>
|
||||
class scoped_ignore_signal
|
||||
@@ -30,18 +33,48 @@ class scoped_ignore_signal
|
||||
public:
|
||||
scoped_ignore_signal ()
|
||||
{
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t set, old_state;
|
||||
|
||||
sigemptyset (&set);
|
||||
sigaddset (&set, Sig);
|
||||
sigprocmask (SIG_BLOCK, &set, &old_state);
|
||||
m_was_blocked = sigismember (&old_state, Sig);
|
||||
#else
|
||||
m_osig = signal (Sig, SIG_IGN);
|
||||
#endif
|
||||
}
|
||||
|
||||
~scoped_ignore_signal ()
|
||||
{
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
if (!m_was_blocked)
|
||||
{
|
||||
sigset_t set;
|
||||
const timespec zero_timeout = {};
|
||||
|
||||
sigemptyset (&set);
|
||||
sigaddset (&set, Sig);
|
||||
|
||||
/* If we got a pending Sig signal, consume it before
|
||||
unblocking. */
|
||||
sigtimedwait (&set, nullptr, &zero_timeout);
|
||||
|
||||
sigprocmask (SIG_UNBLOCK, &set, nullptr);
|
||||
}
|
||||
#else
|
||||
signal (Sig, m_osig);
|
||||
#endif
|
||||
}
|
||||
|
||||
DISABLE_COPY_AND_ASSIGN (scoped_ignore_signal);
|
||||
|
||||
private:
|
||||
sighandler_t m_osig = nullptr;
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
bool m_was_blocked;
|
||||
#else
|
||||
sighandler_t m_osig;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct scoped_ignore_signal_nop
|
||||
|
||||
Reference in New Issue
Block a user