Implement an alternative workaround for CFRunLoop hangs.
Limits the timeout for the CFRunLoop call to one second, after which kqueue will be re-checked again manually, guaranteeing that if a hang occurs, it will be resolved after at most one second.
This commit is contained in:
parent
a9344c8490
commit
a77f626b97
|
@ -38,14 +38,38 @@ final class CFRunLoopEventLoop : KqueueEventLoopBase {
|
|||
|
||||
override bool doProcessEvents(Duration timeout)
|
||||
@trusted {
|
||||
import std.algorithm.comparison : min;
|
||||
|
||||
// submit changes and process pending events
|
||||
auto kres = doProcessEventsBase(0.seconds);
|
||||
if (kres) timeout = 0.seconds;
|
||||
|
||||
CFTimeInterval to = kres ? 0.0 : 1e-7 * timeout.total!"hnsecs";
|
||||
// NOTE: the timeout per CFRunLoopRunInMode call is limited to one
|
||||
// second to work around the issue that the kqueue CFFileDescriptor
|
||||
// sometimes does not fire. There seems to be some kind of race-
|
||||
// condition, between the edge-triggered kqueue events and
|
||||
// CFFileDescriptorEnableCallBacks/CFRunLoopRunInMode.
|
||||
//
|
||||
// Even changing the order of calls in processKqueue to first
|
||||
// re-enable the callbacks and *then* process the already pending
|
||||
// events does not help (and is also eplicitly discouraged in
|
||||
// Apple's documentation).
|
||||
while (timeout > 0.seconds) {
|
||||
auto tol = min(timeout, 1.seconds);
|
||||
timeout -= tol;
|
||||
CFTimeInterval to = 1e-7 * tol.total!"hnsecs";
|
||||
auto res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, to, true);
|
||||
if (res != CFRunLoopRunResult.kCFRunLoopRunTimedOut) {
|
||||
return kres || res == CFRunLoopRunResult.kCFRunLoopRunHandledSource;
|
||||
}
|
||||
|
||||
kres = doProcessEventsBase(0.seconds);
|
||||
if (kres) break;
|
||||
}
|
||||
|
||||
return kres;
|
||||
}
|
||||
|
||||
override void dispose()
|
||||
{
|
||||
() @trusted {
|
||||
|
|
Loading…
Reference in a new issue