PathWatcher no longer opens multiple file descriptors for the same path and other 💄

This commit is contained in:
Corey Johnson & Nathan Sobo
2012-04-25 17:38:25 -06:00
parent 7970b876dc
commit b35823b912
2 changed files with 42 additions and 22 deletions

View File

@@ -4,6 +4,7 @@ typedef void (^WatchCallback)(NSArray *);
@interface PathWatcher : NSObject {
int _kq;
NSMutableDictionary *_fileDescriptorsByPath;
NSMutableDictionary *_callbacksByFileDescriptor;
}

View File

@@ -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);