mirror of
https://github.com/atom/atom.git
synced 2026-01-23 22:08:08 -05:00
PathWatcher no longer opens multiple file descriptors for the same path and other 💄
This commit is contained in:
@@ -4,6 +4,7 @@ typedef void (^WatchCallback)(NSArray *);
|
||||
|
||||
@interface PathWatcher : NSObject {
|
||||
int _kq;
|
||||
NSMutableDictionary *_fileDescriptorsByPath;
|
||||
NSMutableDictionary *_callbacksByFileDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
@interface PathWatcher ()
|
||||
- (void)watchPath:(NSString *)path callback:(WatchCallback)callback;
|
||||
- (void)watchFileDescriptor:(int)fd;
|
||||
@end
|
||||
|
||||
@implementation PathWatcher
|
||||
@@ -29,6 +30,7 @@
|
||||
self = [super init];
|
||||
|
||||
_callbacksByFileDescriptor = [[NSMutableDictionary alloc] init];
|
||||
_fileDescriptorsByPath = [[NSMutableDictionary alloc] init];
|
||||
_kq = kqueue();
|
||||
|
||||
if (_kq == -1) {
|
||||
@@ -39,33 +41,47 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)watchPath:(NSString *)path callback:(WatchCallback)callback {
|
||||
struct timespec timeout = { 0, 0 };
|
||||
struct kevent event;
|
||||
int fd = open([path fileSystemRepresentation], O_EVTONLY, 0);
|
||||
- (void)watchPath:(NSString *)path callback:(WatchCallback)callback {
|
||||
NSLog(@"Watching path %@", path);
|
||||
|
||||
if (fd >= 0) {
|
||||
int filter = EVFILT_VNODE;
|
||||
int flags = EV_ADD | EV_ENABLE | EV_CLEAR;
|
||||
int filterFlags = NOTE_ATTRIB | NOTE_WRITE | NOTE_EXTEND | NOTE_RENAME | NOTE_DELETE;
|
||||
|
||||
EV_SET(&event, fd, filter, flags, filterFlags, 0, (void *)path);
|
||||
|
||||
@synchronized(self) {
|
||||
NSNumber *fdNumber = [NSNumber numberWithInt:fd];
|
||||
NSMutableArray *callbacks = [_callbacksByFileDescriptor objectForKey:fdNumber];
|
||||
if (!callbacks) {
|
||||
callbacks = [NSMutableArray array];
|
||||
[_callbacksByFileDescriptor setObject:callbacks forKey:fdNumber];
|
||||
}
|
||||
[callbacks addObject:callback];
|
||||
|
||||
kevent(_kq, &event, 1, NULL, 0, &timeout);
|
||||
path = [path stringByStandardizingPath];
|
||||
|
||||
@synchronized(self) {
|
||||
NSNumber *fdNumber = [_fileDescriptorsByPath objectForKey:path];
|
||||
if (!fdNumber) {
|
||||
int fd = open([path fileSystemRepresentation], O_EVTONLY, 0);
|
||||
if (fd < 0) return; // TODO: Decide what to do here
|
||||
[self watchFileDescriptor:fd];
|
||||
|
||||
fdNumber = [NSNumber numberWithInt:fd];
|
||||
[_fileDescriptorsByPath setObject:fdNumber forKey:path];
|
||||
}
|
||||
|
||||
NSMutableArray *callbacks = [_callbacksByFileDescriptor objectForKey:fdNumber];
|
||||
if (!callbacks) {
|
||||
callbacks = [NSMutableArray array];
|
||||
[_callbacksByFileDescriptor setObject:callbacks forKey:fdNumber];
|
||||
}
|
||||
|
||||
[callbacks addObject:callback];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)watch {
|
||||
- (void)watchFileDescriptor:(int)fd {
|
||||
NSLog(@"Watching fd %d", fd);
|
||||
|
||||
struct timespec timeout = { 0, 0 };
|
||||
struct kevent event;
|
||||
int filter = EVFILT_VNODE;
|
||||
int flags = EV_ADD | EV_ENABLE | EV_CLEAR;
|
||||
int filterFlags = NOTE_WRITE;
|
||||
EV_SET(&event, fd, filter, flags, filterFlags, 0, 0);
|
||||
kevent(_kq, &event, 1, NULL, 0, &timeout);
|
||||
}
|
||||
|
||||
- (void)watch {
|
||||
NSLog(@"kicking off watch");
|
||||
|
||||
@autoreleasepool {
|
||||
struct kevent event;
|
||||
struct timespec timeout = { 5, 0 }; // 5 seconds timeout.
|
||||
@@ -82,12 +98,15 @@
|
||||
|
||||
NSMutableArray *eventFlags = [NSMutableArray array];
|
||||
|
||||
NSLog(@"flags are: %d, fd is: %d", event.fflags, (int)event.ident);
|
||||
|
||||
if (event.fflags & NOTE_WRITE) {
|
||||
[eventFlags addObject:@"modified"];
|
||||
}
|
||||
|
||||
@synchronized(self) {
|
||||
NSNumber *fdNumber = [NSNumber numberWithInt:event.ident];
|
||||
|
||||
for (WatchCallback callback in [_callbacksByFileDescriptor objectForKey:fdNumber]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(eventFlags);
|
||||
|
||||
Reference in New Issue
Block a user