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 module ocean.util.app.ext.SignalExt; 91 92 93 94 import ocean.meta.types.Qualifiers; 95 import ocean.core.Verify; 96 97 import ocean.util.app.model.IApplicationExtension; 98 import ocean.util.app.model.ExtensibleClassMixin; 99 100 import ocean.util.app.Application; 101 102 import ocean.util.app.ext.model.ISignalExtExtension; 103 104 import ocean.sys.Pipe; 105 106 public class SignalExt : IApplicationExtension 107 { 108 import core.sys.posix.signal; 109 110 import ocean.application.components.Signals; 111 112 // For SignalErrnoException 113 import ocean.sys.SignalFD; 114 115 import ocean.io.select.protocol.SelectReader; 116 import ocean.io.device.IODevice; 117 import ocean.io.device.Device; 118 import ocean.io.device.Conduit: ISelectable; 119 import ocean.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 mixin ExtensibleClassMixin!(ISignalExtExtension); 129 130 /*************************************************************************** 131 132 Signal handlers wrapper. 133 134 ***************************************************************************/ 135 136 private Signals signals; 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 public this ( int[] signals, int[] ignore_signals = null ) 164 { 165 this.signals = new Signals(&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 public void ignore ( in int[] 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 public typeof(this) register ( int signal ) 204 { 205 this.signals.handle(cast(int[])(&signal)[0..1]); 206 207 return this; 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 public ISelectClient selectClient ( ) 221 { 222 return this.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 public override int order ( ) 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 private void handleSignals ( 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 public override void atExit ( IApplication app, istring[] args, int status, 272 ExitException exception ) 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 public override void preRun ( IApplication app, istring[] args ) 287 { 288 } 289 290 /// ditto 291 public override void postRun ( IApplication app, istring[] args, int status ) 292 { 293 } 294 295 /// ditto 296 public override ExitException onExitException ( IApplication app, istring[] args, 297 ExitException exception ) 298 { 299 return exception; 300 } 301 }