Assuming that fixing it with code would mean adding a lock around
that block in apr_palloc, I submit that fixing it with documentation
is the better option.  Given how much slower the threaded MPM is
than the prefork one right now, I think that adding more mutex overhead
would be bad. :-(
--Brian

[EMAIL PROTECTED] wrote:

This is correct.  Most of the locking in pools was based on the fact that
Apache doesn't have this type of problem.  We can either fix the problem
with code or docs, but it does need to be fixed.

Ryan

On Wed, 27 Jun 2001, Brian Pane wrote:

Yes, there's definitely a race condition there.  I noticed that
too, and I thought it was intentional (i.e., that the lack of a
lock was a conscious choice to avoid a performance penalty
for apps in which pools aren't shared across threads) and
harmless (because there aren't any pools in Apache shared
by multiple threads that can do apr_palloc).  But if the
non-thread-safety is intentional, there probably should be
a prominent warning about it in the include file and documentation.

--Brian

Sander Striker wrote:

[...]

In the current apr_palloc, the lock is only around the call to new_block.
I think that's reasonable; new_block is manipulating a global
free list, so it has to be mutex-protected.

This triggered me to investigate the pools code again. It seems to me that
there is a possible race condition when two threads share the same pool.
Examine the following piece of code that is not protected by a lock:

  ...
  new_first_avail = first_avail + size;

  if (new_first_avail <= blok->h.endp) {
      debug_verify_filled(first_avail, blok->h.endp,
                          "[apr_palloc] Ouch!  Someone trounced past the
end "
                          "of their allocation!\n");
      blok->h.first_avail = new_first_avail;
      return (void *) first_avail;
  }
  ...

Now in a situation with 2 threads that call apr_palloc at the same time
(both requesting a size that fits the last block):

   A                                       B
T1   new_first_avail = first_avail + size;
T2                                           new_first_avail = first_avail +
size;

Now, the test will succeed in both A and B, effectively returning the same
memory twice:

   if (new_first_avail <= blok->h.endp) {
       blok->h.first_avail = new_first_avail;
       return (void *) first_avail;
   }

Or am I missing something?


Sander







_____________________________________________________________________________
Ryan Bloom                              [EMAIL PROTECTED]
Covalent Technologies                   [EMAIL PROTECTED]
-----------------------------------------------------------------------------







Reply via email to