Implement listening for signals based on signalfd().
This commit is contained in:
parent
0cce1123fc
commit
bdaff3264f
|
@ -30,11 +30,13 @@ USDS | yes | yes | no | no
|
||||||
DNS | yes | yes | no | no
|
DNS | yes | yes | no | no
|
||||||
Timers | yes | yes | no | no
|
Timers | yes | yes | no | no
|
||||||
Events | yes | yes | no | no
|
Events | yes | yes | no | no
|
||||||
Signals | no | no | no | no
|
Signals | yes² | yes² | no | no
|
||||||
Files | yes | yes | no | no
|
Files | yes | yes | no | no
|
||||||
UI Integration | no | no | no | no
|
UI Integration | no | no | no | no
|
||||||
File watcher | no | no | no | no
|
File watcher | no | no | no | no
|
||||||
|
|
||||||
|
² Currently only supported on Linux
|
||||||
|
|
||||||
|
|
||||||
Open questions
|
Open questions
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -160,8 +160,18 @@ interface EventDriverEvents {
|
||||||
|
|
||||||
interface EventDriverSignals {
|
interface EventDriverSignals {
|
||||||
@safe: /*@nogc:*/ nothrow:
|
@safe: /*@nogc:*/ nothrow:
|
||||||
void wait(int sig, SignalCallback on_signal);
|
SignalListenID listen(int sig, SignalCallback on_signal);
|
||||||
void cancelWait(int sig);
|
|
||||||
|
/** Increments the reference count of the given resource.
|
||||||
|
*/
|
||||||
|
void addRef(SignalListenID descriptor);
|
||||||
|
|
||||||
|
/** Decrements the reference count of the given resource.
|
||||||
|
|
||||||
|
Once the reference count reaches zero, all associated resources will be
|
||||||
|
freed and the resource descriptor gets invalidated.
|
||||||
|
*/
|
||||||
|
void releaseRef(SignalListenID descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EventDriverTimers {
|
interface EventDriverTimers {
|
||||||
|
@ -212,7 +222,7 @@ alias DatagramIOCallback = void delegate(DatagramSocketFD, IOStatus, size_t, sco
|
||||||
alias DNSLookupCallback = void delegate(DNSLookupID, DNSStatus, scope Address[]);
|
alias DNSLookupCallback = void delegate(DNSLookupID, DNSStatus, scope Address[]);
|
||||||
alias FileIOCallback = void delegate(FileFD, IOStatus, size_t);
|
alias FileIOCallback = void delegate(FileFD, IOStatus, size_t);
|
||||||
alias EventCallback = void delegate(EventID);
|
alias EventCallback = void delegate(EventID);
|
||||||
alias SignalCallback = void delegate(int);
|
alias SignalCallback = void delegate(SignalListenID, SignalStatus, int);
|
||||||
alias TimerCallback = void delegate(TimerID);
|
alias TimerCallback = void delegate(TimerID);
|
||||||
alias FileChangesCallback = void delegate(WatcherID, in FileChange[] changes);
|
alias FileChangesCallback = void delegate(WatcherID, in FileChange[] changes);
|
||||||
@system alias DataInitializer = void function(void*);
|
@system alias DataInitializer = void function(void*);
|
||||||
|
@ -284,6 +294,11 @@ enum FileChangeKind {
|
||||||
modified
|
modified
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SignalStatus {
|
||||||
|
ok,
|
||||||
|
error
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Describes a single change in a watched directory.
|
/** Describes a single change in a watched directory.
|
||||||
*/
|
*/
|
||||||
|
@ -328,4 +343,5 @@ alias EventID = Handle!("Event", FD);
|
||||||
alias TimerID = Handle!("Timer", int);
|
alias TimerID = Handle!("Timer", int);
|
||||||
alias WatcherID = Handle!("Watcher", int);
|
alias WatcherID = Handle!("Watcher", int);
|
||||||
alias EventWaitID = Handle!("EventWait", int);
|
alias EventWaitID = Handle!("EventWait", int);
|
||||||
|
alias SignalListenID = Handle!("Signal", int);
|
||||||
alias DNSLookupID = Handle!("DNS", int);
|
alias DNSLookupID = Handle!("DNS", int);
|
||||||
|
|
|
@ -1055,18 +1055,71 @@ final class PosixEventDriverEvents(Loop : PosixEventLoop) : EventDriverEvents {
|
||||||
|
|
||||||
final class PosixEventDriverSignals(Loop : PosixEventLoop) : EventDriverSignals {
|
final class PosixEventDriverSignals(Loop : PosixEventLoop) : EventDriverSignals {
|
||||||
@safe: /*@nogc:*/ nothrow:
|
@safe: /*@nogc:*/ nothrow:
|
||||||
|
import core.sys.posix.signal;
|
||||||
|
import core.sys.linux.sys.signalfd;
|
||||||
|
|
||||||
private Loop m_loop;
|
private Loop m_loop;
|
||||||
|
|
||||||
this(Loop loop) { m_loop = loop; }
|
this(Loop loop) { m_loop = loop; }
|
||||||
|
|
||||||
final override void wait(int sig, SignalCallback on_signal)
|
override SignalListenID listen(int sig, SignalCallback on_signal)
|
||||||
{
|
{
|
||||||
assert(false, "TODO!");
|
auto fd = () @trusted {
|
||||||
|
sigset_t sset;
|
||||||
|
sigemptyset(&sset);
|
||||||
|
sigaddset(&sset, sig);
|
||||||
|
|
||||||
|
if (sigprocmask(SIG_BLOCK, &sset, null) != 0)
|
||||||
|
return SignalListenID.invalid;
|
||||||
|
|
||||||
|
return SignalListenID(signalfd(-1, &sset, SFD_NONBLOCK));
|
||||||
|
} ();
|
||||||
|
|
||||||
|
|
||||||
|
m_loop.initFD(cast(FD)fd);
|
||||||
|
m_loop.m_fds[fd].readCallback = () @trusted { return cast(IOCallback)on_signal; } (); // FIXME: avoid unsafe cast
|
||||||
|
m_loop.registerFD(cast(FD)fd, EventMask.read);
|
||||||
|
m_loop.setNotifyCallback!(EventType.read)(cast(FD)fd, &onSignal);
|
||||||
|
|
||||||
|
onSignal(cast(FD)fd);
|
||||||
|
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void cancelWait(int sig)
|
override void addRef(SignalListenID descriptor)
|
||||||
{
|
{
|
||||||
assert(false, "TODO!");
|
assert(m_loop.m_fds[descriptor].refCount > 0, "Adding reference to unreferenced event FD.");
|
||||||
|
m_loop.m_fds[descriptor].refCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void releaseRef(SignalListenID descriptor)
|
||||||
|
{
|
||||||
|
FD fd = cast(FD)descriptor;
|
||||||
|
assert(m_loop.m_fds[fd].refCount > 0, "Releasing reference to unreferenced event FD.");
|
||||||
|
if (--m_loop.m_fds[fd].refCount == 0) {
|
||||||
|
m_loop.unregisterFD(fd);
|
||||||
|
m_loop.clearFD(fd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSignal(FD fd)
|
||||||
|
{
|
||||||
|
SignalListenID lid = cast(SignalListenID)fd;
|
||||||
|
auto cb = () @trusted { return cast(SignalCallback)m_loop.m_fds[fd].readCallback; } ();
|
||||||
|
signalfd_siginfo nfo;
|
||||||
|
do {
|
||||||
|
auto ret = () @trusted { return read(fd, &nfo, nfo.sizeof); } ();
|
||||||
|
if (ret == -1 && errno == EAGAIN)
|
||||||
|
break;
|
||||||
|
if (ret != nfo.sizeof) {
|
||||||
|
cb(lid, SignalStatus.error, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addRef(lid);
|
||||||
|
cb(lid, SignalStatus.ok, nfo.ssi_signo);
|
||||||
|
releaseRef(lid);
|
||||||
|
} while (m_loop.m_fds[fd].refCount > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
37
tests/0-signal.d
Normal file
37
tests/0-signal.d
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/++ dub.sdl:
|
||||||
|
name "test"
|
||||||
|
dependency "eventcore" path=".."
|
||||||
|
+/
|
||||||
|
module test;
|
||||||
|
|
||||||
|
import eventcore.core;
|
||||||
|
import std.stdio : writefln;
|
||||||
|
import core.stdc.signal;
|
||||||
|
import core.sys.posix.signal : SIGRTMIN;
|
||||||
|
import core.time : msecs;
|
||||||
|
|
||||||
|
bool s_done;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
auto id = eventDriver.signals.listen(SIGRTMIN+1, (id, status, sig) {
|
||||||
|
assert(!s_done);
|
||||||
|
assert(status == SignalStatus.ok);
|
||||||
|
assert(sig == () @trusted { return SIGRTMIN+1; } ());
|
||||||
|
s_done = true;
|
||||||
|
eventDriver.core.exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto tm = eventDriver.timers.create();
|
||||||
|
eventDriver.timers.set(tm, 500.msecs);
|
||||||
|
eventDriver.timers.wait(tm, (tm) {
|
||||||
|
() @trusted { raise(SIGRTMIN+1); } ();
|
||||||
|
});
|
||||||
|
|
||||||
|
ExitReason er;
|
||||||
|
do er = eventDriver.core.processEvents();
|
||||||
|
while (er == ExitReason.idle);
|
||||||
|
//assert(er == ExitReason.outOfWaiters); // FIXME: see above
|
||||||
|
assert(s_done);
|
||||||
|
s_done = false;
|
||||||
|
}
|
Loading…
Reference in a new issue