From b35823b9126e83e990b085aec90145d2cf408d9f Mon Sep 17 00:00:00 2001 From: Corey Johnson & Nathan Sobo Date: Wed, 25 Apr 2012 17:38:25 -0600 Subject: [PATCH] PathWatcher no longer opens multiple file descriptors for the same path and other :lipstick: --- Atom/src/PathWatcher.h | 1 + Atom/src/PathWatcher.m | 63 +++++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/Atom/src/PathWatcher.h b/Atom/src/PathWatcher.h index 0f51d6e8e..00fdd302c 100644 --- a/Atom/src/PathWatcher.h +++ b/Atom/src/PathWatcher.h @@ -4,6 +4,7 @@ typedef void (^WatchCallback)(NSArray *); @interface PathWatcher : NSObject { int _kq; + NSMutableDictionary *_fileDescriptorsByPath; NSMutableDictionary *_callbacksByFileDescriptor; } diff --git a/Atom/src/PathWatcher.m b/Atom/src/PathWatcher.m index fdcee6dd6..c4ee49c1b 100644 --- a/Atom/src/PathWatcher.m +++ b/Atom/src/PathWatcher.m @@ -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);