httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject Re: mutex in palloc
Date Wed, 10 Dec 1997 19:01:32 GMT
I don't agree with this.  I don't agree that two threads should be using
the same pool without doing their own protection from each other. The path
that's protected right now is the path which requires access to the shared
pool of free blocks (or malloc).

My reason:  speed.  If we have to take a mutex on every allocation then we
kill the most common server stuff, you'll note we do allocations left and
right all over the place.  There's no need in the existing server code for
this change either, we never have two threads using the same pool (if we
do, then that's the bug, not palloc). 

Here's an example where multiple threads can be used in a single request: 
mod_cgi can be rewritten to use three threads.  One thread to shuffle bits
from the client to the CGI (doing dechunking as necessary, and logging it
into the script log as necessary).  One thread to shuffle bits from the
CGI to the client (chunk, log, whatever).  And the third thread to shuffle
bits from the CGI's stderr to the error_log while prefixing the lines with
a useful token (i.e. timestamp and UNIQUE_ID).

It should be possible to arrange things such that three subpools are used
so that each thread still has private access to a pool.  You can ensure
that none of the pools are cleaned up until after all the threads have
completed -- so the threads can share data from their private pools (using
whatever synchronization they need or don't need). 

Can you think of an example where subpools can't be used in this way? 

Dean

On Wed, 10 Dec 1997, Ben Hyde wrote:

> Ben Laurie wrote:
> >Ben Hyde wrote:
> >> Ben Laurie wrote:
> >> >Ben Hyde wrote:
> >> >> Is the critical region in palloc so narrow
> >> >> because allocation in a given pool is never
> >> >> done by more than a single thread?
> >> >I haven't checked the code, but that seems like a rash assumption, if
> >> >true.
> >> 
> >> This untested, uncompiled rewrite illustrates my concern.
> >
> >Perhaps I need new glasses, but I can't actually see the difference
> >between the two...
> your glasses ok, my fingers not - ben h.
> 
> --- Before ---
> API_EXPORT(void *) palloc(struct pool *a, int reqsize)
> {
> #ifdef ALLOC_USE_MALLOC
> ...
> #else
> 
>     /* Round up requested size to an even number of alignment units (core clicks)
>      */
> 
>     int nclicks = 1 + ((reqsize - 1) / CLICK_SZ);
>     int size = nclicks * CLICK_SZ;
> 
>     /* First, see if we have space in the block most recently
>      * allocated to this pool
>      */
> 
>     union block_hdr *blok = a->last;
>     char *first_avail = blok->h.first_avail;
>     char *new_first_avail;
> 
>     if (reqsize <= 0)
> 	return NULL;
> 
>     new_first_avail = first_avail + size;
> 
>     if (new_first_avail <= blok->h.endp) {
> 	debug_verify_filled(first_avail, blok->h.endp,
> 	    "Ouch!  Someone trounced past the end of their allocation!\n");
> 	blok->h.first_avail = new_first_avail;
> 	return (void *) first_avail;
>     }
> 
>     /* Nope --- get a new one that's guaranteed to be big enough */
> 
>     block_alarms();
> 
>     (void) acquire_mutex(alloc_mutex);
> 
>     blok = new_block(size);
>     a->last->h.next = blok;
>     a->last = blok;
> 
>     (void) release_mutex(alloc_mutex);
> 
>     unblock_alarms();
> 
>     first_avail = blok->h.first_avail;
>     blok->h.first_avail += size;
> 
>     return (void *) first_avail;
> #endif
> }
> --- After ---
> API_EXPORT(void *) palloc(struct pool *a, int reqsize)
> {
> #ifdef ALLOC_USE_MALLOC
> ...
> #else
>     int nclicks = 1 + ((reqsize - 1) / CLICK_SZ);
>     int size = nclicks * CLICK_SZ; /* Alignable */
>     char *result;
> 
>     if (reqsize <= 0)
>       return NULL;
>     block_alarms();
>     (void)acquire_mutex(alloc_mutex);
>     {
>       union block_hdr *blok = a->last;
>       char *first_avail = blok->h.first_avail;
>       char *new_first_avail = first_avail + size;
> 
>       if (new_first_avail <= blok->h.endp) {
> 	debug_verify_filled(first_avail, blok->h.endp,
> 			    "Ouch!  Someone trounced past the end of their allocation!\n");
> 	blok->h.first_avail = new_first_avail;
> 	result = first_avail;
>       } else {
> 	blok = new_block(size);
> 	a->last->h.next = blok;
> 	a->last = blok;
> 	result = blok->h.first_avail;
> 	blok->h.first_avail += size;
>       }
>     }
>     (void)release_mutex(alloc_mutex);
>     unblock_alarms();
> 
>     return (void *)result;
> #endif
> }
> ---
> 


Mime
View raw message