Work around possible hang of CFRunLoop with pending kqueue events.

This commit is contained in:
Sönke Ludwig 2020-05-25 10:31:43 +02:00
parent 307542ff82
commit decbe7f6bd
2 changed files with 9 additions and 3 deletions

View file

@ -25,6 +25,11 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase {
@trusted @nogc { @trusted @nogc {
super(); super();
// Edge-triggred mode is not fully reliable w.r.t. the CFFileDescriptor
// firing the callback for some reason. Always using level-triggered
// kqueue events avoids possible hangs during CFRunLoopInMode
m_forceLevelTriggered = true;
CFFileDescriptorContext ctx; CFFileDescriptorContext ctx;
ctx.info = cast(void*)this; ctx.info = cast(void*)this;

View file

@ -45,6 +45,7 @@ abstract class KqueueEventLoopBase : PosixEventLoop {
size_t m_changeCount = 0; size_t m_changeCount = 0;
kevent_t[100] m_changes; kevent_t[100] m_changes;
kevent_t[100] m_events; kevent_t[100] m_events;
bool m_forceLevelTriggered = false;
} }
this() this()
@ -101,7 +102,7 @@ abstract class KqueueEventLoopBase : PosixEventLoop {
kevent_t ev; kevent_t ev;
ev.ident = fd; ev.ident = fd;
ev.flags = EV_ADD|EV_ENABLE; ev.flags = EV_ADD|EV_ENABLE;
if (edge_triggered) ev.flags |= EV_CLEAR; if (edge_triggered && !m_forceLevelTriggered) ev.flags |= EV_CLEAR;
if (mask & EventMask.read) { if (mask & EventMask.read) {
ev.filter = EVFILT_READ; ev.filter = EVFILT_READ;
putChange(ev); putChange(ev);
@ -130,14 +131,14 @@ abstract class KqueueEventLoopBase : PosixEventLoop {
if (changes & EventMask.read) { if (changes & EventMask.read) {
ev.filter = EVFILT_READ; ev.filter = EVFILT_READ;
ev.flags = new_mask & EventMask.read ? EV_ADD : EV_DELETE; ev.flags = new_mask & EventMask.read ? EV_ADD : EV_DELETE;
if (edge_triggered) ev.flags |= EV_CLEAR; if (edge_triggered && !m_forceLevelTriggered) ev.flags |= EV_CLEAR;
putChange(ev); putChange(ev);
} }
if (changes & EventMask.write) { if (changes & EventMask.write) {
ev.filter = EVFILT_WRITE; ev.filter = EVFILT_WRITE;
ev.flags = new_mask & EventMask.write ? EV_ADD : EV_DELETE; ev.flags = new_mask & EventMask.write ? EV_ADD : EV_DELETE;
if (edge_triggered) ev.flags |= EV_CLEAR; if (edge_triggered && !m_forceLevelTriggered) ev.flags |= EV_CLEAR;
putChange(ev); putChange(ev);
} }