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 import ocean.core.Verify; 93 import ocean.meta.types.Qualifiers; 94 import ocean.util.app.Application; 95 import ocean.util.app.model.ExtensibleClassMixin; 96 import ocean.util.app.model.IApplicationExtension; 97 import ocean.util.app.ext.model.ISignalExtExtension; 98 99 public class SignalExt : IApplicationExtension 100 { 101 import core.sys.posix.signal; 102 103 import ocean.application.components.Signals; 104 import ocean.io.select.protocol.SelectReader; 105 import ocean.io.device.IODevice; 106 import ocean.io.device.Device; 107 import ocean.io.device.Conduit: ISelectable; 108 import ocean.io.select.client.model.ISelectClient; 109 110 /*************************************************************************** 111 112 Adds a list of extensions (this.extensions) and methods to handle them. 113 See ExtensibleClassMixin documentation for details. 114 115 ***************************************************************************/ 116 117 mixin ExtensibleClassMixin!(ISignalExtExtension); 118 119 /*************************************************************************** 120 121 Signal handlers wrapper. 122 123 ***************************************************************************/ 124 125 private Signals signals; 126 127 /*************************************************************************** 128 129 Constructor. Creates the internal signal event, handling the specified 130 signals. The event (accessible via the event() method) must be 131 registered with epoll. 132 133 The list of signals handled may be extended after construction by 134 calling the register() method. 135 136 Note that the signals will be handled with a delay of up to single 137 epoll cycle. This is because the signal extension is synced with the 138 EpollSelectDispatcher. This makes it unsuitable to handle critical 139 signals (like `SIGABRT` or `SIGSEGV`) where the application shouldn't 140 be allowed to proceed in the general case; for these cases setup an 141 asynchronous signal handler using `sigaction` instead. 142 143 Params: 144 signals = list of signals to handle 145 ignore_signals = list of signals to ignore 146 147 Throws: 148 SignalErrnoException if setting up the signal handling fails 149 150 ***************************************************************************/ 151 152 public this ( int[] signals, int[] ignore_signals = null ) 153 { 154 this.signals = new Signals(&this.handleSignals); 155 this.signals.handle(signals); 156 this.signals.ignore(ignore_signals); 157 } 158 159 /*************************************************************************** 160 161 Ignores the signals. 162 163 Params: 164 signals = list of signals to ignore 165 166 Throws: 167 SignalErrnoException if setting up the signal fails 168 169 ***************************************************************************/ 170 171 public void ignore ( in int[] signals ) 172 { 173 this.signals.ignore(signals); 174 } 175 176 /*************************************************************************** 177 178 Adds the specified signal to the set of signals handled by this 179 extension. 180 181 Params: 182 signal = signal to handle 183 184 Returns: 185 this instance for chaining 186 187 Throws: 188 SignalErrnoException if the updating the signal handling fails 189 190 ***************************************************************************/ 191 192 public typeof(this) register ( int signal ) 193 { 194 this.signals.handle(cast(int[])(&signal)[0..1]); 195 196 return this; 197 } 198 199 200 /*************************************************************************** 201 202 ISelectClient getter, for registering with epoll. 203 204 Returns: 205 ISelectClient interface to register with epoll 206 207 ***************************************************************************/ 208 209 public ISelectClient selectClient ( ) 210 { 211 return this.signals.selectClient(); 212 } 213 214 215 /*************************************************************************** 216 217 Extension order. This extension uses -2_000 because it should be called 218 before the LogExt and StatsExt. 219 220 Returns: 221 the extension order 222 223 ***************************************************************************/ 224 225 public override int order ( ) 226 { 227 return -2_000; 228 } 229 230 231 /*************************************************************************** 232 233 Signal handler delegate, called from epoll when a signal has fired. In 234 turn notifies all registered extensions about the signal. 235 236 Params: 237 signals = info about signals which have fired 238 239 ***************************************************************************/ 240 241 private void handleSignals ( int[] signals ) 242 { 243 foreach ( ext; this.extensions ) 244 { 245 foreach (signal; signals) 246 { 247 ext.onSignal(signal); 248 } 249 } 250 } 251 252 /*************************************************************************** 253 254 atExit IApplicationExtension method. 255 256 Should restore the original signal handlers. 257 258 ***************************************************************************/ 259 260 public override void atExit ( IApplication app, string[] args, int status, 261 ExitException exception ) 262 { 263 this.signals.clear(); 264 } 265 266 /*************************************************************************** 267 268 Unused IApplicationExtension methods. 269 270 We just need to provide an "empty" implementation to satisfy the 271 interface. 272 273 ***************************************************************************/ 274 275 public override void preRun ( IApplication app, string[] args ) 276 { 277 } 278 279 /// ditto 280 public override void postRun ( IApplication app, string[] args, int status ) 281 { 282 } 283 284 /// ditto 285 public override ExitException onExitException ( IApplication app, string[] args, 286 ExitException exception ) 287 { 288 return exception; 289 } 290 }