On 4 June 2014 21:02, Kandarian, Richard M <richard.kandar...@lanl.gov> wrote: > Reading MP_TRACE messages I noticed that for every modperl_interp_select() > call during a request there were two modperl_interp_unselect() calls, one > bracketing the _select() call and one from the registered cleanup when the > pool was destroyed. The attached patch stopped those crashes. I would call my > fix VERY tentative for various reasons including my noobiness and I've added > comments near the active ingredient in modperl_interp.c. Inactive ingredients > include diffs in the patch which are my adding trace info. >
Apologies for the long delay in following up on this. Where was the crash that you were seeing (the one which your patch stops from happening)? The patch makes modperl_interp_unselect() return early when the interp in question is already not "in use", but that in itself won't stop a crash from occurring -- there is no harm in turning off the "in use" flag again when it is already off. Was it one of the other lines further down modperl_interp_unselect() that crashed, or something somewhere else? As for returning early if refcnt is <= 0, I added an assertion that refcnt is > 0, and didn't see it triggered... Having said that I also didn't see the existing assertion that MpInterpIN_USE(interp) is true get triggered either, but I did see some trace messages about the interp not being in use, so maybe MP_ASSERT() isn't working as I expected. (It is a debug build I'm using.) And regarding setting refcnt to 0, that doesn't seem quite right, but certainly decrementing it sounds to me like it should be done to match the increment which is done in modperl_interp_pool_select() and modperl_interp_select(). The end of the latter adds an extra refcnt for the registered cleanup, so certainly something needs to be called to decrement the refcnt twice -- we shouldn't return from modperl_interp_unselect() so early that the refcnt decrement gets skipped. I haven't seen the crash that you were experiencing, which makes it difficult to test things out. All the tests pass (using SVN trunk with httpd-2.4.9 and perl-5.21.0) except for the four failures documented in the README. I tried adding a decrement of refcnt to cover the case where it doesn't already return early due to refcnt being > 1. This decrement used to happen, but got removed by r1562772 and I'm not sure if that was intentional. Tests still pass with this change: Index: src/modules/perl/modperl_interp.c =================================================================== --- src/modules/perl/modperl_interp.c (revision 1635423) +++ src/modules/perl/modperl_interp.c (working copy) @@ -273,7 +273,7 @@ modperl_interp_t *interp = (modperl_interp_t *)data; modperl_interp_pool_t *mip = interp->mip; - MP_ASSERT(interp && MpInterpIN_USE(interp)); + MP_ASSERT(interp && MpInterpIN_USE(interp) && interp->refcnt > 0); MP_TRACE_i(MP_FUNC, "unselect(interp=%pp): refcnt=%d", interp, interp->refcnt); @@ -285,6 +285,7 @@ } MpInterpIN_USE_Off(interp); + --interp->refcnt; modperl_thx_interp_set(interp->perl, NULL); #ifdef MP_DEBUG I also tried going further, along the lines of your own patch, but again making sure that the refcnt decrement still happens even in the case of both early returns: Index: src/modules/perl/modperl_interp.c =================================================================== --- src/modules/perl/modperl_interp.c (revision 1635423) +++ src/modules/perl/modperl_interp.c (working copy) @@ -273,17 +273,24 @@ modperl_interp_t *interp = (modperl_interp_t *)data; modperl_interp_pool_t *mip = interp->mip; - MP_ASSERT(interp && MpInterpIN_USE(interp)); + MP_ASSERT(interp && MpInterpIN_USE(interp) && interp->refcnt > 0); MP_TRACE_i(MP_FUNC, "unselect(interp=%pp): refcnt=%d", interp, interp->refcnt); - if (interp->refcnt > 1) { - --interp->refcnt; + --interp->refcnt; + + if (interp->refcnt > 0) { MP_TRACE_i(MP_FUNC, "interp=0x%lx, refcnt=%d -- interp still in use", (unsigned long)interp, interp->refcnt); return APR_SUCCESS; } + if (!MpInterpIN_USE(interp)){ + MP_TRACE_i(MP_FUNC, "interp=0x%lx, refcnt=%d -- interp not in use, alre ady unselected?", + (unsigned long)interp, interp->refcnt); + return APR_SUCCESS; + } + MpInterpIN_USE_Off(interp); modperl_thx_interp_set(interp->perl, NULL); @@ -301,6 +308,9 @@ interp, mip->tipool->size, mip->tipool->in_use); } + MP_TRACE_i(MP_FUNC, "interp=0x%lx, refcnt=%d -- interp now unselected", + (unsigned long)interp, interp->refcnt); + return APR_SUCCESS; } Tests still pass, but I'm shooting in the dark without knowing where the crash was. It does seem to me like the refcnt decrement needs doing, though. Does that change alone (i.e. the first of my diffs above) fix your crash, or do you still need the early return too (i.e. the second of my diffs above)? I will ask Jan Kaluza about the refcnt business since he authored the change I cited above which dropped the refcnt decrement in the case where refcnt is 1.