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 
37 
38 
39 import ocean.core.Verify;
40 
41 import ocean.io.select.client.model.ISelectClient;
42 
43 import ocean.sys.SignalFD;
44 
45 
46 
47 
48 /*******************************************************************************
49 
50     Signal select event class.
51 
52 *******************************************************************************/
53 
54 public class SignalEvent : ISelectClient
55 {
56     /***************************************************************************
57 
58         Alias for signalfd_siginfo.
59 
60     ***************************************************************************/
61 
62     public alias SignalFD.SignalInfo SignalInfo;
63 
64 
65     /***************************************************************************
66 
67         Signal event.
68 
69     ***************************************************************************/
70 
71     private SignalFD event;
72 
73 
74     /***************************************************************************
75 
76         Signal handler delegate.
77 
78     ***************************************************************************/
79 
80     private alias void delegate ( SignalInfo siginfo ) Handler;
81 
82     private Handler handler;
83 
84 
85     /***************************************************************************
86 
87         Re-usable array of info about signals which fired.
88 
89     ***************************************************************************/
90 
91     private SignalInfo[] siginfos;
92 
93 
94     /***************************************************************************
95 
96         Constructor. Creates the internal SignalFD instance but does not mask
97         the standard handling of the specified signals. When this client is
98         registered with epoll, the signals are masked.
99 
100         The list of signals handled may be extended after construction by
101         calling the register() method.
102 
103         Params:
104             handler = delegate to call when a signal fires (must be non-null)
105             signals = list of signals to handle
106 
107         Throws:
108             SignalErrnoException if the creation of the SignalFD fails
109 
110     ***************************************************************************/
111 
112     public this ( scope Handler handler, int[] signals ... )
113     {
114         verify(handler !is null);
115 
116         this.handler = handler;
117 
118         this.event = new SignalFD(signals, false);
119     }
120 
121 
122     /***************************************************************************
123 
124         Adds the specified signal to the set of signals handled by this client.
125 
126         Params:
127             signal = signal to handle
128 
129         Returns:
130             this instance for chaining
131 
132         Throws:
133             SignalErrnoException if the updating of the SignalFD fails
134 
135     ***************************************************************************/
136 
137     public typeof(this) register ( int signal )
138     {
139         this.event.register(signal, false);
140 
141         return this;
142     }
143 
144 
145     /***************************************************************************
146 
147         Returns:
148             the epoll events to register for.
149 
150     ***************************************************************************/
151 
152     public override Event events ( )
153     {
154         return Event.EPOLLIN;
155     }
156 
157 
158     /***************************************************************************
159 
160         Required by ISelectable interface.
161 
162         Returns:
163             file descriptor used to manage signal event
164 
165     ***************************************************************************/
166 
167     public override Handle fileHandle ( )
168     {
169         return this.event.fileHandle;
170     }
171 
172 
173     /***************************************************************************
174 
175         Checks whether the specified signal is registered to be handled by this
176         client.
177 
178         Params:
179             signal = code of signal to check
180 
181         Returns:
182             true if the specified signal is handled by this client
183 
184     ***************************************************************************/
185 
186     public bool isRegistered ( int signal )
187     {
188         return this.event.isRegistered(signal);
189     }
190 
191 
192     /***************************************************************************
193 
194         Handles events which occurred for the signal event fd.
195 
196         (Implements an abstract super class method.)
197 
198         Returns:
199             always true, to leave event registered with epoll
200 
201     ***************************************************************************/
202 
203     public override bool handle ( Event events )
204     {
205         this.event.handle(this.siginfos);
206 
207         foreach ( siginfo; this.siginfos )
208         {
209             this.handler(siginfo);
210         }
211 
212         return true;
213     }
214 
215 
216     /***************************************************************************
217 
218         Register method, called after this client is registered with the
219         SelectDispatcher.
220 
221         Masks signals handled by this event, meaning that the default signal
222         (interrupt) handler will not deal with them from now.
223 
224     ***************************************************************************/
225 
226     protected override void registered_ ( )
227     {
228         this.event.maskHandledSignals();
229     }
230 
231 
232     /***************************************************************************
233 
234         Unregister method, called after this client is unregistered from the
235         SelectDispatcher.
236 
237         Unmasks signals handled by this event, meaning that the default signal
238         (interrupt) handler will deal with them from now.
239 
240     ***************************************************************************/
241 
242     protected override void unregistered_ ( )
243     {
244         this.event.unmaskHandledSignals();
245     }
246 }
247