1 module eventcore.drivers.posix.signals; 2 @safe: 3 4 import eventcore.driver; 5 import eventcore.drivers.posix.driver; 6 import eventcore.internal.utils : nogc_assert; 7 8 import std.algorithm.comparison : among; 9 10 11 final class SignalFDEventDriverSignals(Loop : PosixEventLoop) : EventDriverSignals { 12 @safe: /*@nogc:*/ nothrow: 13 import core.stdc.errno : errno, EAGAIN, EINPROGRESS; 14 import core.sys.posix.signal; 15 import core.sys.posix.unistd : close, read, write; 16 import core.sys.linux.sys.signalfd; 17 18 private Loop m_loop; 19 20 this(Loop loop) @nogc { m_loop = loop; } 21 22 override SignalListenID listen(int sig, SignalCallback on_signal) 23 { 24 return listenInternal(sig, on_signal, false); 25 } 26 27 package SignalListenID listenInternal(int sig, SignalCallback on_signal, bool is_internal = true) 28 { 29 auto sigfd = () @trusted { 30 sigset_t sset; 31 sigemptyset(&sset); 32 sigaddset(&sset, sig); 33 34 if (sigprocmask(SIG_BLOCK, &sset, null) != 0) 35 return -1; 36 37 return signalfd(-1, &sset, SFD_NONBLOCK | SFD_CLOEXEC); 38 } (); 39 40 41 auto fd = m_loop.initFD!SignalListenID(sigfd, is_internal ? FDFlags.internal : FDFlags.none, SignalSlot(on_signal)); 42 m_loop.registerFD(cast(FD)fd, EventMask.read); 43 m_loop.setNotifyCallback!(EventType.read)(cast(FD)fd, &onSignal); 44 45 onSignal(cast(FD)fd); 46 47 return fd; 48 } 49 50 override bool isValid(SignalListenID handle) 51 const { 52 if (handle.value >= m_loop.m_fds.length) return false; 53 return m_loop.m_fds[handle.value].common.validationCounter == handle.validationCounter; 54 } 55 56 override void addRef(SignalListenID descriptor) 57 { 58 if (!isValid(descriptor)) return; 59 60 assert(m_loop.m_fds[descriptor].common.refCount > 0, "Adding reference to unreferenced event FD."); 61 m_loop.m_fds[descriptor].common.refCount++; 62 } 63 64 override bool releaseRef(SignalListenID descriptor) 65 { 66 if (!isValid(descriptor)) return true; 67 68 FD fd = cast(FD)descriptor; 69 nogc_assert(m_loop.m_fds[fd].common.refCount > 0, "Releasing reference to unreferenced event FD."); 70 if (--m_loop.m_fds[fd].common.refCount == 1) { // NOTE: 1 because setNotifyCallback adds a second reference 71 m_loop.setNotifyCallback!(EventType.read)(fd, null); 72 m_loop.unregisterFD(fd, EventMask.read); 73 m_loop.clearFD!SignalSlot(fd); 74 close(cast(int)fd); 75 return false; 76 } 77 return true; 78 } 79 80 private void onSignal(FD fd) 81 { 82 SignalListenID lid = cast(SignalListenID)fd; 83 signalfd_siginfo nfo; 84 do { 85 auto ret = () @trusted { return read(cast(int)fd, &nfo, nfo.sizeof); } (); 86 if (ret == -1 && errno.among!(EAGAIN, EINPROGRESS)) 87 break; 88 auto cb = m_loop.m_fds[fd].signal.callback; 89 if (ret != nfo.sizeof) { 90 cb(lid, SignalStatus.error, -1); 91 return; 92 } 93 addRef(lid); 94 cb(lid, SignalStatus.ok, nfo.ssi_signo); 95 releaseRef(lid); 96 } while (m_loop.m_fds[fd].common.refCount > 0); 97 } 98 } 99 100 final class DummyEventDriverSignals(Loop : PosixEventLoop) : EventDriverSignals { 101 @safe: /*@nogc:*/ nothrow: 102 103 private Loop m_loop; 104 105 this(Loop loop) { m_loop = loop; } 106 107 override SignalListenID listen(int sig, SignalCallback on_signal) 108 { 109 return listenInternal(sig, on_signal, false); 110 } 111 112 package SignalListenID listenInternal(int sig, SignalCallback on_signal, bool is_internal = true) 113 { 114 assert(false); 115 } 116 117 override bool isValid(SignalListenID handle) 118 const { 119 return false; 120 } 121 122 override void addRef(SignalListenID descriptor) 123 { 124 assert(false); 125 } 126 127 override bool releaseRef(SignalListenID descriptor) 128 { 129 assert(false); 130 } 131 } 132 133 package struct SignalSlot { 134 alias Handle = SignalListenID; 135 SignalCallback callback; 136 }