@@ -19,7 +19,7 @@ @interface SSYPathWatch : NSObject {
19
19
NSString * m_path ;
20
20
id m_userInfo ;
21
21
uint32_t m_fileDescriptor ;
22
- NSThread * m_notifyThread ;
22
+ __unsafe_unretained NSThread * m_notifyThread ;
23
23
}
24
24
25
25
@property (retain ) NSString * path ;
@@ -53,12 +53,14 @@ - (BOOL)isEqual:(SSYPathWatch*)otherPathWatch {
53
53
return ([[otherPathWatch path ] isEqualToString: [self path ]]) ;
54
54
}
55
55
56
+ #if !__has_feature(objc_arc)
56
57
- (void )dealloc {
57
58
[m_path release ] ;
58
59
[m_userInfo release ] ;
59
60
60
61
[super dealloc ] ;
61
62
}
63
+ #endif
62
64
63
65
@end
64
66
@@ -76,6 +78,7 @@ @implementation SSYPathObserver
76
78
@synthesize pathWatches = m_pathWatches ;
77
79
@synthesize kqueueFileDescriptor = m_kqueueFileDescriptor ; // file descriptor for the kqueue
78
80
81
+ #if !__has_feature(objc_arc)
79
82
/*
80
83
Note that this method is always invoked by the watcher
81
84
thread, not the main thread. See commments in -release.
@@ -85,6 +88,7 @@ - (void)dealloc {
85
88
86
89
[super dealloc ] ;
87
90
}
91
+ #endif
88
92
89
93
- (void )watchAndWait {
90
94
/* Note that, in macOS 10.5, we may kill this thread in -release.
@@ -105,13 +109,11 @@ camping on kevent(), outside of these two blocks of code, but,
105
109
106
110
int fileDescriptor ;
107
111
@synchronized (self) {
108
- NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc ] init ] ;
109
-
110
- [[NSThread currentThread ] setName: SSYPathObserverWatcherThread] ;
111
-
112
- fileDescriptor = [self kqueueFileDescriptor ] ;
113
-
114
- [pool1 release ] ;
112
+ @autoreleasepool {
113
+ [[NSThread currentThread ] setName: SSYPathObserverWatcherThread] ;
114
+
115
+ fileDescriptor = [self kqueueFileDescriptor ] ;
116
+ }
115
117
}
116
118
117
119
@@ -128,63 +130,66 @@ camping on kevent(), outside of these two blocks of code, but,
128
130
) ;
129
131
if (result != -1 ) {
130
132
if (event.filter == EVFILT_VNODE ) {
131
- SSYPathWatch* pathWatch = (SSYPathWatch*)event.udata ;
133
+ SSYPathWatch* pathWatch = (__bridge SSYPathWatch*)event.udata ;
132
134
133
135
@synchronized (self) {
134
- NSAutoreleasePool * pool2 = [[NSAutoreleasePool alloc ] init ] ;
135
- // Retain pathWatch here, in case of the unlikely event that
136
- // pathWatch has just been removed on another thread
137
- [pathWatch retain ] ;
138
- NSString * path = [pathWatch path ];
139
- NSDictionary * pathWatchUserInfo = [pathWatch userInfo ];
140
- NSThread * notifyThread = [pathWatch notifyThread ];
141
- if ([self isWatching ]) {
142
- NSNumber * filterFlags = [NSNumber numberWithInteger: event.fflags] ;
143
- NSDictionary * userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
144
- filterFlags, SSYPathObserverChangeFlagsKey,
145
- path, SSYPathObserverPathKey,
146
- [NSNumber numberWithInteger: [pathWatch fileDescriptor ]], SSYPathObserverFileDescriptorKey,
147
- pathWatchUserInfo, SSYPathObserverUserInfoKey, // may be nil
148
- nil ] ;
149
- NSNotification * note = [NSNotification notificationWithName: SSYPathObserverChangeNotification
150
- object: self
151
- userInfo: userInfo] ;
152
- [[NSNotificationCenter defaultCenter ] performSelector: @selector (postNotification: )
153
- onThread: notifyThread
154
- withObject: note
155
- waitUntilDone: NO ] ;
156
- }
157
-
158
- /* In some cases, I think if the event we re no processing was
159
- caused by an external actor *replacing* the file at the watched
160
- path with a new file, our path watch will be watching the old file
161
- which no longer exists, and therefore we will not get any subsequent
162
- events when the *new* file at the watched path is touched. Although I
163
- have not verified that such file replacement is the cause, I have
164
- definitely seen kqueues "die" like this. I think it's a good theory,
165
- and in at least one reproducible case, the following code, which
166
- removes the "used" path watch adds back a new one) fixed the problem.
167
- I theorize this is due to the fact that destroying the path watch
168
- closes its (watched) file descriptor, and creating a new path
169
- watch opens a new file descriptor. I did verify that the new file
170
- descriptor integer value is the same as the old one; presumably
171
- the system uses the lowest unused file descriptor which is the old
172
- one that was just released. */
173
- BOOL ok;
174
- NSError * error = nil ;
175
- ok = [self removePath: path
176
- error_p: &error];
177
- NSAssert (ok, @" Error removing used path from kqueue : %@ " , error);
178
- uint32_t watchFlags = pathWatch.watchFlags ;
179
- [pathWatch release ] ;
180
- [self addPath: path
181
- watchFlags: watchFlags
182
- notifyThread: notifyThread
183
- userInfo: pathWatchUserInfo
184
- error_p: &error];
185
- NSAssert (ok, @" Error renewing used path from kqueue : %@ " , error);
186
-
187
- [pool2 release ] ;
136
+ @autoreleasepool {
137
+ // Retain pathWatch here, in case of the unlikely event that
138
+ // pathWatch has just been removed on another thread
139
+ #if !__has_feature(objc_arc)
140
+ [pathWatch retain ] ;
141
+ #endif
142
+ NSString * path = [pathWatch path ];
143
+ NSDictionary * pathWatchUserInfo = [pathWatch userInfo ];
144
+ NSThread * notifyThread = [pathWatch notifyThread ];
145
+ if ([self isWatching ]) {
146
+ NSNumber * filterFlags = [NSNumber numberWithInteger: event.fflags] ;
147
+ NSDictionary * userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
148
+ filterFlags, SSYPathObserverChangeFlagsKey,
149
+ path, SSYPathObserverPathKey,
150
+ [NSNumber numberWithInteger: [pathWatch fileDescriptor ]], SSYPathObserverFileDescriptorKey,
151
+ pathWatchUserInfo, SSYPathObserverUserInfoKey, // may be nil
152
+ nil ] ;
153
+ NSNotification * note = [NSNotification notificationWithName: SSYPathObserverChangeNotification
154
+ object: self
155
+ userInfo: userInfo] ;
156
+ [[NSNotificationCenter defaultCenter ] performSelector: @selector (postNotification: )
157
+ onThread: notifyThread
158
+ withObject: note
159
+ waitUntilDone: NO ] ;
160
+ }
161
+
162
+ /* In some cases, I think if the event we re no processing was
163
+ caused by an external actor *replacing* the file at the watched
164
+ path with a new file, our path watch will be watching the old file
165
+ which no longer exists, and therefore we will not get any subsequent
166
+ events when the *new* file at the watched path is touched. Although I
167
+ have not verified that such file replacement is the cause, I have
168
+ definitely seen kqueues "die" like this. I think it's a good theory,
169
+ and in at least one reproducible case, the following code, which
170
+ removes the "used" path watch adds back a new one) fixed the problem.
171
+ I theorize this is due to the fact that destroying the path watch
172
+ closes its (watched) file descriptor, and creating a new path
173
+ watch opens a new file descriptor. I did verify that the new file
174
+ descriptor integer value is the same as the old one; presumably
175
+ the system uses the lowest unused file descriptor which is the old
176
+ one that was just released. */
177
+ BOOL ok;
178
+ NSError * error = nil ;
179
+ ok = [self removePath: path
180
+ error_p: &error];
181
+ NSAssert (ok, @" Error removing used path from kqueue : %@ " , error);
182
+ uint32_t watchFlags = pathWatch.watchFlags ;
183
+ #if !__has_feature(objc_arc)
184
+ [pathWatch release ] ;
185
+ #endif
186
+ [self addPath: path
187
+ watchFlags: watchFlags
188
+ notifyThread: notifyThread
189
+ userInfo: pathWatchUserInfo
190
+ error_p: &error];
191
+ NSAssert (ok, @" Error renewing used path from kqueue : %@ " , error);
192
+ }
188
193
}
189
194
}
190
195
}
@@ -211,7 +216,9 @@ -(id)init {
211
216
if (kqueueFileDescriptor == -1 ) {
212
217
NSLog (@" Internal Error 153-9092. Failed creating kqueue" ) ;
213
218
// See http://lists.apple.com/archives/Objc-language/2008/Sep/msg00133.html ...
219
+ #if !__has_feature(objc_arc)
214
220
[super dealloc ] ;
221
+ #endif
215
222
self = nil ;
216
223
}
217
224
else {
@@ -302,7 +309,7 @@ - (BOOL)kqueueRegisterPathWatch:(SSYPathWatch*)pathWatch
302
309
actionFlags, // flags
303
310
fflags, // fflags
304
311
0 , // data
305
- pathWatch // udata, user data, aka "context info"
312
+ (__bridge void *) pathWatch // udata, user data, aka "context info"
306
313
) ;
307
314
308
315
#if DEBUG_LOG_KQUEUE_SETTINGS
@@ -347,6 +354,7 @@ - (BOOL)kqueueRegisterPathWatch:(SSYPathWatch*)pathWatch
347
354
return ok ;
348
355
}
349
356
357
+ #if !__has_feature(objc_arc)
350
358
- (oneway void )release {
351
359
// The default behavior of -release is to decrement retainCount if
352
360
// retainCount is greater than 1, and otherwise invoke -dealloc.
@@ -396,6 +404,7 @@ - (oneway void)release {
396
404
[super release ] ;
397
405
return ;
398
406
}
407
+ #endif
399
408
400
409
#if 0
401
410
- (id)autorelease {
@@ -431,28 +440,29 @@ - (BOOL)addPath:(NSString*)path
431
440
}
432
441
433
442
ok = NO ;
434
- goto end ;
435
443
}
436
444
437
- // Create pathWatch
438
- SSYPathWatch* pathWatch = [[SSYPathWatch alloc ] init ] ;
439
- [pathWatch setPath: path] ;
440
- [pathWatch setUserInfo: userInfo] ;
441
- [pathWatch setFileDescriptor: fileDescriptor] ;
442
- [pathWatch setNotifyThread: (notifyThread ? notifyThread : [NSThread mainThread ])] ;
443
- @synchronized (self) {
444
- [[self pathWatches ] addObject: pathWatch] ;
445
- [pathWatch release ] ;
446
-
447
- // Register kqueue for it
448
- ok = [self kqueueRegisterPathWatch: pathWatch
449
- doAdd: YES
450
- flags: watchFlags
451
- error_p: error_p] ;
452
- }
453
-
454
- end:
455
- return ok ;
445
+ if (ok) {
446
+ // Create pathWatch
447
+ SSYPathWatch* pathWatch = [[SSYPathWatch alloc ] init ] ;
448
+ [pathWatch setPath: path] ;
449
+ [pathWatch setUserInfo: userInfo] ;
450
+ [pathWatch setFileDescriptor: fileDescriptor] ;
451
+ [pathWatch setNotifyThread: (notifyThread ? notifyThread : [NSThread mainThread ])] ;
452
+ @synchronized (self) {
453
+ [[self pathWatches ] addObject: pathWatch] ;
454
+ #if !__has_feature(objc_arc)
455
+ [pathWatch release ] ;
456
+ #endif
457
+ // Register kqueue for it
458
+ ok = [self kqueueRegisterPathWatch: pathWatch
459
+ doAdd: YES
460
+ flags: watchFlags
461
+ error_p: error_p] ;
462
+ }
463
+ }
464
+
465
+ return ok ;
456
466
}
457
467
458
468
- (BOOL )removePath : (NSString *)path
@@ -499,9 +509,11 @@ - (NSSet*)currentlyWatchedPaths {
499
509
}
500
510
501
511
NSSet * answer = [paths copy ];
512
+ #if !__has_feature(objc_arc)
502
513
[paths release ];
503
514
[answer autorelease ];
504
-
515
+ #endif
516
+
505
517
return answer;
506
518
}
507
519
0 commit comments