1 /*******************************************************************************
2 3 Application extension which handles signals to the process and calls the
4 onSignal() method of all registered extensions (see ISignalExtExtension).
5 The extension can handle any number of different signals -- depending solely
6 on which signals are specified in the constructor.
7 8 Note: not only must the extension be registered with the application but its
9 internal ISelectClient (returned by the selectClient() method) must also be
10 registered with an epoll instance! Until the event is registered with epoll
11 and the event loop started, the signal handlers will not be called in
12 response to signals which have occurred.
13 14 Usage example:
15 16 ---
17 18 import ocean.util.app.Application;
19 import ocean.util.app.ext.SignalExt;
20 import ocean.io.select.EpollSelectDispatcher;
21 import core.sys.posix.signal : SIGINT, SIGTERM;
22 23 // Example application class which does two things:
24 // 1. Owns an instance of SignalExtension and registers some signals
25 // with it.
26 // 2. Implements ISignalExtExtension to be notified when registered
27 // signals occur.
28 29 // It's important to understand that these two things are not connected.
30 // It's perfectly possible for an application class to own a SignalExt
31 // but for another class (indeed other classes) elsewhere to implement
32 // ISignalExtExtension to receive the notification of signals occurring.
33 class MyApp : Application, ISignalExtExtension
34 {
35 private SignalExt signal_ext;
36 37 this ( )
38 {
39 super("name", "desc");
40 41 // Construct a signal extension instance and tell it which
42 // signals we're interested in. The list of signals can be
43 // extended after construction via the register() method.
44 auto signals = [SIGINT, SIGTERM];
45 this.signal_ext = new SignalExt(signals);
46 47 // Register the signal extension with the application class
48 // (this).
49 this.registerExtension(this.signal_ext);
50 51 // Register this class with the signal extension so that it will
52 // be notified (via its onSignal() method, below) when one of
53 // the registered signals occurs.
54 this.signal_ext.registerExtension(this);
55 }
56 57 // Signal handler callback required by ISignalExtExtension. Called
58 // when a signal which has been registered with the signal extension
59 // occurs.
60 override void onSignal ( int signum )
61 {
62 }
63 64 // Application main method required by Application.
65 override int run ( char[][] args )
66 {
67 // Important: onSignal() will not be called until the signal
68 // extension's event has been registered with epoll!
69 auto epoll = new EpollSelectDispatcher;
70 epoll.register(this.signal_ext.selectClient());
71 epoll.eventLoop();
72 73 return 0;
74 }
75 }
76 77 ---
78 79 Copyright:
80 Copyright (c) 2009-2016 dunnhumby Germany GmbH.
81 All rights reserved.
82 83 License:
84 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
85 Alternatively, this file may be distributed under the terms of the Tango
86 3-Clause BSD License (see LICENSE_BSD.txt for details).
87 88 *******************************************************************************/89 90 moduleocean.util.app.ext.SignalExt;
91 92 93 94 importocean.transition;
95 importocean.core.Verify;
96 97 importocean.util.app.model.IApplicationExtension;
98 importocean.util.app.model.ExtensibleClassMixin;
99 100 importocean.util.app.Application;
101 102 importocean.util.app.ext.model.ISignalExtExtension;
103 104 importocean.sys.Pipe;
105 106 publicclassSignalExt : IApplicationExtension107 {
108 importcore.sys.posix.signal;
109 110 importocean.application.components.Signals;
111 112 // For SignalErrnoException113 importocean.sys.SignalFD;
114 115 importocean.io.select.protocol.SelectReader;
116 importocean.io.device.IODevice;
117 importocean.io.device.Device;
118 importocean.io.device.Conduit: ISelectable;
119 importocean.io.select.client.model.ISelectClient;
120 121 /***************************************************************************
122 123 Adds a list of extensions (this.extensions) and methods to handle them.
124 See ExtensibleClassMixin documentation for details.
125 126 ***************************************************************************/127 128 mixinExtensibleClassMixin!(ISignalExtExtension);
129 130 /***************************************************************************
131 132 Signal handlers wrapper.
133 134 ***************************************************************************/135 136 privateSignalssignals;
137 138 /***************************************************************************
139 140 Constructor. Creates the internal signal event, handling the specified
141 signals. The event (accessible via the event() method) must be
142 registered with epoll.
143 144 The list of signals handled may be extended after construction by
145 calling the register() method.
146 147 Note that the signals will be handled with a delay of up to single
148 epoll cycle. This is because the signal extension is synced with the
149 EpollSelectDispatcher. This makes it unsuitable to handle critical
150 signals (like `SIGABRT` or `SIGSEGV`) where the application shouldn't
151 be allowed to proceed in the general case; for these cases setup an
152 asynchronous signal handler using `sigaction` instead.
153 154 Params:
155 signals = list of signals to handle
156 ignore_signals = list of signals to ignore
157 158 Throws:
159 SignalErrnoException if setting up the signal handling fails
160 161 ***************************************************************************/162 163 publicthis ( int[] signals, int[] ignore_signals = null )
164 {
165 this.signals = newSignals(&this.handleSignals);
166 this.signals.handle(signals);
167 this.signals.ignore(ignore_signals);
168 }
169 170 /***************************************************************************
171 172 Ignores the signals.
173 174 Params:
175 signals = list of signals to ignore
176 177 Throws:
178 SignalErrnoException if setting up the signal fails
179 180 ***************************************************************************/181 182 publicvoidignore ( inint[] signals )
183 {
184 this.signals.ignore(signals);
185 }
186 187 /***************************************************************************
188 189 Adds the specified signal to the set of signals handled by this
190 extension.
191 192 Params:
193 signal = signal to handle
194 195 Returns:
196 this instance for chaining
197 198 Throws:
199 SignalErrnoException if the updating the signal handling fails
200 201 ***************************************************************************/202 203 publictypeof(this) register ( intsignal )
204 {
205 this.signals.handle(cast(int[])(&signal)[0..1]);
206 207 returnthis;
208 }
209 210 211 /***************************************************************************
212 213 ISelectClient getter, for registering with epoll.
214 215 Returns:
216 ISelectClient interface to register with epoll
217 218 ***************************************************************************/219 220 publicISelectClientselectClient ( )
221 {
222 returnthis.signals.selectClient();
223 }
224 225 226 /***************************************************************************
227 228 Extension order. This extension uses -2_000 because it should be called
229 before the LogExt and StatsExt.
230 231 Returns:
232 the extension order
233 234 ***************************************************************************/235 236 publicoverrideintorder ( )
237 {
238 return -2_000;
239 }
240 241 242 /***************************************************************************
243 244 Signal handler delegate, called from epoll when a signal has fired. In
245 turn notifies all registered extensions about the signal.
246 247 Params:
248 signals = info about signals which have fired
249 250 ***************************************************************************/251 252 privatevoidhandleSignals ( int[] signals )
253 {
254 foreach ( ext; this.extensions )
255 {
256 foreach (signal; signals)
257 {
258 ext.onSignal(signal);
259 }
260 }
261 }
262 263 /***************************************************************************
264 265 atExit IApplicationExtension method.
266 267 Should restore the original signal handlers.
268 269 ***************************************************************************/270 271 publicoverridevoidatExit ( IApplicationapp, istring[] args, intstatus,
272 ExitExceptionexception )
273 {
274 this.signals.clear();
275 }
276 277 /***************************************************************************
278 279 Unused IApplicationExtension methods.
280 281 We just need to provide an "empty" implementation to satisfy the
282 interface.
283 284 ***************************************************************************/285 286 publicoverridevoidpreRun ( IApplicationapp, istring[] args )
287 {
288 }
289 290 /// ditto291 publicoverridevoidpostRun ( IApplicationapp, istring[] args, intstatus )
292 {
293 }
294 295 /// ditto296 publicoverrideExitExceptiononExitException ( IApplicationapp, istring[] args,
297 ExitExceptionexception )
298 {
299 returnexception;
300 }
301 }