Implement a CFRunLoop based event loop.
This enables efficient integration of the kqueue based I/O processing with Apple OS based UI apps. On top of that, an FSEvent based directory watcher can now be implemented to replace the inefficient generic watcher that is used on macOS right now.
This commit is contained in:
parent
4b1afa8d6c
commit
e28450f9f5
6
dub.sdl
6
dub.sdl
|
@ -23,6 +23,12 @@ configuration "epoll-gaia" {
|
||||||
versions "EventcoreEpollDriver"
|
versions "EventcoreEpollDriver"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configuration "cfrunloop" {
|
||||||
|
platforms "osx"
|
||||||
|
versions "EventcoreCFRunLoopDriver"
|
||||||
|
lflags "-framework" "CoreFoundation"
|
||||||
|
}
|
||||||
|
|
||||||
configuration "kqueue" {
|
configuration "kqueue" {
|
||||||
platforms "osx" "freebsd"
|
platforms "osx" "freebsd"
|
||||||
versions "EventcoreKqueueDriver"
|
versions "EventcoreKqueueDriver"
|
||||||
|
|
|
@ -2,14 +2,16 @@ module eventcore.core;
|
||||||
|
|
||||||
public import eventcore.driver;
|
public import eventcore.driver;
|
||||||
|
|
||||||
import eventcore.drivers.posix.loop.select;
|
import eventcore.drivers.posix.loop.cfrunloop;
|
||||||
import eventcore.drivers.posix.loop.epoll;
|
import eventcore.drivers.posix.loop.epoll;
|
||||||
import eventcore.drivers.posix.loop.kqueue;
|
import eventcore.drivers.posix.loop.kqueue;
|
||||||
|
import eventcore.drivers.posix.loop.select;
|
||||||
import eventcore.drivers.libasync;
|
import eventcore.drivers.libasync;
|
||||||
import eventcore.drivers.winapi.driver;
|
import eventcore.drivers.winapi.driver;
|
||||||
import eventcore.internal.utils : mallocT, freeT;
|
import eventcore.internal.utils : mallocT, freeT;
|
||||||
|
|
||||||
version (EventcoreEpollDriver) alias NativeEventDriver = EpollEventDriver;
|
version (EventcoreEpollDriver) alias NativeEventDriver = EpollEventDriver;
|
||||||
|
else version (EventcoreCFRunLoopDriver) alias NativeEventDriver = CFRunLoopEventDriver;
|
||||||
else version (EventcoreKqueueDriver) alias NativeEventDriver = KqueueEventDriver;
|
else version (EventcoreKqueueDriver) alias NativeEventDriver = KqueueEventDriver;
|
||||||
else version (EventcoreWinAPIDriver) alias NativeEventDriver = WinAPIEventDriver;
|
else version (EventcoreWinAPIDriver) alias NativeEventDriver = WinAPIEventDriver;
|
||||||
else version (EventcoreLibasyncDriver) alias NativeEventDriver = LibasyncEventDriver;
|
else version (EventcoreLibasyncDriver) alias NativeEventDriver = LibasyncEventDriver;
|
||||||
|
|
65
source/eventcore/drivers/posix/loop/cfrunloop.d
Normal file
65
source/eventcore/drivers/posix/loop/cfrunloop.d
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/**
|
||||||
|
`CFRunLoop` based event loop for macOS UI compatible operation.
|
||||||
|
*/
|
||||||
|
module eventcore.drivers.posix.loop.cfrunloop;
|
||||||
|
@safe: /*@nogc:*/ nothrow:
|
||||||
|
|
||||||
|
version (EventcoreCFRunLoopDriver):
|
||||||
|
|
||||||
|
import eventcore.drivers.posix.loop.kqueue;
|
||||||
|
import eventcore.internal.corefoundation;
|
||||||
|
import eventcore.internal.utils;
|
||||||
|
import core.time;
|
||||||
|
|
||||||
|
|
||||||
|
alias CFRunLoopEventDriver = PosixEventDriver!CFRunLoopEventLoop;
|
||||||
|
|
||||||
|
final class CFRunLoopEventLoop : KqueueEventLoopBase {
|
||||||
|
@safe nothrow:
|
||||||
|
private {
|
||||||
|
CFFileDescriptorRef m_kqueueDescriptor;
|
||||||
|
CFRunLoopSourceRef m_kqueueSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
this()
|
||||||
|
@trusted @nogc {
|
||||||
|
super();
|
||||||
|
|
||||||
|
CFFileDescriptorContext ctx;
|
||||||
|
ctx.info = cast(void*)this;
|
||||||
|
|
||||||
|
m_kqueueDescriptor = CFFileDescriptorCreate(kCFAllocatorDefault,
|
||||||
|
m_queue, false, &processKqueue, &ctx);
|
||||||
|
|
||||||
|
CFFileDescriptorEnableCallBacks(m_kqueueDescriptor, CFOptionFlags.kCFFileDescriptorReadCallBack);
|
||||||
|
m_kqueueSource = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, m_kqueueDescriptor, 0);
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetMain(), m_kqueueSource, kCFRunLoopDefaultMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
override bool doProcessEvents(Duration timeout)
|
||||||
|
@trusted {
|
||||||
|
// submit changes and process pending events
|
||||||
|
auto kres = doProcessEventsBase(0.seconds);
|
||||||
|
|
||||||
|
CFTimeInterval to = kres ? 0.0 : 1e-7 * timeout.total!"hnsecs";
|
||||||
|
auto res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, to, true);
|
||||||
|
return kres || res == CFRunLoopRunResult.kCFRunLoopRunHandledSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void dispose()
|
||||||
|
{
|
||||||
|
() @trusted {
|
||||||
|
CFRelease(m_kqueueSource);
|
||||||
|
CFRelease(m_kqueueDescriptor);
|
||||||
|
} ();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static extern(C) void processKqueue(CFFileDescriptorRef fdref,
|
||||||
|
CFOptionFlags callBackTypes, void* info)
|
||||||
|
{
|
||||||
|
auto this_ = () @trusted { return cast(CFRunLoopEventLoop)info; } ();
|
||||||
|
auto res = this_.doProcessEventsBase(0.seconds);
|
||||||
|
() @trusted { CFFileDescriptorEnableCallBacks(this_.m_kqueueDescriptor, CFOptionFlags.kCFFileDescriptorReadCallBack); } ();
|
||||||
|
}
|
||||||
|
}
|
35
source/eventcore/internal/corefoundation.d
Normal file
35
source/eventcore/internal/corefoundation.d
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
module eventcore.internal.corefoundation;
|
||||||
|
|
||||||
|
version (Darwin):
|
||||||
|
|
||||||
|
extern(C):
|
||||||
|
|
||||||
|
static if (!is(typeof(CFRelease))) {
|
||||||
|
alias CFTypeRef = const(void)*;
|
||||||
|
alias CFTypeRef CFAllocatorRef;
|
||||||
|
extern const CFAllocatorRef kCFAllocatorDefault;
|
||||||
|
CFTypeRef CFRetain(CFTypeRef cf);
|
||||||
|
void CFRelease(CFTypeRef cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (!is(typeof(CFRunLoop))) {
|
||||||
|
alias CFRunLoopMode = CFStringRef;
|
||||||
|
struct __CFRunLoop;
|
||||||
|
alias CFRunLoopRef = __CFRunLoop*;
|
||||||
|
struct __CFRunLoopSource;
|
||||||
|
alias CFRunLoopSourceRef = __CFRunLoopSource*;
|
||||||
|
|
||||||
|
alias CFTimeInterval = double;
|
||||||
|
alias Boolean = bool;
|
||||||
|
|
||||||
|
extern const CFStringRef kCFRunLoopDefaultMode;
|
||||||
|
extern const CFStringRef kCFRunLoopCommonModes;
|
||||||
|
|
||||||
|
void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFRunLoopMode mode);
|
||||||
|
CFRunLoopRunResult CFRunLoopRunInMode(CFRunLoopMode mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (!is(CFFileDescriptor)) {
|
||||||
|
alias FSEventStreamRef = x;
|
||||||
|
FSEventStreamRef FSEventStreamCreate(CFAllocatorRef allocator, FSEventStreamCallback callback, FSEventStreamContext *context, CFArrayRef pathsToWatch, FSEventStreamEventId sinceWhen, CFTimeInterval latency, FSEventStreamCreateFlags flags);
|
||||||
|
}
|
Loading…
Reference in a new issue