Mladen Turk
Mon, 21 Jul 2008 03:38:58 -0700
Joe Orton wrote:
... S = apr_socket_create(P) ... do something ... with socket apr_socket_close(S) -> calls socket_cleanup(S) ... However if the apr_pool_destroy(P) gets called before apr_socket_close call (somebody rise the signal, etc..) the apr_pool_destroy call will cause the socket_cleanup(S) call and the apr_socket_close(S) will be no-op , and everything will behave as expected.1) Any operation on S after P is destroyed has undefined behaviour, including calling apr_socket_close(S). If that doesn't crash and burn with the current implementation it is pure chance.
Sure, and that's the problem. You need to design your code accordingly so it skips the operations on S if the P was destroyed by its parent, and that requires maintaining some sort of operational state info if you bail out from a blocking call on socket S. You simply don't have the info about that. This info has to be maintained in parent pool so that code doesn't touch the zombie memory still pointed by S (allocated by P), and that dramatically complicates the user code.
2) No APR function is defined to be async-signal-safe, calling apr_pool_destroy(P) from a signal handler is liable to crash and burn regardless of how you change the cleanup ordering.
Well, hitting CTRL+C shouldn't cause the core :) I probably wrongly explained the issue. Pool detachment from the parent is guarded by mutex (I'm here referring to the threaded usage), so pool can be destroyed asynchronously. Of course the client code must provide the needed synchronization, but even with that there is a problem with reverse execution order of the callbacks; childs are destroyed before or after the cleanup depending on the initiator. For sockets as an example with pool_destroy or cleanup case the socket is always hard closed (by invoking its pool cleanup callback) I still don't know how to solve that problem effectively, so any ideas are welcome. Regards -- ^(TM)