1 /// Manage signals as reactor callbacks 2 module mecca.reactor.platform.kqueue_signals; 3 4 // Licensed under the Boost license. Full copyright information in the AUTHORS file 5 6 version (Kqueue): 7 package(mecca.reactor.platform): 8 9 alias ReactorSignal = KqueueReactorSignal; 10 11 private struct KqueueReactorSignal { 12 import core.sys.posix.signal : sigaction_t, sigaction, SIG_IGN; 13 14 import std.traits : Parameters; 15 16 import mecca.lib.exception : ASSERT, errnoEnforceNGC; 17 import mecca.platform.os : OSSignal; 18 import mecca.reactor.platform.kqueue : Kqueue; 19 import mecca.reactor.subsystems.poller : poller, Poller; 20 21 alias SignalHandler = Kqueue.SignalHandler; 22 23 private Poller.FdContext*[OSSignal.max + 1] handlers; 24 private sigaction_t[OSSignal.max + 1] previousActions; 25 26 /** 27 * Must be called prior to registering any signals. 28 * 29 * Must be called after the reactor is open, and also after ReactorFS.openReactor has already been called. 30 */ 31 void _open() @trusted @nogc { 32 ASSERT!"ReactorSignal.open called without first calling ReactorFD.openReactor"(poller.isOpen); 33 } 34 35 /// Call this when shutting down the reactor. Mostly necessary for unit tests 36 void _close() @safe @nogc { 37 // noop 38 } 39 40 /** 41 * register a signal handler 42 * 43 * Register a handler for a specific signal. The signal must not already be handled, either through ReactorSignal or 44 * otherwise. 45 * 46 * Params: 47 * signum = the signal to be handled 48 * handler = a delegate to be called when the signal arrives 49 */ 50 void registerHandler(OSSignal signum, SignalHandler handler) @trusted @nogc { 51 ASSERT!"registerHandler called with invalid signal %s"(signum <= OSSignal.max || signum<=0, signum); 52 ASSERT!"signal %s registered twice"(handlers[signum] is null, signum); 53 54 sigaction_t previousAction; 55 const sigaction_t action = { sa_handler: &dummySignalHandler }; 56 errnoEnforceNGC(sigaction(signum, &action, &previousAction) == 0, "Failed to register signal action"); 57 58 handlers[signum] = poller.registerSignalHandler(signum, handler); 59 previousActions[signum] = previousAction; 60 } 61 62 void registerHandler(string sig, T)(T handler) @trusted { 63 registerHandler(__traits(getMember, OSSignal, sig), (_){handler();}); 64 } 65 66 void unregisterHandler(OSSignal signum) @trusted @nogc { 67 ASSERT!"registerHandler called with invalid signal %s"(signum <= OSSignal.max || signum<=0, signum); 68 ASSERT!"signal %s not registered"(handlers[signum] !is null, signum); 69 70 errnoEnforceNGC(sigaction(signum, &previousActions[signum], null) == 0, "Failed to restore signal action"); 71 poller.unregisterSignalHandler(handlers[signum]); 72 73 handlers[signum] = null; 74 previousActions[signum] = sigaction_t.init; 75 } 76 77 void unregisterHandler(string sig)() @trusted @nogc { 78 unregisterHandler(__traits(getMember, OSSignal, sig)); 79 } 80 81 // Dummy signal handler is necessary, otherwise kqueue won't receive the 82 // signal since it has lower precedence 83 extern (C) private static void dummySignalHandler(int) {} 84 }