Repository navigation
Install libdispatch autorelease pool hooks - #862
Conversation
rfm
left a comment
There was a problem hiding this comment.
This looks reasonable so far, but incomplete.
I think the ARC_RUNTIME guard is wrong (since the availability/use of libdispatch is independent of ARC).
I think this needs to use the correct pool creation/destruction for the way the library is configured, so if objc_autoreleasePoolPop and objc_autoreleasePoolPush don't exist it would need to call small functions to create and store a pool in one case and to destroy that pool in the other.
Those functions could be called objc_autoreleasePoolPush() and objc_autoreleasePoolPop() and implemented in Source/ObjectiveC2 so they are built as part of the library iff the runtime doesn't implement them.
200996d to
6b67da8
Compare
|
Yeah good points, sorry for not spotting that. Does the new version look better? |
rfm
left a comment
There was a problem hiding this comment.
Yes, that looks good now.
The one thing missing is a testcase to demonstrate that it actually works.
However, from visual inspection I have a pretty high degree of confidence, so I think it could be merged even if you don't want to write a testcase.
Let me know what you want to do.
6b67da8 to
d3abc52
Compare
|
Good point, I’ve added tests. (The Android tests seem to be flakey?) |
|
|
I tried the new testcase: it didn't work (the setup I created for testing this is a system using libdispatch with gcc), because it's conditional on blocks rather than libdispatch. What we need is a testcase for libdispatch wrapping a dispatched function (rather than a block) with autorelease. |
d3abc52 to
6808f56
Compare
|
Thanks. The test case should now also run when no blocks are available, and test both with and without blocks. |
rfm
left a comment
There was a problem hiding this comment.
Yes, that looks good.
But still, one more thought. I realised that dispatch/private.h is not normally installed.
It's kind of stupid if a hook we need to use is only declared in a private header, but perhaps it would be worth looking for the symbol in the library at configure time rather than gating on the header?
libdispatch wraps the work it runs on its worker threads in autorelease pools only if _dispatch_begin_NSAutoReleasePool and _dispatch_end_NSAutoReleasePool are set. Nothing set them, so objects autoreleased by dispatched blocks were only released when the worker thread exited. Point them at objc_autoreleasePoolPush() and objc_autoreleasePoolPop() whenever base uses libdispatch, independent of whether the runtime supports ARC. configure checks whether the runtime provides those functions, and if it doesn't, Source/ObjectiveC2/autorelease.m implements them with NSAutoreleasePool objects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6808f56 to
2b92fdb
Compare
|
Good point, should be done now. |
|
Works for me. Thanks. |
libdispatch wraps the work it runs on its worker threads in autorelease pools only if _dispatch_begin_NSAutoReleasePool and _dispatch_end_NSAutoReleasePool are set. Nothing set them, so objects autoreleased by dispatched blocks were only released when the worker thread exited. Point them at objc_autoreleasePoolPush() and objc_autoreleasePoolPop() whenever base uses libdispatch, independent of whether the runtime supports ARC. configure checks whether the runtime provides those functions, and if it doesn't, Source/ObjectiveC2/autorelease.m implements them with NSAutoreleasePool objects. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
libdispatch only wraps the work it runs on its worker threads in autorelease pools if
_dispatch_begin_NSAutoReleasePooland_dispatch_end_NSAutoReleasePoolare set. Nothing sets them, so objects autoreleased by dispatched blocks are only released when the worker thread exits (libobjc2 empties the thread's pool in its TLS destructor). For long-lived worker threads, that means they effectively leak.This change has
+[NSAutoreleasePool initialize]point the hooks atobjc_autoreleasePoolPush/objc_autoreleasePoolPopwhen building with libdispatch and the ARC-compatible runtime. These hooks are SPI meant for Foundation (dispatch/private.hmarks them "SPI for CoreFoundation/Foundation ONLY"), and base links against libdispatch directly, so on Windows the variables are reached through the DLL import as usual. Any hooks that were already set are left alone, and the end hook is set before the begin hook so a worker thread can't push a pool it then fails to pop.Why not libobjc2?
libobjc2 tries to install these hooks in
init_runtime()(loader.c), but that code has never run:NULL), not their addresses, so the assignments are never made.I’ve opened gnustep/libobjc2#436 to remove that code from libobjc2.