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 version(Posix): 16 17 import std.exception; 18 19 public import core.sys.posix.signal; 20 21 alias void delegate() nothrow @system SignalHandler; 22 23 // https://github.com/D-Programming-Language/druntime/pull/759 24 version(OSX) private 25 { 26 enum SIG_BLOCK = 1; 27 enum SIG_UNBLOCK = 2; 28 enum SIG_SETMASK = 3; 29 } 30 31 // https://github.com/D-Programming-Language/druntime/pull/1140 32 version(FreeBSD) private 33 { 34 enum SIG_BLOCK = 1; 35 enum SIG_UNBLOCK = 2; 36 enum SIG_SETMASK = 3; 37 } 38 39 void addSignalHandler(int signum, SignalHandler fn) 40 { 41 if (handlers[signum].length == 0) 42 { 43 alias sigfn_t = typeof(signal(0, null)); 44 auto old = signal(signum, cast(sigfn_t)&sighandle); 45 assert(old == SIG_DFL, "A signal handler was already set"); 46 } 47 handlers[signum] ~= fn; 48 } 49 50 void removeSignalHandler(int signum, SignalHandler fn) 51 { 52 foreach (i, lfn; handlers[signum]) 53 if (lfn is fn) 54 { 55 handlers[signum] = handlers[signum][0..i] ~ handlers[signum][i+1..$]; 56 if (handlers[signum].length == 0) 57 signal(signum, SIG_DFL); 58 return; 59 } 60 assert(0); 61 } 62 63 // *************************************************************************** 64 65 /// If the signal signum is raised during execution of code, 66 /// ignore it. Returns true if the signal was raised. 67 bool collectSignal(int signum, void delegate() code) 68 { 69 sigset_t mask; 70 sigemptyset(&mask); 71 sigaddset(&mask, signum); 72 errnoEnforce(pthread_sigmask(SIG_BLOCK, &mask, null) != -1); 73 74 bool result; 75 { 76 scope(exit) 77 errnoEnforce(pthread_sigmask(SIG_UNBLOCK, &mask, null) != -1); 78 79 scope(exit) 80 { 81 static if (is(typeof(&sigpending))) 82 { 83 errnoEnforce(sigpending(&mask) == 0); 84 auto m = sigismember(&mask, signum); 85 errnoEnforce(m >= 0); 86 result = m != 0; 87 if (result) 88 { 89 int s; 90 errnoEnforce(sigwait(&mask, &s) == 0); 91 assert(s == signum); 92 } 93 } 94 else 95 { 96 timespec zerotime; 97 result = sigtimedwait(&mask, null, &zerotime) == 0; 98 } 99 } 100 101 code(); 102 } 103 104 return result; 105 } 106 107 private: 108 109 enum SIGMAX = 100; 110 shared SignalHandler[][SIGMAX] handlers; 111 112 extern(C) void sighandle(int signum) nothrow @system 113 { 114 if (signum >= 0 && signum < handlers.length) 115 foreach (fn; handlers[signum]) 116 fn(); 117 }