From decbe7f6bdeb292183ac447c853d5825eacca8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 25 May 2020 10:31:43 +0200 Subject: [PATCH] Work around possible hang of CFRunLoop with pending kqueue events. --- source/eventcore/drivers/posix/cfrunloop.d | 5 +++++ source/eventcore/drivers/posix/kqueue.d | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/source/eventcore/drivers/posix/cfrunloop.d b/source/eventcore/drivers/posix/cfrunloop.d index d4a48dc..8fc7b45 100644 --- a/source/eventcore/drivers/posix/cfrunloop.d +++ b/source/eventcore/drivers/posix/cfrunloop.d @@ -25,6 +25,11 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase { @trusted @nogc { 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; ctx.info = cast(void*)this; diff --git a/source/eventcore/drivers/posix/kqueue.d b/source/eventcore/drivers/posix/kqueue.d index 3692e83..80e6bea 100644 --- a/source/eventcore/drivers/posix/kqueue.d +++ b/source/eventcore/drivers/posix/kqueue.d @@ -45,6 +45,7 @@ abstract class KqueueEventLoopBase : PosixEventLoop { size_t m_changeCount = 0; kevent_t[100] m_changes; kevent_t[100] m_events; + bool m_forceLevelTriggered = false; } this() @@ -101,7 +102,7 @@ abstract class KqueueEventLoopBase : PosixEventLoop { kevent_t ev; ev.ident = fd; 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) { ev.filter = EVFILT_READ; putChange(ev); @@ -130,14 +131,14 @@ abstract class KqueueEventLoopBase : PosixEventLoop { if (changes & EventMask.read) { ev.filter = EVFILT_READ; 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); } if (changes & EventMask.write) { ev.filter = EVFILT_WRITE; 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); }