Commit | Line | Data |
---|---|---|
6a7f1c20 PA |
1 | /* Support for ignoring signals. |
2 | ||
3 | Copyright (C) 2021 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #ifndef SCOPED_IGNORE_SIGNAL_H | |
21 | #define SCOPED_IGNORE_SIGNAL_H | |
22 | ||
23 | #include <signal.h> | |
24 | ||
606a4313 PA |
25 | /* RAII class used to ignore a signal in a scope. If sigprocmask is |
26 | supported, then the signal is only ignored by the calling thread. | |
27 | Otherwise, the signal disposition is set to SIG_IGN, which affects | |
336b30e5 PA |
28 | the whole process. If ConsumePending is true, the destructor |
29 | consumes a pending Sig. SIGPIPE for example is queued on the | |
30 | thread even if blocked at the time the pipe is written to. SIGTTOU | |
31 | OTOH is not raised at all if the thread writing to the terminal has | |
32 | it blocked. Because SIGTTOU is sent to the whole process instead | |
33 | of to a specific thread, consuming a pending SIGTTOU in the | |
34 | destructor could consume a signal raised due to actions done by | |
35 | some other thread. */ | |
36 | ||
37 | template <int Sig, bool ConsumePending> | |
6a7f1c20 PA |
38 | class scoped_ignore_signal |
39 | { | |
40 | public: | |
41 | scoped_ignore_signal () | |
42 | { | |
606a4313 PA |
43 | #ifdef HAVE_SIGPROCMASK |
44 | sigset_t set, old_state; | |
45 | ||
46 | sigemptyset (&set); | |
47 | sigaddset (&set, Sig); | |
48 | sigprocmask (SIG_BLOCK, &set, &old_state); | |
49 | m_was_blocked = sigismember (&old_state, Sig); | |
50 | #else | |
6a7f1c20 | 51 | m_osig = signal (Sig, SIG_IGN); |
606a4313 | 52 | #endif |
6a7f1c20 PA |
53 | } |
54 | ||
55 | ~scoped_ignore_signal () | |
56 | { | |
606a4313 PA |
57 | #ifdef HAVE_SIGPROCMASK |
58 | if (!m_was_blocked) | |
59 | { | |
60 | sigset_t set; | |
606a4313 PA |
61 | |
62 | sigemptyset (&set); | |
63 | sigaddset (&set, Sig); | |
64 | ||
65 | /* If we got a pending Sig signal, consume it before | |
66 | unblocking. */ | |
336b30e5 | 67 | if (ConsumePending) |
fa8740b6 SM |
68 | { |
69 | #ifdef HAVE_SIGTIMEDWAIT | |
70 | const timespec zero_timeout = {}; | |
71 | ||
72 | sigtimedwait (&set, nullptr, &zero_timeout); | |
73 | #else | |
74 | sigset_t pending; | |
75 | ||
76 | sigpending (&pending); | |
77 | if (sigismember (&pending, Sig)) | |
78 | sigwait (&set, nullptr); | |
79 | #endif | |
80 | } | |
606a4313 PA |
81 | |
82 | sigprocmask (SIG_UNBLOCK, &set, nullptr); | |
83 | } | |
84 | #else | |
6a7f1c20 | 85 | signal (Sig, m_osig); |
606a4313 | 86 | #endif |
6a7f1c20 PA |
87 | } |
88 | ||
89 | DISABLE_COPY_AND_ASSIGN (scoped_ignore_signal); | |
90 | ||
91 | private: | |
606a4313 PA |
92 | #ifdef HAVE_SIGPROCMASK |
93 | bool m_was_blocked; | |
94 | #else | |
95 | sighandler_t m_osig; | |
96 | #endif | |
6a7f1c20 PA |
97 | }; |
98 | ||
99 | struct scoped_ignore_signal_nop | |
100 | { | |
101 | /* Note, these can't both be "= default", because otherwise the | |
102 | compiler warns that variables of this type are not used. */ | |
103 | scoped_ignore_signal_nop () | |
104 | {} | |
105 | ~scoped_ignore_signal_nop () | |
106 | {} | |
107 | DISABLE_COPY_AND_ASSIGN (scoped_ignore_signal_nop); | |
108 | }; | |
109 | ||
110 | #ifdef SIGPIPE | |
336b30e5 | 111 | using scoped_ignore_sigpipe = scoped_ignore_signal<SIGPIPE, true>; |
6a7f1c20 PA |
112 | #else |
113 | using scoped_ignore_sigpipe = scoped_ignore_signal_nop; | |
114 | #endif | |
115 | ||
116 | #endif /* SCOPED_IGNORE_SIGNAL_H */ |