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     public alias remove opSub;
96 
97 
98     /***************************************************************************
99 
100         Adds the specified signal to the set.
101 
102         Params:
103             signal = signal to add to set
104 
105         This method is aliased as opAdd.
106 
107     ***************************************************************************/
108 
109     public void add ( int signal )
110     {
111         sigaddset(&(&this).sigset, signal);
112     }
113 
114     public alias add opAdd;
115 
116 
117     /***************************************************************************
118 
119         Removes the specified signals from the set.
120 
121         Params:
122             signals = signals to remove from set
123 
124         This method is aliased as opSub.
125 
126     ***************************************************************************/
127 
128     public void remove ( in int[] signals )
129     {
130         foreach ( signal; signals )
131         {
132             (&this).remove(signal);
133         }
134     }
135 
136     public alias remove opSub;
137 
138 
139     /***************************************************************************
140 
141         Adds the specified signals to the set.
142 
143         Params:
144             signals = signals to add to set
145 
146         This method is aliased as opAdd.
147 
148     ***************************************************************************/
149 
150     public void add ( in int[] signals )
151     {
152         foreach ( signal; signals )
153         {
154             (&this).add(signal);
155         }
156     }
157 
158     public alias add opAdd;
159 
160 
161     /***************************************************************************
162 
163         Tells whether a signal is in the set.
164 
165         Params:
166             signal = signal to test
167 
168         Returns:
169             true if signal is in set
170 
171     ***************************************************************************/
172 
173     public bool isSet ( int signal )
174     {
175         return !!sigismember(&(&this).sigset, signal);
176     }
177 
178     /***************************************************************************
179 
180         Calls pthread_sigmask() with the set of signals of this instance.
181 
182         Params:
183             how = specifies the operation of pthread_sigmask():
184                   SIG_SETMASK: All signals in the set of this instance this set
185                       will be blocked, and all other signals will be unblocked.
186                   SIG_BLOCK: All signals in the set of this instance this set
187                       will be blocked, and the blocking status of all other
188                       signals will remain unchanged.
189                   SIG_UNBLOCK: All signals in the set of this instance this set
190                       will be unblocked, and the blocking status of all other
191                       signals will remain unchanged.
192 
193         Returns:
194             previous masked signals set (call its sigmask() method to restore
195             the previous state)
196 
197         In:
198             how must be SIG_SETMASK, SIG_BLOCK or SIG_UNBLOCK. Note that
199             ensuring this guarantees that pthread_sigmask() will always
200             succeed.
201 
202     ***************************************************************************/
203 
204     public typeof(this) mask ( int how = SIG_SETMASK )
205     in
206     {
207         switch (how)
208         {
209             case SIG_SETMASK, SIG_BLOCK, SIG_UNBLOCK:
210                 break;
211 
212             default:
213                 assert(false, "invalid pthread_sigmask opcode");
214         }
215     }
216     body
217     {
218         typeof(this) old_set;
219 
220         pthread_sigmask(how, &(&this).sigset, &old_set.sigset);
221 
222         return old_set;
223     }
224 
225     /***************************************************************************
226 
227         Blocks the signals in in the set of this instance in the calling thread.
228         Signals that are not in this set but are already blocked will stay
229         blocked.
230 
231         Returns:
232             previous masked signals set (call its mask() method to restore the
233             previous state)
234 
235     ***************************************************************************/
236 
237     public typeof(this) block ( )
238     {
239         return (&this).mask(SIG_BLOCK);
240     }
241 
242     /***************************************************************************
243 
244         Unblocks the signals in in the set of this instance in the calling
245         thread. Signals that are not in this set but are not blocked will stay
246         unblocked.
247 
248         Returns:
249             previous masked signals set (call its mask() method to restore the
250             previous state)
251 
252     ***************************************************************************/
253 
254     public typeof(this) unblock ( )
255     {
256         return (&this).mask(SIG_UNBLOCK);
257     }
258 
259     /***************************************************************************
260 
261         Executes op with the signals in this set blocked. The signals are
262         automatically unblocked again after op has finished (returned or threw).
263 
264         Params:
265             op = the operation to execute
266 
267     ***************************************************************************/
268 
269     public void callBlocked ( lazy void op )
270     {
271         auto old_sigset = (&this).block();
272 
273         scope ( exit )
274         {
275             debug ( SignalMask )
276             {
277                 sigset_t pending;
278                 sigpending(&pending);
279 
280                 foreach ( signal; (&this).signals )
281                 {
282                     if ( sigismember(&pending, signal) )
283                     {
284                         Stderr.formatln("Signal {} fired while masked", signal);
285                     }
286                 }
287             }
288 
289             old_sigset.mask();
290         }
291 
292         op;
293     }
294 
295     /***************************************************************************
296 
297         Gets the signal mask for the calling thread.
298 
299         Returns:
300             set of currently masked signals for the calling thread
301 
302     ***************************************************************************/
303 
304     public static typeof(this) getCurrent ( )
305     {
306         typeof(this) current_set;
307 
308         pthread_sigmask(SIG_SETMASK, null, &current_set.sigset);
309 
310         return current_set;
311     }
312 
313     /***************************************************************************
314 
315         Cast operator for convenient use of this struct in C functions which
316         accept a sigset_t.
317 
318     ***************************************************************************/
319 
320     public sigset_t opCast ( )
321     {
322         return (&this).sigset;
323     }
324 }