Re: CFFileDescriptor fd leak?
site_archiver@lists.apple.com Delivered-To: darwin-dev@lists.apple.com -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Aug 20, 2009, at 6:47 PM, Dave Keck wrote: Hey, #include <CoreFoundation/CoreFoundation.h> #include <unistd.h> #include <sys/event.h> static void junkCallback(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) {} int main(int argc, char *argv[]) { int i = 0; for (i = 0; i < 3; i++) { CFFileDescriptorRef fileDescriptor = nil; CFRunLoopSourceRef runLoopSource = nil; NSLog(@"CREATE %d", i); fileDescriptor = CFFileDescriptorCreate(NULL, 0, false, junkCallback, NULL); runLoopSource = CFFileDescriptorCreateRunLoopSource(NULL, fileDescriptor, 0); CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop], runLoopSource, kCFRunLoopDefaultMode); } sleep(-1); return 0; } ============================== Hi Dave, #include <CoreFoundation/CoreFoundation.h> #include <unistd.h> #include <sys/event.h> static void junkCallback(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) {} struct __FileDescriptorHackStruct { int junkA; int junkB; int junkC; int internalKqueueDescriptor; }; int main(int argc, char *argv[]) { int i = 0; for (i = 0; i < 3; i++) { CFFileDescriptorRef fileDescriptor = nil; CFRunLoopSourceRef runLoopSource = nil; fileDescriptor = CFFileDescriptorCreate(NULL, 0, false, junkCallback, NULL); runLoopSource = CFFileDescriptorCreateRunLoopSource(NULL, fileDescriptor, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); CFRelease(runLoopSource); CFFileDescriptorInvalidate(fileDescriptor); CFRelease(fileDescriptor); } sleep(-1); return 0; } Cheers, M -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.10 (Darwin) iEYEARECAAYFAkqN328ACgkQqVAj6JpR7t4LUQCfamtzP0xV6GWEBNxpQRw6ZK+I SuAAn3wouHd+LXixOKheQFJL3ccy2IuI =iogu -----END PGP SIGNATURE----- _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-dev mailing list (Darwin-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-dev/site_archiver%40lists.appl... I ran your test code and saw the same results. After tweaking the code a bit, I found that to have the kqueues cleaned up, you have to create a run loop source for the CFFD, add it to the run loop, and then remove it from the run loop. Here's the tweaked code: ============================== NSLog(@"DESTROY %d", i); CFRunLoopRemoveSource([[NSRunLoop currentRunLoop] getCFRunLoop], runLoopSource, kCFRunLoopDefaultMode); CFRelease(runLoopSource); CFFileDescriptorInvalidate(fileDescriptor); CFRelease(fileDescriptor); I'd definitely consider your findings a bug. But I don't think it poses any real issue, since CFFileDescriptor is useless unless it's used with a run loop. I'd say a radar is in order... I shaved down the code from the previous email from code which did indeed add the CFFileDescriptor to the runloop and leaked. However, I did not remove the source from the runloop manually like you do above and the Apple example code (http://developer.apple.com/documentation/CoreFoundation/Reference/CFFileDesc... ) doesn't remove the runloop source either. Unfortunately, the code you laid out above does indeed sometimes leak a single kqueue fd (OS 10.5.8): rd07:~ alex$ ./davekeck & [1] 4880 rd07:~ alex$ lsof -p $! | grep KQUEUE davekeck 4880 alex 4u KQUEUE count=0, state=0 If I run it with breakpoints on kqueue, close, and kevent in gdb, then the leak disappears, which indicates that the Apple code has a race condition. I noticed that close() is called in the __monitor_file_descriptor__ thread, so I suspect that without the thread created from the addition of a source, that close on the kqueue will never be called. The above code leaks sometimes due to a race condition in inter-thread communications- bizarrely, it leaks descriptor 4 which is the first that was allocated- I would have thought that the last one would leak... With the following hack-around code (based on yours), the fd leak is permanently squelched: close(((struct __FileDescriptorHackStruct*)fileDescriptor)-
internalKqueueDescriptor); At least it is not leaking threads. Speaking of which, why does each file descriptor need to be watched by a new thread? Not even CFSocketManager is that dumb. In any case, this is looking so bad that I will likely need to implement my own CFFileDescriptor replacement. This email sent to site_archiver@lists.apple.com
participants (1)
-
A.M.