1 /*******************************************************************************
2 
3     Posix functions for masking & unmasking signals.
4 
5     Masked signals will not be noted but will not fire. If a signal occurs one
6     or more times while masked, when it is unmasked it will fire immediately.
7     Signals are not queued, so if a signal fires multiple times while masked, it
8     will only fire once upon unmasking.
9 
10     The list of posix signals is defined in ocean.stdc.posix.signal
11 
12     Build flags:
13         -debug=SignalMask: prints debugging information to Stderr
14 
15     Copyright:
16         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
17         All rights reserved.
18 
19     License:
20         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
21         Alternatively, this file may be distributed under the terms of the Tango
22         3-Clause BSD License (see LICENSE_BSD.txt for details).
23 
24 *******************************************************************************/
25 
26 module ocean.sys.SignalMask;
27 
28 import core.sys.posix.signal;
29 
30 debug ( SignalMask ) import ocean.io.Stdout : Stderr;
31 
32 
33 
34 /*******************************************************************************
35 
36     Signal set struct wrapping the C sigset_t and its setter / getter functions.
37 
38     Note that, as this is a struct rather than a class, and thus has no
39     constructor, it is necessary to explicitly call the clear() method before
40     using an instance.
41 
42 *******************************************************************************/
43 
44 public struct SignalSet
45 {
46     /***************************************************************************
47 
48         Signal set.
49 
50     ***************************************************************************/
51 
52     private sigset_t sigset;
53 
54 
55     /***************************************************************************
56 
57         Clears all signals in the set (i.e. sets to the set of no signals).
58 
59     ***************************************************************************/
60 
61     public void clear ( )
62     {
63         sigemptyset(&this.sigset);
64     }
65 
66 
67     /***************************************************************************
68 
69         Sets to the set of all signals.
70 
71     ***************************************************************************/
72 
73     public void setAll ( )
74     {
75         sigfillset(&this.sigset);
76     }
77 
78 
79     /***************************************************************************
80 
81         Removes the specified signal from the set.
82 
83         Params:
84             signal = signal to remove from set
85 
86         This method is aliased as opSub.
87 
88     ***************************************************************************/
89 
90     public void remove ( int signal )
91     {
92         sigdelset(&this.sigset, signal);
93     }
94 
95     /***************************************************************************
96 
97         Adds the specified signal to the set.
98 
99         Params:
100             signal = signal to add to set
101 
102         This method is aliased as opAdd.
103 
104     ***************************************************************************/
105 
106     public void add ( int signal )
107     {
108         sigaddset(&this.sigset, signal);
109     }
110 
111     /***************************************************************************
112 
113         Removes the specified signals from the set.
114 
115         Params:
116             signals = signals to remove from set
117 
118         This method is aliased as opSub.
119 
120     ***************************************************************************/
121 
122     public void remove ( in int[] signals )
123     {
124         foreach ( signal; signals )
125         {
126             this.remove(signal);
127         }
128     }
129 
130     /***************************************************************************
131 
132         Adds the specified signals to the set.
133 
134         Params:
135             signals = signals to add to set
136 
137         This method is aliased as opAdd.
138 
139     ***************************************************************************/
140 
141     public void add ( in int[] signals )
142     {
143         foreach ( signal; signals )
144         {
145             this.add(signal);
146         }
147     }
148 
149     /***************************************************************************
150 
151         Tells whether a signal is in the set.
152 
153         Params:
154             signal = signal to test
155 
156         Returns:
157             true if signal is in set
158 
159     ***************************************************************************/
160 
161     public bool isSet ( int signal )
162     {
163         return !!sigismember(&this.sigset, signal);
164     }
165 
166     /***************************************************************************
167 
168         Calls pthread_sigmask() with the set of signals of this instance.
169 
170         Params:
171             how = specifies the operation of pthread_sigmask():
172                   SIG_SETMASK: All signals in the set of this instance this set
173                       will be blocked, and all other signals will be unblocked.
174                   SIG_BLOCK: All signals in the set of this instance this set
175                       will be blocked, and the blocking status of all other
176                       signals will remain unchanged.
177                   SIG_UNBLOCK: All signals in the set of this instance this set
178                       will be unblocked, and the blocking status of all other
179                       signals will remain unchanged.
180 
181         Returns:
182             previous masked signals set (call its sigmask() method to restore
183             the previous state)
184 
185         In:
186             how must be SIG_SETMASK, SIG_BLOCK or SIG_UNBLOCK. Note that
187             ensuring this guarantees that pthread_sigmask() will always
188             succeed.
189 
190     ***************************************************************************/
191 
192     public typeof(this) mask ( int how = SIG_SETMASK )
193     in
194     {
195         switch (how)
196         {
197             case SIG_SETMASK, SIG_BLOCK, SIG_UNBLOCK:
198                 break;
199 
200             default:
201                 assert(false, "invalid pthread_sigmask opcode");
202         }
203     }
204     do
205     {
206         typeof(this) old_set;
207 
208         pthread_sigmask(how, &this.sigset, &old_set.sigset);
209 
210         return old_set;
211     }
212 
213     /***************************************************************************
214 
215         Blocks the signals in in the set of this instance in the calling thread.
216         Signals that are not in this set but are already blocked will stay
217         blocked.
218 
219         Returns:
220             previous masked signals set (call its mask() method to restore the
221             previous state)
222 
223     ***************************************************************************/
224 
225     public typeof(this) block ( )
226     {
227         return this.mask(SIG_BLOCK);
228     }
229 
230     /***************************************************************************
231 
232         Unblocks the signals in in the set of this instance in the calling
233         thread. Signals that are not in this set but are not blocked will stay
234         unblocked.
235 
236         Returns:
237             previous masked signals set (call its mask() method to restore the
238             previous state)
239 
240     ***************************************************************************/
241 
242     public typeof(this) unblock ( )
243     {
244         return this.mask(SIG_UNBLOCK);
245     }
246 
247     /***************************************************************************
248 
249         Executes op with the signals in this set blocked. The signals are
250         automatically unblocked again after op has finished (returned or threw).
251 
252         Params:
253             op = the operation to execute
254 
255     ***************************************************************************/
256 
257     public void callBlocked ( lazy void op )
258     {
259         auto old_sigset = this.block();
260 
261         scope ( exit )
262         {
263             debug ( SignalMask )
264             {
265                 sigset_t pending;
266                 sigpending(&pending);
267 
268                 foreach ( signal; this.signals )
269                 {
270                     if ( sigismember(&pending, signal) )
271                     {
272                         Stderr.formatln("Signal {} fired while masked", signal);
273                     }
274                 }
275             }
276 
277             old_sigset.mask();
278         }
279 
280         op;
281     }
282 
283     /***************************************************************************
284 
285         Gets the signal mask for the calling thread.
286 
287         Returns:
288             set of currently masked signals for the calling thread
289 
290     ***************************************************************************/
291 
292     public static typeof(this) getCurrent ( )
293     {
294         typeof(this) current_set;
295 
296         pthread_sigmask(SIG_SETMASK, null, &current_set.sigset);
297 
298         return current_set;
299     }
300 
301     /***************************************************************************
302 
303         Cast operator for convenient use of this struct in C functions which
304         accept a sigset_t.
305 
306     ***************************************************************************/
307 
308     public sigset_t opCast ( )
309     {
310         return this.sigset;
311     }
312 }