1 /*******************************************************************************
2 
3     Linux signal file descriptor event for use with epoll.
4 
5     Allows signals to be handled as events in epoll, rather than as interrupts.
6     One or more signals can be specified. Once the SignalEvent is registered,
7     the default interrupt-based signal handlers will no longer receive these
8     events, and they will cause this select client's event to fire in epoll
9     instead. When the fired event is handled, a user-provided delegate is
10     called, which receives a SignalInfo struct (see ocean.sys.SignalFD)
11     providing information about the signal which fired.
12 
13     Note that when the SignalEvent is unregistered from epoll, the interrupt-
14     based signal handlers are automatically reinstated.
15 
16     Warning: signalfd behaves poorly in multi-threaded programs, (including
17     programs using third party libraries which use threads internally).
18     SignalEvents are triggered only if signals are masked in all threads.
19     Ensuring that this condition is met is often impossible, particularly if
20     threads are created inside third-party libraries. For this reason it is
21     generally more reliable to use a signal handler rather than a SignalEvent.
22 
23     Copyright:
24         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
25         All rights reserved.
26 
27     License:
28         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
29         Alternatively, this file may be distributed under the terms of the Tango
30         3-Clause BSD License (see LICENSE_BSD.txt for details).
31 
32 *******************************************************************************/
33 
34 module ocean.io.select.client.SignalEvent;
35 
36 import ocean.core.Verify;
37 import ocean.io.select.client.model.ISelectClient;
38 import ocean.sys.SignalFD;
39 
40 
41 /*******************************************************************************
42 
43     Signal select event class.
44 
45 *******************************************************************************/
46 
47 public class SignalEvent : ISelectClient
48 {
49     /***************************************************************************
50 
51         Alias for signalfd_siginfo.
52 
53     ***************************************************************************/
54 
55     public alias SignalFD.SignalInfo SignalInfo;
56 
57 
58     /***************************************************************************
59 
60         Signal event.
61 
62     ***************************************************************************/
63 
64     private SignalFD event;
65 
66 
67     /***************************************************************************
68 
69         Signal handler delegate.
70 
71     ***************************************************************************/
72 
73     private alias void delegate ( SignalInfo siginfo ) Handler;
74 
75     private Handler handler;
76 
77 
78     /***************************************************************************
79 
80         Re-usable array of info about signals which fired.
81 
82     ***************************************************************************/
83 
84     private SignalInfo[] siginfos;
85 
86 
87     /***************************************************************************
88 
89         Constructor. Creates the internal SignalFD instance but does not mask
90         the standard handling of the specified signals. When this client is
91         registered with epoll, the signals are masked.
92 
93         The list of signals handled may be extended after construction by
94         calling the register() method.
95 
96         Params:
97             handler = delegate to call when a signal fires (must be non-null)
98             signals = list of signals to handle
99 
100         Throws:
101             SignalErrnoException if the creation of the SignalFD fails
102 
103     ***************************************************************************/
104 
105     public this ( scope Handler handler, int[] signals ... )
106     {
107         verify(handler !is null);
108 
109         this.handler = handler;
110 
111         this.event = new SignalFD(signals, false);
112     }
113 
114 
115     /***************************************************************************
116 
117         Adds the specified signal to the set of signals handled by this client.
118 
119         Params:
120             signal = signal to handle
121 
122         Returns:
123             this instance for chaining
124 
125         Throws:
126             SignalErrnoException if the updating of the SignalFD fails
127 
128     ***************************************************************************/
129 
130     public typeof(this) register ( int signal )
131     {
132         this.event.register(signal, false);
133 
134         return this;
135     }
136 
137 
138     /***************************************************************************
139 
140         Returns:
141             the epoll events to register for.
142 
143     ***************************************************************************/
144 
145     public override Event events ( )
146     {
147         return Event.EPOLLIN;
148     }
149 
150 
151     /***************************************************************************
152 
153         Required by ISelectable interface.
154 
155         Returns:
156             file descriptor used to manage signal event
157 
158     ***************************************************************************/
159 
160     public override Handle fileHandle ( )
161     {
162         return this.event.fileHandle;
163     }
164 
165 
166     /***************************************************************************
167 
168         Checks whether the specified signal is registered to be handled by this
169         client.
170 
171         Params:
172             signal = code of signal to check
173 
174         Returns:
175             true if the specified signal is handled by this client
176 
177     ***************************************************************************/
178 
179     public bool isRegistered ( int signal )
180     {
181         return this.event.isRegistered(signal);
182     }
183 
184 
185     /***************************************************************************
186 
187         Handles events which occurred for the signal event fd.
188 
189         (Implements an abstract super class method.)
190 
191         Returns:
192             always true, to leave event registered with epoll
193 
194     ***************************************************************************/
195 
196     public override bool handle ( Event events )
197     {
198         this.event.handle(this.siginfos);
199 
200         foreach ( siginfo; this.siginfos )
201         {
202             this.handler(siginfo);
203         }
204 
205         return true;
206     }
207 
208 
209     /***************************************************************************
210 
211         Register method, called after this client is registered with the
212         SelectDispatcher.
213 
214         Masks signals handled by this event, meaning that the default signal
215         (interrupt) handler will not deal with them from now.
216 
217     ***************************************************************************/
218 
219     protected override void registered_ ( )
220     {
221         this.event.maskHandledSignals();
222     }
223 
224 
225     /***************************************************************************
226 
227         Unregister method, called after this client is unregistered from the
228         SelectDispatcher.
229 
230         Unmasks signals handled by this event, meaning that the default signal
231         (interrupt) handler will deal with them from now.
232 
233     ***************************************************************************/
234 
235     protected override void unregistered_ ( )
236     {
237         this.event.unmaskHandledSignals();
238     }
239 }