Rearm the CFFileDescriptor before each CFRunLoop run.

Instead of rearming from within the callback, this enables the callback before the event loop is run and before the kqueue is cleared. This at least heavily reduces the cases where the CFRunLoop hangs instead of reporting a pending kqueue event. For this reason, the safety timeout has been increased to 5 seconds.
This commit is contained in:
Sönke Ludwig 2020-05-28 16:43:20 +02:00
parent f99ba6db49
commit ab829efc7c

View file

@ -31,7 +31,6 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase {
m_kqueueDescriptor = CFFileDescriptorCreate(kCFAllocatorDefault, m_kqueueDescriptor = CFFileDescriptorCreate(kCFAllocatorDefault,
m_queue, false, &processKqueue, &ctx); m_queue, false, &processKqueue, &ctx);
CFFileDescriptorEnableCallBacks(m_kqueueDescriptor, CFOptionFlags.kCFFileDescriptorReadCallBack);
m_kqueueSource = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, m_kqueueDescriptor, 0); m_kqueueSource = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, m_kqueueDescriptor, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), m_kqueueSource, kCFRunLoopDefaultMode); CFRunLoopAddSource(CFRunLoopGetCurrent(), m_kqueueSource, kCFRunLoopDefaultMode);
} }
@ -40,6 +39,8 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase {
@trusted { @trusted {
import std.algorithm.comparison : min; import std.algorithm.comparison : min;
CFFileDescriptorEnableCallBacks(m_kqueueDescriptor, CFOptionFlags.kCFFileDescriptorReadCallBack);
// submit changes and process pending events // submit changes and process pending events
auto kres = doProcessEventsBase(0.seconds); auto kres = doProcessEventsBase(0.seconds);
if (kres) timeout = 0.seconds; if (kres) timeout = 0.seconds;
@ -55,7 +56,7 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase {
// events does not help (and is also eplicitly discouraged in // events does not help (and is also eplicitly discouraged in
// Apple's documentation). // Apple's documentation).
while (timeout > 0.seconds) { while (timeout > 0.seconds) {
auto tol = min(timeout, 1.seconds); auto tol = min(timeout, 5.seconds);
timeout -= tol; timeout -= tol;
CFTimeInterval to = 1e-7 * tol.total!"hnsecs"; CFTimeInterval to = 1e-7 * tol.total!"hnsecs";
auto res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, to, true); auto res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, to, true);
@ -63,6 +64,7 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase {
return kres || res == CFRunLoopRunResult.kCFRunLoopRunHandledSource; return kres || res == CFRunLoopRunResult.kCFRunLoopRunHandledSource;
} }
CFFileDescriptorEnableCallBacks(m_kqueueDescriptor, CFOptionFlags.kCFFileDescriptorReadCallBack);
kres = doProcessEventsBase(0.seconds); kres = doProcessEventsBase(0.seconds);
if (kres) break; if (kres) break;
} }
@ -83,7 +85,6 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase {
CFOptionFlags callBackTypes, void* info) CFOptionFlags callBackTypes, void* info)
{ {
auto this_ = () @trusted { return cast(CFRunLoopEventLoop)info; } (); auto this_ = () @trusted { return cast(CFRunLoopEventLoop)info; } ();
auto res = this_.doProcessEventsBase(0.seconds); this_.doProcessEventsBase(0.seconds);
() @trusted { CFFileDescriptorEnableCallBacks(this_.m_kqueueDescriptor, CFOptionFlags.kCFFileDescriptorReadCallBack); } ();
} }
} }