1 /******************************************************************************* 2 3 Linux signal file descriptor event. 4 5 signalfd man page follows: 6 7 signalfd() creates a file descriptor that can be used to accept signals 8 targeted at the caller. This provides an alternative to the use of a signal 9 handler or sigwaitinfo(2), and has the advantage that the file descriptor may 10 be monitored by select(2), poll(2), and epoll(7). 11 12 The mask argument specifies the set of signals that the caller wishes to 13 accept via the file descriptor. This argument is a signal set whose contents 14 can be initialized using the macros described in sigsetops(3). Normally, the 15 set of signals to be received via the file descriptor should be blocked using 16 sigprocmask(2), to prevent the signals being handled according to their 17 default dispositions. It is not possible to receive SIGKILL or SIGSTOP 18 signals via a signalfd file descriptor; these signals are silently ignored if 19 specified in mask. 20 21 If the fd argument is -1, then the call creates a new file descriptor and 22 associates the signal set specified in mask with that descriptor. If fd is 23 not -1, then it must specify a valid existing signalfd file descriptor, and 24 mask is used to replace the signal set associated with that descriptor. 25 26 Starting with Linux 2.6.27, the following values may be bitwise ORed in flags 27 to change the behaviour of signalfd(): 28 29 SFD_NONBLOCK Set the O_NONBLOCK file status flag on the new open file 30 description. Using this flag saves extra calls to fcntl(2) to 31 achieve the same result. 32 33 SFD_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the new file 34 descriptor. See the description of the O_CLOEXEC flag in 35 open(2) for reasons why this may be useful. 36 37 In Linux up to version 2.6.26, the flags argument is unused, and must be 38 specified as zero. 39 40 signalfd() returns a file descriptor that supports the following operations: 41 42 read(2) 43 If one or more of the signals specified in mask is pending for the 44 process, then the buffer supplied to read(2) is used to return one or 45 more signalfd_siginfo structures (see below) that describe the signals. 46 The read(2) returns information for as many signals as are pending and 47 will fit in the supplied buffer. The buffer must be at least 48 sizeof(struct signalfd_siginfo) bytes. The return value of the read(2) 49 is the total number of bytes read. 50 51 As a consequence of the read(2), the signals are consumed, so that they 52 are no longer pending for the process (i.e., will not be caught by 53 signal handlers, and cannot be accepted using sigwaitinfo(2)). 54 55 If none of the signals in mask is pending for the process, then the 56 read(2) either blocks until one of the signals in mask is generated for 57 the process, or fails with the error EAGAIN if the file descriptor has 58 been made nonblocking. 59 60 poll(2), select(2) (and similar) 61 The file descriptor is readable (the select(2) readfds argument; the 62 poll(2) POLLIN flag) if one or more of the signals in mask is pending 63 for the process. 64 65 The signalfd file descriptor also supports the other file-descriptor 66 multiplexing APIs: pselect(2), ppoll(2), and epoll(7). 67 68 close(2) 69 When the file descriptor is no longer required it should be closed. 70 When all file descriptors associated with the same signalfd object have 71 been closed, the resources for object are freed by the kernel. 72 73 Copyright: 74 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 75 All rights reserved. 76 77 License: 78 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 79 Alternatively, this file may be distributed under the terms of the Tango 80 3-Clause BSD License (see LICENSE_BSD.txt for details). 81 82 *******************************************************************************/ 83 84 module ocean.sys.SignalFD; 85 86 87 import ocean.core.Exception; 88 import ocean.sys.ErrnoException; 89 90 import ocean.sys.SignalMask; 91 92 import ocean.meta.codegen.Identifier; 93 94 import ocean.io.model.IConduit; 95 96 import core.sys.posix.signal; 97 98 import core.sys.posix.unistd : read, close; 99 100 import core.stdc.errno : EAGAIN, EWOULDBLOCK, errno; 101 102 import ocean.core.Array : contains; 103 104 import ocean.transition; 105 106 debug import ocean.io.Stdout; 107 108 /******************************************************************************* 109 110 Signal fd class 111 112 *******************************************************************************/ 113 114 public class SignalFD : ISelectable 115 { 116 import core.sys.linux.sys.signalfd; 117 import ocean.sys.CloseOnExec; 118 119 /*************************************************************************** 120 121 errno exception type for signal events. 122 123 ***************************************************************************/ 124 125 public static class SignalErrnoException : ErrnoException { } 126 127 128 /*************************************************************************** 129 130 Exception type for signal events. 131 132 ***************************************************************************/ 133 134 private static class SignalException : Exception 135 { 136 mixin ReusableExceptionImplementation; 137 } 138 139 140 /*************************************************************************** 141 142 More convenient alias for signalfd_siginfo. 143 144 ***************************************************************************/ 145 146 public alias signalfd_siginfo SignalInfo; 147 148 149 /*************************************************************************** 150 151 Re-usable exception instances. 152 153 ***************************************************************************/ 154 155 private SignalErrnoException errno_exception; 156 157 private SignalException exception; 158 159 160 /*************************************************************************** 161 162 Integer file descriptor provided by the operating system and used to 163 manage the signal event. The default value (-1), when passed to the 164 signalfd() function (see register()) causes a new fd to be created. 165 166 ***************************************************************************/ 167 168 private int fd = -1; 169 170 171 /*************************************************************************** 172 173 List of signals being handled by the fd. (Declared as package so that 174 the module slowtest can access it.) 175 176 ***************************************************************************/ 177 178 private int[] signals; 179 180 181 /*************************************************************************** 182 183 Constructor. Creates a signal event file descriptor which will be 184 written to when one of the specified signals fires. The normal signal 185 handling for the specified signals is optionally masked. 186 187 The list of signals handled may be extended after construction by 188 calling the register() method. 189 190 Params: 191 signals = list of signals to register 192 mask = if true, default signal handling of the specified signals 193 will be masked 194 195 Throws: 196 SignalErrnoException if the creation of the signalfd fails 197 198 ***************************************************************************/ 199 200 public this ( int[] signals, bool mask = true ) 201 { 202 foreach ( signal; signals ) 203 { 204 this.register(signal, mask); 205 } 206 207 this.exception = new SignalException; 208 this.errno_exception = new SignalErrnoException; 209 } 210 211 212 /*************************************************************************** 213 214 Destructor. Destroys the signal file descriptor and unmasks all masked 215 signals. 216 217 ***************************************************************************/ 218 219 ~this ( ) 220 { 221 this.unmaskHandledSignals(); 222 .close(this.fd); 223 } 224 225 226 /*************************************************************************** 227 228 Adds the specified signal to the set of signals handled by this fd. The 229 normal signal handling for the specified signal is optionally masked. 230 231 Params: 232 signal = signal to register 233 mask = if true, default signal handling of the specified signal will 234 be masked 235 236 Returns: 237 this instance for chaining 238 239 Throws: 240 SignalErrnoException if the creation of the signalfd fails 241 242 ***************************************************************************/ 243 244 public typeof(this) register ( int signal, bool mask = true ) 245 { 246 if ( !this.isRegistered(signal) ) 247 { 248 this.signals ~= signal; 249 } 250 251 SignalSet sigset; 252 sigset.clear; 253 sigset.add(this.signals); 254 auto c_sigset = cast(sigset_t) sigset; 255 256 this.fd = signalfd( 257 this.fd, &c_sigset, setCloExec(SFD_NONBLOCK, SFD_CLOEXEC) 258 ); 259 if ( this.fd == -1 ) 260 { 261 scope ( exit ) .errno = 0; 262 auto errnum = .errno; 263 throw this.errno_exception.set(errnum, identifier!(signalfd)); 264 } 265 266 if ( mask ) 267 { 268 this.maskHandledSignals(); 269 } 270 271 return this; 272 } 273 274 275 /*************************************************************************** 276 277 Unmasks all signals registered with this fd, meaning that the default 278 signal (interrupt) handler will deal with them from now. 279 280 Warning: this will simply unmask all specified signals. This could be 281 problematic if some completely different module has separately requested 282 that these signals be masked. If this situation ever arises we'll need 283 to come up with a clever solution involving some kind of reference 284 counting or something. 285 286 ***************************************************************************/ 287 288 public void unmaskHandledSignals ( ) 289 { 290 auto sigset = SignalSet.getCurrent(); 291 sigset.remove(this.signals); 292 sigset.mask(); 293 } 294 295 296 /*************************************************************************** 297 298 Masks all signals registered with this fd, meaning that the default 299 signal (interrupt) handler will not deal with them from now. 300 301 ***************************************************************************/ 302 303 public void maskHandledSignals ( ) 304 { 305 SignalSet sigset; 306 sigset.clear(); 307 sigset.add(this.signals); 308 sigset.block(); 309 } 310 311 312 /*************************************************************************** 313 314 Required by ISelectable interface. 315 316 Returns: 317 file descriptor used to manage signal event 318 319 ***************************************************************************/ 320 321 public Handle fileHandle ( ) 322 { 323 return cast(Handle)this.fd; 324 } 325 326 327 /*************************************************************************** 328 329 Checks whether the specified signal is registered to be handled by this 330 fd. 331 332 Params: 333 signal = code of signal to check 334 335 Returns: 336 true if the specified signal is handled by this fd 337 338 ***************************************************************************/ 339 340 public bool isRegistered ( int signal ) 341 { 342 return !!this.signals.contains(signal); 343 } 344 345 346 /*************************************************************************** 347 348 Getter for the list of registered signals. Changing the contents of the 349 returned array may lead to undefined behaviour. 350 351 Returns: 352 list of signals which are registered to be handled by this fd 353 354 ***************************************************************************/ 355 356 public int[] registered_signals ( ) 357 { 358 return this.signals; 359 } 360 361 362 /*************************************************************************** 363 364 Should be called when the signal event has fired. Fills in the provided 365 array with structs containing information about which signals fired. 366 367 Params: 368 siginfos = output array of structs containing information about 369 signals which fired 370 371 Throws: 372 if an error occurs while reading from the signalfd 373 374 ***************************************************************************/ 375 376 public void handle ( ref SignalInfo[] siginfos ) 377 { 378 siginfos.length = 0; 379 enableStomping(siginfos); 380 381 SignalInfo siginfo; 382 383 ssize_t bytes; 384 do 385 { 386 /* 387 * Reading from a signal FD has a special meaning and satisfies 388 * certain assumptions: A read() call for siginfo.sizeof bytes 389 * attempts to consume one of the pending signals. If it succeeds 390 * then it is guaranteed to have read all bytes. If there are no 391 * signals pending -- usually because we consumed all pending 392 * signals by having called read(siginfo.sizeof) as often as there 393 * were signals pending, but also if this method was called without 394 * the signal FD having fired -- then read() fails with 395 * EAGAIN/EWOULDBLOCK. 396 */ 397 bytes = .read(this.fd, &siginfo, siginfo.sizeof); 398 if ( bytes == siginfo.sizeof ) 399 { 400 siginfos ~= siginfo; 401 } 402 else if ( bytes < 0 ) 403 { 404 // Check for errnum == EAGAIN/EWOUDLBLOCK which indicates the 405 // end of the list of signals (that is, we either read the whole 406 // list or no signal was actually pending in the first place). 407 408 scope ( exit ) .errno = 0; 409 auto errnum = .errno; 410 411 switch ( errnum ) 412 { 413 case EAGAIN: 414 break; // The loop will exit because bytes < 0. 415 416 static if ( EAGAIN != EWOULDBLOCK ) 417 { 418 case EWOUDLBLOCK: 419 break; // The loop will exit because bytes < 0. 420 } 421 422 default: 423 throw this.errno_exception.set(errnum, identifier!(.read)); 424 } 425 } 426 else 427 { 428 // This should not happen: read(siginfo.sizeof) from a signal FD 429 // returns either siginfo.sizeof for success or -1 for failure. 430 431 throw this.exception.set("read invalid bytes from signalfd"); 432 } 433 } 434 while ( bytes > 0 ); 435 } 436 }