1 /** 2 * POSIX signal handlers. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.sys.signals; 15 16 import std.exception; 17 18 public import core.sys.posix.signal; 19 20 alias void delegate() nothrow @system SignalHandler; 21 22 // https://github.com/D-Programming-Language/druntime/pull/759 23 version(OSX) private 24 { 25 enum SIG_BLOCK = 1; 26 enum SIG_UNBLOCK = 2; 27 enum SIG_SETMASK = 3; 28 } 29 30 void addSignalHandler(int signum, SignalHandler fn) 31 { 32 if (handlers[signum].length == 0) 33 { 34 alias sigfn_t = typeof(signal(0, null)); 35 auto old = signal(signum, cast(sigfn_t)&sighandle); 36 assert(old == SIG_DFL, "A signal handler was already set"); 37 } 38 handlers[signum] ~= fn; 39 } 40 41 void removeSignalHandler(int signum, SignalHandler fn) 42 { 43 foreach (i, lfn; handlers[signum]) 44 if (lfn is fn) 45 { 46 handlers[signum] = handlers[signum][0..i] ~ handlers[signum][i+1..$]; 47 if (handlers[signum].length == 0) 48 signal(signum, SIG_DFL); 49 return; 50 } 51 assert(0); 52 } 53 54 // *************************************************************************** 55 56 /// If the signal signum is raised during execution of code, 57 /// ignore it. Returns true if the signal was raised. 58 bool collectSignal(int signum, void delegate() code) 59 { 60 sigset_t mask; 61 sigemptyset(&mask); 62 sigaddset(&mask, signum); 63 errnoEnforce(pthread_sigmask(SIG_BLOCK, &mask, null) != -1); 64 65 bool result; 66 { 67 scope(exit) 68 errnoEnforce(pthread_sigmask(SIG_UNBLOCK, &mask, null) != -1); 69 70 scope(exit) 71 { 72 static if (is(typeof(&sigpending))) 73 { 74 errnoEnforce(sigpending(&mask) == 0); 75 auto m = sigismember(&mask, signum); 76 errnoEnforce(m >= 0); 77 result = m != 0; 78 if (result) 79 { 80 int s; 81 errnoEnforce(sigwait(&mask, &s) == 0); 82 assert(s == signum); 83 } 84 } 85 else 86 { 87 timespec zerotime; 88 result = sigtimedwait(&mask, null, &zerotime) == 0; 89 } 90 } 91 92 code(); 93 } 94 95 return result; 96 } 97 98 private: 99 100 enum SIGMAX = 100; 101 shared SignalHandler[][SIGMAX] handlers; 102 103 extern(C) void sighandle(int signum) nothrow @system 104 { 105 if (signum >= 0 && signum < handlers.length) 106 foreach (fn; handlers[signum]) 107 fn(); 108 }