From f8f68067d7b822a6cb7aba4eaefdb32b1a4a7bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C5=93ur?= Date: Sun, 31 Dec 2023 22:17:31 +0100 Subject: [PATCH] perf: Don't poll every second for kevents (#6452) * perf: Don't poll every second for kevents * No need to alter properties in dealloc --- macosx/VDKQueue/VDKQueue.h | 2 ++ macosx/VDKQueue/VDKQueue.mm | 28 ++++++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/macosx/VDKQueue/VDKQueue.h b/macosx/VDKQueue/VDKQueue.h index 1ee87b3db..ebfc912b2 100644 --- a/macosx/VDKQueue/VDKQueue.h +++ b/macosx/VDKQueue/VDKQueue.h @@ -86,6 +86,8 @@ // // - macOS 10.10+: DispatchSource API (makeFileSystemObjectSource) // (https://developer.apple.com/documentation/dispatch/dispatchsource/2300040-makefilesystemobjectsource) +// "DispatchSource is just the Swift version of gcd dispatch sources" +// (https://github.com/bdkjones/VDKQueue/pull/22#issuecomment-1871623127) // // Example: SFSMonitor (https://github.com/ClassicalDude/SFSMonitor) diff --git a/macosx/VDKQueue/VDKQueue.mm b/macosx/VDKQueue/VDKQueue.mm index ef6b0f81e..fe86122bc 100644 --- a/macosx/VDKQueue/VDKQueue.mm +++ b/macosx/VDKQueue/VDKQueue.mm @@ -39,8 +39,8 @@ NSString const* VDKQueueAccessRevocationNotification = @"VDKQueueAccessWasRevoke /// This is a simple model class used to hold info about each path we watch. @interface VDKQueuePathEntry : NSObject -@property(atomic, copy) NSString* path; -@property(atomic, assign) int watchedFD; +@property(atomic, copy, readonly) NSString* path; +@property(atomic, assign, readonly) int watchedFD; @property(atomic, assign) u_int subscriptionFlags; @end @@ -69,7 +69,6 @@ NSString const* VDKQueueAccessRevocationNotification = @"VDKQueueAccessWasRevoke { close(_watchedFD); } - _watchedFD = -1; } @end @@ -147,7 +146,6 @@ NSString const* VDKQueueAccessRevocationNotification = @"VDKQueueAccessWasRevoke { struct timespec nullts = { 0, 0 }; struct kevent ev; - EV_SET(&ev, pathEntry.watchedFD, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, flags, 0, (__bridge void*)pathEntry); pathEntry.subscriptionFlags = flags; @@ -176,16 +174,13 @@ NSString const* VDKQueueAccessRevocationNotification = @"VDKQueueAccessWasRevoke NSThread.currentThread.name = @"VDKQueue"; struct kevent ev; - // 1 second timeout. Should be longer, but we need this thread to exit when a kqueue is dealloced, so 1 second timeout is quite a while to wait. - const struct timespec timeout = { 1, 0 }; - // So we don't have to risk accessing iVars when the thread is terminated. int const theFD = _coreQueueFD; NSMutableArray* notesToPost = [[NSMutableArray alloc] initWithCapacity:5]; while (_keepWatcherThreadRunning) { - int n = kevent(theFD, NULL, 0, &ev, 1, &timeout); + int n = kevent(theFD, NULL, 0, &ev, 1, NULL); if (n <= 0 || ev.filter != EVFILT_VNODE || !ev.fflags) { continue; @@ -294,6 +289,17 @@ NSString const* VDKQueueAccessRevocationNotification = @"VDKQueueAccessWasRevoke } } +/// Shut down the thread that's scanning for kQueue events. +- (void)shutdownWatcherThread +{ + _keepWatcherThreadRunning = NO; + + // Trigger a custom event to stop the thread. + struct timespec nullts = { 0, 0 }; + struct kevent stopEvent = { 0, EVFILT_USER, EV_ADD | EV_ONESHOT, NOTE_TRIGGER, 0, NULL }; + kevent(_coreQueueFD, &stopEvent, 1, NULL, 0, &nullts); +} + - (void)removePath:(NSString*)aPath { if (!aPath) @@ -310,8 +316,7 @@ NSString const* VDKQueueAccessRevocationNotification = @"VDKQueueAccessWasRevoke if (_watchedPathEntries.count == 0) { - // Shut down the thread that's scanning for kQueue events. - _keepWatcherThreadRunning = NO; + [self shutdownWatcherThread]; } } } @@ -323,8 +328,7 @@ NSString const* VDKQueueAccessRevocationNotification = @"VDKQueueAccessWasRevoke // Close all the open file descriptors for files we're watching. [_watchedPathEntries removeAllObjects]; - // Shut down the thread that's scanning for kQueue events. - _keepWatcherThreadRunning = NO; + [self shutdownWatcherThread]; } }