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 import ocean.core.Array : contains; 87 import ocean.core.Exception; 88 import ocean.meta.codegen.Identifier; 89 import ocean.meta.types.Qualifiers; 90 import ocean.sys.ErrnoException; 91 import ocean.sys.SignalMask; 92 import ocean.io.model.IConduit; 93 debug import ocean.io.Stdout; 94 95 import core.stdc.errno : EAGAIN, EWOULDBLOCK, errno; 96 import core.sys.posix.signal; 97 import core.sys.posix.unistd : read, close; 98 99 100 /// Ditto 101 public class SignalFD : ISelectable 102 { 103 import core.sys.linux.sys.signalfd; 104 import ocean.sys.CloseOnExec; 105 106 /*************************************************************************** 107 108 errno exception type for signal events. 109 110 ***************************************************************************/ 111 112 public static class SignalErrnoException : ErrnoException { } 113 114 115 /*************************************************************************** 116 117 Exception type for signal events. 118 119 ***************************************************************************/ 120 121 private static class SignalException : Exception 122 { 123 mixin ReusableExceptionImplementation; 124 } 125 126 127 /*************************************************************************** 128 129 More convenient alias for signalfd_siginfo. 130 131 ***************************************************************************/ 132 133 public alias signalfd_siginfo SignalInfo; 134 135 136 /*************************************************************************** 137 138 Re-usable exception instances. 139 140 ***************************************************************************/ 141 142 private SignalErrnoException errno_exception; 143 144 private SignalException exception; 145 146 147 /*************************************************************************** 148 149 Integer file descriptor provided by the operating system and used to 150 manage the signal event. The default value (-1), when passed to the 151 signalfd() function (see register()) causes a new fd to be created. 152 153 ***************************************************************************/ 154 155 private int fd = -1; 156 157 158 /*************************************************************************** 159 160 List of signals being handled by the fd. (Declared as package so that 161 the module slowtest can access it.) 162 163 ***************************************************************************/ 164 165 private int[] signals; 166 167 168 /*************************************************************************** 169 170 Constructor. Creates a signal event file descriptor which will be 171 written to when one of the specified signals fires. The normal signal 172 handling for the specified signals is optionally masked. 173 174 The list of signals handled may be extended after construction by 175 calling the register() method. 176 177 Params: 178 signals = list of signals to register 179 mask = if true, default signal handling of the specified signals 180 will be masked 181 182 Throws: 183 SignalErrnoException if the creation of the signalfd fails 184 185 ***************************************************************************/ 186 187 public this ( int[] signals, bool mask = true ) 188 { 189 foreach ( signal; signals ) 190 { 191 this.register(signal, mask); 192 } 193 194 this.exception = new SignalException; 195 this.errno_exception = new SignalErrnoException; 196 } 197 198 199 /*************************************************************************** 200 201 Destructor. Destroys the signal file descriptor and unmasks all masked 202 signals. 203 204 ***************************************************************************/ 205 206 ~this ( ) 207 { 208 this.unmaskHandledSignals(); 209 .close(this.fd); 210 } 211 212 213 /*************************************************************************** 214 215 Adds the specified signal to the set of signals handled by this fd. The 216 normal signal handling for the specified signal is optionally masked. 217 218 Params: 219 signal = signal to register 220 mask = if true, default signal handling of the specified signal will 221 be masked 222 223 Returns: 224 this instance for chaining 225 226 Throws: 227 SignalErrnoException if the creation of the signalfd fails 228 229 ***************************************************************************/ 230 231 public typeof(this) register ( int signal, bool mask = true ) 232 { 233 if ( !this.isRegistered(signal) ) 234 { 235 this.signals ~= signal; 236 } 237 238 SignalSet sigset; 239 sigset.clear; 240 sigset.add(this.signals); 241 auto c_sigset = cast(sigset_t) sigset; 242 243 this.fd = signalfd( 244 this.fd, &c_sigset, setCloExec(SFD_NONBLOCK, SFD_CLOEXEC) 245 ); 246 if ( this.fd == -1 ) 247 { 248 scope ( exit ) .errno = 0; 249 auto errnum = .errno; 250 throw this.errno_exception.set(errnum, identifier!(signalfd)); 251 } 252 253 if ( mask ) 254 { 255 this.maskHandledSignals(); 256 } 257 258 return this; 259 } 260 261 262 /*************************************************************************** 263 264 Unmasks all signals registered with this fd, meaning that the default 265 signal (interrupt) handler will deal with them from now. 266 267 Warning: this will simply unmask all specified signals. This could be 268 problematic if some completely different module has separately requested 269 that these signals be masked. If this situation ever arises we'll need 270 to come up with a clever solution involving some kind of reference 271 counting or something. 272 273 ***************************************************************************/ 274 275 public void unmaskHandledSignals ( ) 276 { 277 auto sigset = SignalSet.getCurrent(); 278 sigset.remove(this.signals); 279 sigset.mask(); 280 } 281 282 283 /*************************************************************************** 284 285 Masks all signals registered with this fd, meaning that the default 286 signal (interrupt) handler will not deal with them from now. 287 288 ***************************************************************************/ 289 290 public void maskHandledSignals ( ) 291 { 292 SignalSet sigset; 293 sigset.clear(); 294 sigset.add(this.signals); 295 sigset.block(); 296 } 297 298 299 /*************************************************************************** 300 301 Required by ISelectable interface. 302 303 Returns: 304 file descriptor used to manage signal event 305 306 ***************************************************************************/ 307 308 public Handle fileHandle ( ) 309 { 310 return cast(Handle)this.fd; 311 } 312 313 314 /*************************************************************************** 315 316 Checks whether the specified signal is registered to be handled by this 317 fd. 318 319 Params: 320 signal = code of signal to check 321 322 Returns: 323 true if the specified signal is handled by this fd 324 325 ***************************************************************************/ 326 327 public bool isRegistered ( int signal ) 328 { 329 return !!this.signals.contains(signal); 330 } 331 332 333 /*************************************************************************** 334 335 Getter for the list of registered signals. Changing the contents of the 336 returned array may lead to undefined behaviour. 337 338 Returns: 339 list of signals which are registered to be handled by this fd 340 341 ***************************************************************************/ 342 343 public int[] registered_signals ( ) 344 { 345 return this.signals; 346 } 347 348 349 /*************************************************************************** 350 351 Should be called when the signal event has fired. Fills in the provided 352 array with structs containing information about which signals fired. 353 354 Params: 355 siginfos = output array of structs containing information about 356 signals which fired 357 358 Throws: 359 if an error occurs while reading from the signalfd 360 361 ***************************************************************************/ 362 363 public void handle ( ref SignalInfo[] siginfos ) 364 { 365 siginfos.length = 0; 366 assumeSafeAppend(siginfos); 367 368 SignalInfo siginfo; 369 370 ssize_t bytes; 371 do 372 { 373 /* 374 * Reading from a signal FD has a special meaning and satisfies 375 * certain assumptions: A read() call for siginfo.sizeof bytes 376 * attempts to consume one of the pending signals. If it succeeds 377 * then it is guaranteed to have read all bytes. If there are no 378 * signals pending -- usually because we consumed all pending 379 * signals by having called read(siginfo.sizeof) as often as there 380 * were signals pending, but also if this method was called without 381 * the signal FD having fired -- then read() fails with 382 * EAGAIN/EWOULDBLOCK. 383 */ 384 bytes = .read(this.fd, &siginfo, siginfo.sizeof); 385 if ( bytes == siginfo.sizeof ) 386 { 387 siginfos ~= siginfo; 388 } 389 else if ( bytes < 0 ) 390 { 391 // Check for errnum == EAGAIN/EWOUDLBLOCK which indicates the 392 // end of the list of signals (that is, we either read the whole 393 // list or no signal was actually pending in the first place). 394 395 scope ( exit ) .errno = 0; 396 auto errnum = .errno; 397 398 switch ( errnum ) 399 { 400 case EAGAIN: 401 break; // The loop will exit because bytes < 0. 402 403 static if ( EAGAIN != EWOULDBLOCK ) 404 { 405 case EWOUDLBLOCK: 406 break; // The loop will exit because bytes < 0. 407 } 408 409 default: 410 throw this.errno_exception.set(errnum, identifier!(.read)); 411 } 412 } 413 else 414 { 415 // This should not happen: read(siginfo.sizeof) from a signal FD 416 // returns either siginfo.sizeof for success or -1 for failure. 417 418 throw this.exception.set("read invalid bytes from signalfd"); 419 } 420 } 421 while ( bytes > 0 ); 422 } 423 }