We've been fighting with some DSO/Pool related bugs in Subversion lately, and have basically come to the conclusion that there's no good solution, or at least no good solution that doesn't involve patching APR itself.
The problem, in short, is that when you use a pool to load a DSO you need to make sure that the pool lives longer than any code that might call a function within the DSO. This is simple enough with most things, but when the code inside the DSO makes use of pools, specifically pool cleanups, you can easily end up in situations where you've set up a cleanup (which calls a function defined inside the DSO) on a pool that will outlive the pool used to open the DSO. This means that by the time you call that cleanup function the DSO is unloaded, so all sorts of badness ensues. The timeline for this sort of thing looks like this: 1. Create application pool (global scope). 2. In another global pool open up a DSO. 3. Call a function defined in the DSO, passing in your application pool. 4. The function inside the DSO registers a cleanup on the application pool. 5. The program finishes, and apr_terminate is called. 6. Global pools are destroyed in a last-in first-out manner, so the pool used to load the DSO is destroyed (and the DSO is unloaded) before the application pool, madness ensues. So if you're going to pass pools into a function within a DSO you basically need to make sure that the DSO is loaded in an older pool, to be 100% sure it has to be a pool that's older than ANY other pool. Possible solutions include: 1) Just use the global top level pool to load the DSO. This sounds great, but is not thread safe, so it's a no-no. 2) Create yourself a global pool to load DSOs into, and do so early enough that it'll always be destroyed last. This works if you have control over the entire program, but basically means you need to do this immediately after apr_initialize(), which may not always be possible (what if you're a library, or you're running inside of a httpd module, etc). Basically, what I'd like to do is add a new API (say, apr_dso_load_permanently, or hopefully something with a better name than that) which will load DSOs into a new global pool that's created during apr_initialize(), it'll be the first pool created after the global top level APR pool, and thus it'll be certain to outlive any application created pool. The dsos will only be unloaded at apr_terminate time, when their global pool is destroyed, but honestly, that's what I want in this situation anyway, as it's impossible to be sure that users of your API haven't done unfortunate things with pools that make unloading the DSO dangerous anyway. Thoughts? -garrett
