You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by fa...@locus.apache.org on 2000/08/19 08:04:59 UTC

cvs commit: apache-2.0/src/main http_core.c http_protocol.c

fanf        00/08/18 23:04:58

  Modified:    src      CHANGES
               src/ap   Makefile.in ap_buckets.c ap_buckets_eos.c
                        ap_buckets_heap.c ap_buckets_mmap.c
               src/include ap_buckets.h
               src/main http_core.c http_protocol.c
  Added:       src/ap   ap_buckets_refcount.c
  Removed:     src/ap   ap_buckets_transient.c
  Log:
  Add generic support for reference-counting the resources used by
  buckets, and alter the HEAP and MMAP buckets to use it. Change
  the way buckets are initialised to support changing the type of
  buckets in place, and use it when setting aside TRANSIENT buckets.
  Change the implementation of TRANSIENT buckets so that it can be
  mostly shared with IMMORTAL buckets, which are now implemented.
  
  Reviewed by:	rbb
  
  Revision  Changes    Path
  1.207     +8 -0      apache-2.0/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/CHANGES,v
  retrieving revision 1.206
  retrieving revision 1.207
  diff -u -u -r1.206 -r1.207
  --- CHANGES	2000/08/19 05:55:26	1.206
  +++ CHANGES	2000/08/19 06:04:51	1.207
  @@ -1,5 +1,13 @@
   Changes with Apache 2.0a7
   
  +  *) Add generic support for reference-counting the resources used by
  +     buckets, and alter the HEAP and MMAP buckets to use it. Change
  +     the way buckets are initialised to support changing the type of
  +     buckets in place, and use it when setting aside TRANSIENT buckets.
  +     Change the implementation of TRANSIENT buckets so that it can be
  +     mostly shared with IMMORTAL buckets, which are now implemented.
  +     [Tony Finch]
  +
   Changes with Apache 2.0a6
   
     *) Add support to Apache and APR for dsos on OS/390.  [Greg Ames]
  
  
  
  1.6       +2 -2      apache-2.0/src/ap/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/ap/Makefile.in,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -u -r1.5 -r1.6
  --- Makefile.in	2000/08/12 18:45:25	1.5
  +++ Makefile.in	2000/08/19 06:04:51	1.6
  @@ -1,7 +1,7 @@
   
   LTLIBRARY_NAME    = libap.la
   LTLIBRARY_SOURCES = ap_cache.c ap_base64.c ap_sha1.c ap_hooks.c ap_buckets.c \
  -	ap_buckets_heap.c ap_buckets_transient.c ap_buckets_mmap.c \
  -	ap_buckets_eos.c
  +	ap_buckets_eos.c ap_buckets_simple.c ap_buckets_refcount.c \
  +	ap_buckets_heap.c ap_buckets_mmap.c
   
   include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.9       +4 -3      apache-2.0/src/ap/ap_buckets.c
  
  Index: ap_buckets.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/ap/ap_buckets.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -u -r1.8 -r1.9
  --- ap_buckets.c	2000/08/16 16:07:55	1.8
  +++ ap_buckets.c	2000/08/19 06:04:51	1.9
  @@ -176,7 +176,8 @@
               break;
           j = strlen(x);
          
  -        r = ap_bucket_heap_create(x, j, &i);
  +	/* XXX: copy or not? let the caller decide? */
  +        r = ap_bucket_create_heap(x, j, 1, &i);
           if (i != j) {
               /* Do we need better error reporting?  */
               return -1;
  @@ -202,7 +203,7 @@
   
   API_EXPORT(int) ap_brigade_vprintf(ap_bucket_brigade *b, const char *fmt, va_list va)
   {
  -    /* THIS IS A HACK.  This needs to be replaced with a function to printf
  +    /* XXX:  This needs to be replaced with a function to printf
        * directly into a bucket.  I'm being lazy right now.  RBB
        */
       char buf[4096];
  @@ -211,7 +212,7 @@
   
       res = apr_vsnprintf(buf, 4096, fmt, va);
   
  -    r = ap_bucket_heap_create(buf, strlen(buf), &i);
  +    r = ap_bucket_create_heap(buf, strlen(buf), 1, &i);
       ap_brigade_append_buckets(b, r);
   
       return res;
  
  
  
  1.5       +14 -13    apache-2.0/src/ap/ap_buckets_eos.c
  
  Index: ap_buckets_eos.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/ap/ap_buckets_eos.c,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -u -r1.4 -r1.5
  --- ap_buckets_eos.c	2000/08/16 16:07:55	1.4
  +++ ap_buckets_eos.c	2000/08/19 06:04:51	1.5
  @@ -56,7 +56,7 @@
   #include "ap_buckets.h"
   #include <stdlib.h>
   
  -static apr_status_t eos_get_str(ap_bucket *e, const char **str, 
  +static apr_status_t eos_read(ap_bucket *b, const char **str, 
                                   apr_ssize_t *len, int block)
   {
       *str = NULL;
  @@ -64,20 +64,21 @@
       return AP_END_OF_BRIGADE;
   }
   
  -API_EXPORT(ap_bucket *) ap_bucket_eos_create(void)
  +API_EXPORT(ap_bucket *) ap_bucket_make_eos(ap_bucket *b)
   {
  -    ap_bucket *newbuf;
  +    b->length    = AP_END_OF_BRIGADE;
   
  -    newbuf            = calloc(1, sizeof(*newbuf));
  -    newbuf->length    = AP_END_OF_BRIGADE;
  -
  -    newbuf->type      = AP_BUCKET_EOS;
  -    newbuf->read      = eos_get_str;
  -    newbuf->setaside  = NULL;
  -    newbuf->split     = NULL;
  -    newbuf->destroy   = NULL;
  -    newbuf->data      = NULL;
  +    b->type      = AP_BUCKET_EOS;
  +    b->read      = eos_read;
  +    b->setaside  = NULL;
  +    b->split     = NULL;
  +    b->destroy   = NULL;
  +    b->data      = NULL;
       
  -    return newbuf;
  +    return b;
   }
   
  +API_EXPORT(ap_bucket *) ap_bucket_create_eos(void)
  +{
  +    ap_bucket_do_create(ap_bucket_make_eos(b));
  +}
  
  
  
  1.8       +66 -108   apache-2.0/src/ap/ap_buckets_heap.c
  
  Index: ap_buckets_heap.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/ap/ap_buckets_heap.c,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -u -r1.7 -r1.8
  --- ap_buckets_heap.c	2000/08/16 16:07:55	1.7
  +++ ap_buckets_heap.c	2000/08/19 06:04:52	1.8
  @@ -56,132 +56,90 @@
   #include "ap_buckets.h"
   #include <stdlib.h>
   
  -#ifndef DEFAULT_RWBUF_SIZE
  -#define DEFAULT_RWBUF_SIZE (4096)
  +/*
  + * The size of heap bucket memory allocations.
  + * XXX: This is currently a guess and should be adjusted to an
  + * empirically good value.
  + */
  +#ifndef DEFAULT_BUCKET_SIZE
  +#define DEFAULT_BUCKET_SIZE (4096)
   #endif
  -
  -void ap_heap_setaside(ap_bucket *e);
   
  -static apr_status_t heap_get_str(ap_bucket *e, const char **str, 
  -                                 apr_ssize_t *len, int block)
  +static apr_status_t heap_read(ap_bucket *b, const char **str, 
  +			      apr_ssize_t *len, int block)
   {
  -    ap_bucket_heap *b = (ap_bucket_heap *)e->data;
  -    *str = b->start;
  -    *len = e->length;
  +    ap_bucket_shared *s = b->data;
  +    ap_bucket_heap *h = s->data;
  +
  +    *str = h->base + s->start;
  +    *len = s->end - s->start;
       return APR_SUCCESS;
   }
   
  -static void heap_destroy(ap_bucket *e)
  +static void heap_destroy(ap_bucket *b)
   {
  -    ap_bucket_heap *d = (ap_bucket_heap *)e->data;
  -    free(d->alloc_addr);
  +    ap_bucket_heap *h;
  +
  +    h = ap_bucket_destroy_shared(b);
  +    if (h == NULL) {
  +	return;
  +    }
  +    free(h->base);
  +    free(h);
   }
   
  -static apr_status_t heap_split(ap_bucket *e, apr_off_t nbyte)
  +API_EXPORT(ap_bucket *) ap_bucket_make_heap(ap_bucket *b,
  +		const char *buf, apr_size_t length, int copy, apr_ssize_t *w)
   {
  -    ap_bucket *newbuck;
  -    ap_bucket_heap *a = (ap_bucket_heap *)e;
  -    ap_bucket_heap *b;
  -    apr_ssize_t dump; 
  -
  -    newbuck = ap_bucket_heap_create(a->alloc_addr, a->alloc_len, &dump);
  -    b = (ap_bucket_heap *)newbuck->data;
  -
  -    b->alloc_addr = a->alloc_addr;
  -    b->alloc_len = a->alloc_len;
  -    b->end = a->end;
  -    a->end = a->start + nbyte;
  -    b->start = a->end + 1;
  -    newbuck->length = e->length - nbyte;
  -    e->length = nbyte;
  -
  -    newbuck->prev = e;
  -    newbuck->next = e->next;
  -    e->next = newbuck;
  +    ap_bucket_heap *h;
   
  -    return APR_SUCCESS;
  -}
  +    h = malloc(sizeof(*h));
  +    if (h == NULL) {
  +	return NULL;
  +    }
   
  -/*
  - * save nbyte bytes to the bucket.
  - * Only returns fewer than nbyte if an error occurred.
  - * Returns -1 if no bytes were written before the error occurred.
  - * It is worth noting that if an error occurs, the buffer is in an unknown
  - * state.
  - */
  -static apr_status_t heap_insert(ap_bucket *e, const char *buf,
  -                                apr_size_t nbyte, apr_ssize_t *w)
  -{
  -    int amt;
  -    int total;
  -    ap_bucket_heap *b = (ap_bucket_heap *)e->data;
  -
  -    if (nbyte == 0) {
  -        *w = 0;
  -        return APR_SUCCESS;
  +    if (copy) {
  +	h->base = malloc(DEFAULT_BUCKET_SIZE);
  +	if (h->base == NULL) {
  +	    free(h);
  +	    return NULL;
  +	}
  +	h->alloc_len = DEFAULT_BUCKET_SIZE;
  +	if (length > DEFAULT_BUCKET_SIZE) {
  +	    length = DEFAULT_BUCKET_SIZE;
  +	}
  +	memcpy(h->base, buf, length);
  +    }
  +    else {
  +	/* XXX: we lose the const qualifier here which indicates
  +         * there's something screwy with the API...
  +	 */
  +	h->base = (char *) buf;
  +	h->alloc_len = length;
       }
   
  -/*
  - * At this point, we need to make sure we aren't trying to write too much
  - * data to the bucket.  We will need to write to the dist here, but I am
  - * leaving that for a later pass.  The basics are presented below, but this
  - * is horribly broken.
  - */
  -    amt = b->alloc_len - (b->end - b->start);
  -    total = 0;
  -    if (nbyte > amt) {
  -        /* loop through and write to the disk */
  -        /* Replace the heap buckets with file buckets */
  +    b = ap_bucket_make_shared(b, h, 0, length);
  +    if (b == NULL) {
  +	if (copy) {
  +	    free(h->base);
  +	}
  +	free(h);
  +	return NULL;
       }
  -    /* now we know that nbyte < b->alloc_len */
  -    memcpy(b->end, buf, nbyte);
  -    b->end = b->end + nbyte;
  -    *w = total + nbyte;
  -    return APR_SUCCESS;
  -}
   
  -void ap_heap_setaside(ap_bucket *e)
  -{
  -    ap_bucket_transient *a = (ap_bucket_transient *)e;
  -    ap_bucket_heap *b = calloc(1, sizeof(*b));
  +    b->type     = AP_BUCKET_HEAP;
  +    b->split    = ap_bucket_split_shared;
  +    b->destroy  = heap_destroy;
  +    b->read     = heap_read;
  +    b->setaside = NULL;
  +
  +    *w = length;
   
  -    b->alloc_addr = calloc(DEFAULT_RWBUF_SIZE, 1);
  -    b->alloc_len  = DEFAULT_RWBUF_SIZE;
  -    memcpy(b->alloc_addr, a->start, e->length);
  -    b->start      = b->alloc_addr;
  -    b->end        = b->start + e->length;
  -
  -    e->type       = AP_BUCKET_HEAP;
  -    e->read       = heap_get_str;
  -    e->setaside   = NULL;
  -    e->split      = heap_split;
  -    e->destroy    = heap_destroy;
  +    return b;
   }
   
  -API_EXPORT(ap_bucket *) ap_bucket_heap_create(const char *buf,
  -                                apr_size_t nbyte, apr_ssize_t *w)
  +API_EXPORT(ap_bucket *) ap_bucket_create_heap(
  +		const char *buf, apr_size_t length, int copy, apr_ssize_t *w)
   {
  -    ap_bucket *newbuf;
  -    ap_bucket_heap *b;
  -
  -    newbuf = calloc(1, sizeof(*newbuf));
  -    b = malloc(sizeof(*b));
  -    
  -    b->alloc_addr = calloc(DEFAULT_RWBUF_SIZE, 1);
  -    b->alloc_len  = DEFAULT_RWBUF_SIZE;
  -    b->start      = b->alloc_addr;
  -    b->end        = b->alloc_addr;
  -
  -    newbuf->data       = b;
  -    heap_insert(newbuf, buf, nbyte, w); 
  -    newbuf->length     = b->end - b->start;
  -
  -    newbuf->type       = AP_BUCKET_HEAP;
  -    newbuf->read       = heap_get_str;
  -    newbuf->setaside   = NULL;
  -    newbuf->split      = heap_split;
  -    newbuf->destroy    = heap_destroy;
  -
  -    return newbuf;
  +    ap_bucket_do_create(ap_bucket_make_heap(b, buf, length, copy, w));
   }
  -
  
  
  
  1.6       +51 -57    apache-2.0/src/ap/ap_buckets_mmap.c
  
  Index: ap_buckets_mmap.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/ap/ap_buckets_mmap.c,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -u -r1.5 -r1.6
  --- ap_buckets_mmap.c	2000/08/16 16:07:55	1.5
  +++ ap_buckets_mmap.c	2000/08/19 06:04:52	1.6
  @@ -56,73 +56,67 @@
   #include "ap_buckets.h"
   #include <stdlib.h>
   
  -static apr_status_t mmap_get_str(ap_bucket *e, const char **str, 
  -                                 apr_ssize_t *length, int block)
  +static apr_status_t mmap_read(ap_bucket *b, const char **str, 
  +			      apr_ssize_t *length, int block)
   {
  -    ap_bucket_mmap *b = (ap_bucket_mmap *)e->data;
  -    *str = b->start;
  -    *length = e->length;
  +    ap_bucket_shared *s = b->data;
  +    ap_bucket_mmap *m = s->data;
  +    apr_status_t ok;
  +    void *addr;
  +    
  +    ok = apr_mmap_offset(&addr, m->mmap, s->start);
  +    if (ok != APR_SUCCESS) {
  +	return ok;
  +    }
  +    *str = addr;
  +    *length = s->end - s->start;
       return APR_SUCCESS;
   }
  -
  -static apr_status_t mmap_bucket_insert(ap_bucket *e, const apr_mmap_t *mm, 
  -                                      apr_size_t nbytes, apr_ssize_t *w)
  -{
  -    ap_bucket_mmap *b = (ap_bucket_mmap *)e->data;
   
  -    b->sub = calloc(1, sizeof(*b->sub));
  -    b->sub->mmap = mm;
  -    b->sub->refcount = 1;
  -
  -    b->start = mm->mm;
  -    b->end = (char *) mm->mm + nbytes;
  -    *w = nbytes;
  -    return APR_SUCCESS;
  -}
  -    
  -static apr_status_t mmap_split(ap_bucket *e, apr_off_t nbyte)
  +static void mmap_destroy(ap_bucket *b)
   {
  -    ap_bucket *newbuck;
  -    ap_bucket_mmap *a = (ap_bucket_mmap *)e->data;
  -    ap_bucket_mmap *b;
  -    apr_ssize_t dump;
  -
  -    newbuck = ap_bucket_mmap_create(a->sub->mmap, e->length, &dump);
  -    b = (ap_bucket_mmap *)newbuck->data;
  -    b->start = (char *) a->start + nbyte + 1;
  -    b->end = a->end;
  -    a->end = (char *) a->start + nbyte;
  -    newbuck->length = e->length - nbyte;
  -    e->length = nbyte;
  -
  -    newbuck->prev = e;
  -    newbuck->next = e->next;
  -    e->next = newbuck;
  +    ap_bucket_mmap *m;
   
  -    return APR_SUCCESS;
  +    m = ap_bucket_destroy_shared(b);
  +    if (m == NULL) {
  +	return;
  +    }
  +    apr_mmap_delete(m->mmap); /* hope this works! */
  +    free(m);
   }
   
  -API_EXPORT(ap_bucket *) ap_bucket_mmap_create(const apr_mmap_t *buf, 
  -                                      apr_size_t nbytes, apr_ssize_t *w)
  +/*
  + * XXX: are the start and length arguments useful?
  + */
  +API_EXPORT(ap_bucket *) ap_bucket_make_mmap(ap_bucket *b,
  +		apr_mmap_t *mm, apr_off_t start, apr_size_t length)
   {
  -    ap_bucket *newbuf;
  -    ap_bucket_mmap *b;
  -
  -    newbuf            = calloc(1, sizeof(*newbuf));
  -    b                 = malloc(sizeof(*b));
  +    ap_bucket_mmap *m;
   
  -    b->start = b->end = NULL;
  +    m = malloc(sizeof(*m));
  +    if (m == NULL) {
  +	return NULL;
  +    }
  +    m->mmap = mm;
  +
  +    b = ap_bucket_make_shared(b, m, start, start+length);
  +    if (b == NULL) {
  +	free(m);
  +	return NULL;
  +    }
  +
  +    b->type     = AP_BUCKET_MMAP;
  +    b->split    = ap_bucket_split_shared;
  +    b->destroy  = mmap_destroy;
  +    b->read     = mmap_read;
  +    b->setaside = NULL;
   
  -    newbuf->data      = b;
  -    mmap_bucket_insert(newbuf, buf, nbytes, w);
  -    newbuf->length    = *w;
  -
  -    newbuf->type      = AP_BUCKET_MMAP;
  -    newbuf->read      = mmap_get_str;
  -    newbuf->setaside  = NULL;
  -    newbuf->split     = mmap_split;
  -    newbuf->destroy   = NULL;
  -    
  -    return newbuf;
  +    return b;
   }
   
  +
  +API_EXPORT(ap_bucket *) ap_bucket_create_mmap(
  +		apr_mmap_t *mm, apr_off_t start, apr_size_t length)
  +{
  +    ap_bucket_do_create(ap_bucket_make_mmap(b, mm, start, length));
  +}
  
  
  
  1.1                  apache-2.0/src/ap/ap_buckets_refcount.c
  
  Index: ap_buckets_refcount.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include <stdlib.h>
  
  #include "apr_errno.h"
  
  #include "ap_buckets.h"
  
  API_EXPORT(apr_status_t) ap_bucket_split_shared(ap_bucket *a, apr_off_t point)
  {
      ap_bucket *b;
      ap_bucket_shared *ad, *bd;
      ap_bucket_refcount *r;
  
      if (point <= 0 || point >= a->length) {
  	return APR_EINVAL;
      }
  
      b = malloc(sizeof(*b)); 
      if (b == NULL) {
  	return APR_ENOMEM;
      }
      bd = malloc(sizeof(*bd));
      if (bd == NULL) {
  	free(b);
  	return APR_ENOMEM;
      }
      *b = *a;
      ad = a->data;
      b->data = bd;
      *bd = *ad;
  
      r = ad->data;
      r->refcount += 1;
  
      a->length = point;
      ad->end = ad->start + point;
      b->length -= point;
      bd->start += point;
  
      if (a->next) {
  	a->next->prev = b;
      }
      b->next = a->next;
      b->prev = a;
      a->next = b;
  
      return APR_SUCCESS;
  }
  
  API_EXPORT(void *) ap_bucket_destroy_shared(ap_bucket *b)
  {
      ap_bucket_shared *s = b->data;
      ap_bucket_refcount *r = s->data;
  
      free(s);
      r->refcount -= 1;
      if (r->refcount == 0) {
  	return r;
      }
      else {
  	return NULL;
      }
  }
  
  API_EXPORT(ap_bucket *) ap_bucket_make_shared(ap_bucket *b, void *data,
  					      apr_off_t start, apr_off_t end)
  {
      ap_bucket_shared *s;
      ap_bucket_refcount *r = data;
  
      s = malloc(sizeof(*s));
      if (s == NULL) {
  	return NULL;
      }
  
      b->data = s;
      b->length = end - start;
      /* caller initializes the type field and function pointers */
      s->start = start;
      s->end = end;
      s->data = r;
      r->refcount = 1;
      /* caller initializes the rest of r */
  
      return b;
  }
  
  
  
  1.12      +209 -92   apache-2.0/src/include/ap_buckets.h
  
  Index: ap_buckets.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/ap_buckets.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -u -r1.11 -r1.12
  --- ap_buckets.h	2000/08/15 06:58:31	1.11
  +++ ap_buckets.h	2000/08/19 06:04:54	1.12
  @@ -75,35 +75,25 @@
   
   /* The basic concept behind bucket brigades.....
    *
  - * A bucket brigade is simply a doubly linked list of buckets, where
  + * A bucket brigade is simply a doubly linked list of buckets, so
    * we aren't limited to inserting at the front and removing at the
    * end.
    *
    * Buckets are just data stores.  They can be files, mmap areas, or just
    * pre-allocated memory.  The point of buckets is to store data.  Along with
    * that data, come some functions to access it.  The functions are relatively
  - * simple, read, write, getlen, split, and free.
  + * simple, read, split, setaside, and destroy.
    *
    * read reads a string of data.  Currently, it assumes we read all of the 
    * data in the bucket.  This should be changed to only read the specified 
    * amount.
    *
  - * getlen gets the number of bytes stored in the bucket.
  - * 
  - * write writes the specified data to the bucket.  Depending on the type of
  - * bucket, this may append to the end of previous data, or wipe out the data
  - * currently in the bucket.  heap buckets append currently, all others 
  - * erase the current bucket.
  + * split makes one bucket into two at the specified location.
    *
  - * split just makes one bucket into two at the specified location.  To implement
  - * this correctly, we really need to implement reference counting.
  + * setaside ensures that the data in the bucket has a long enough lifetime.
    *
  - * free just destroys the data associated with the bucket.
  + * free destroys the data associated with the bucket.
    *
  - * We may add more functions later.  There has been talk of needing a stat,
  - * which would probably replace the getlen.  And, we definately need a convert
  - * function.  Convert would make one bucket type into another bucket type.
  - *
    * To write a bucket brigade, they are first made into an iovec, so that we
    * don't write too little data at one time.  Currently we ignore compacting the
    * buckets into as few buckets as possible, but if we really want good
  @@ -175,7 +165,8 @@
        * @param b The bucket to read from
        * @param str A place to store the data read.  Allocation should only be
        *            done if absolutely necessary. 
  -     * @param len The amount of data read.
  +     * @param len The amount of data read,
  +     *            or -1 (AP_END_OF_BRIGADE) if there is no more data
        * @param block Should this read function block if there is more data that
        *              cannot be read immediately.
        * @deffunc apr_status_t read(ap_bucket *b, const char **str, apr_ssize_t *len, int block)
  @@ -186,16 +177,16 @@
        *  a no-op; buckets containing data that dies when the stack is un-wound
        *  must convert the bucket into a heap bucket.
        * @param e The bucket to convert
  -     * @deffunc void setaside(ap_bucket *e)
  +     * @deffunc apr_status_t setaside(ap_bucket *e)
        */
  -    void (*setaside)(ap_bucket *e);
  +    apr_status_t (*setaside)(ap_bucket *e);
   
       /** Split one bucket in two at the specified position
        * @param e The bucket to split
  -     * @param nbytes The offset at which to split the bucket
  -     * @deffunc apr_status_t split(ap_bucket *e, apr_off_t nbytes)
  +     * @param point The offset of the first byte in the new bucket
  +     * @deffunc apr_status_t split(ap_bucket *e, apr_off_t point)
        */
  -    apr_status_t (*split)(ap_bucket *e, apr_off_t nbytes);
  +    apr_status_t (*split)(ap_bucket *e, apr_off_t point);
   };
   
   /** A list of buckets */
  @@ -212,69 +203,103 @@
       ap_bucket *tail;
   };
   
  -/*    ******  Different bucket types   *****/
  +/**
  + * General-purpose reference counting for the varous bucket types.
  + *
  + * Any bucket type that keeps track of the resources it uses (i.e.
  + * most of them except for IMMORTAL, TRANSIENT, and EOS) needs to
  + * attach a reference count to the resource so that it can be freed
  + * when the last bucket that uses it goes away. Resource-sharing may
  + * occur because of bucket splits or buckets that refer to globally
  + * cached data.
  + */
   
  -typedef struct ap_bucket_transient ap_bucket_transient;
  +/**
  + * The structure used to manage the shared resource must start with an
  + * ap_bucket_refcount which is updated by the general-purpose refcount
  + * code. A pointer to the bucket-type-dependent private data structure
  + * can be cast to a pointer to an ap_bucket_refcount and vice versa.
  + */
  +typedef struct ap_bucket_refcount ap_bucket_refcount;
  +struct ap_bucket_refcount {
  +    int          refcount;
  +};
   
   /**
  - * A bucket containing data on the stack that will be destroyed as the
  - * stack is unwound.
  + * The data pointer of a refcounted bucket points to an
  + * ap_bucket_shared structure which describes the region of the shared
  + * object that this bucket refers to. The ap_bucket_shared isn't a
  + * fully-fledged bucket type: it is a utility type that proper bucket
  + * types are based on.
  + */
  +typedef struct ap_bucket_shared ap_bucket_shared;
  +struct ap_bucket_shared {
  +    /** start of the data in the bucket relative to the private base pointer */
  +    apr_off_t start;
  +    /** end of the data in the bucket relative to the private base pointer */
  +    apr_off_t end;
  +    /** pointer to the real private data of the bucket,
  +     * which starts with an ap_bucket_refcount */
  +    void *data;
  +};
  +
  +
  +/*  *****  Non-reference-counted bucket types  *****  */
  +
  +
  +typedef struct ap_bucket_simple ap_bucket_simple;
  +
  +/**
  + * TRANSIENT and IMMORTAL buckets don't have much to do with looking
  + * after the memory that they refer to so they share a lot of their
  + * implementation.
    */
  -struct ap_bucket_transient {
  +struct ap_bucket_simple {
       /** The start of the data in the bucket */
       const char    *start;
       /** The end of the data in the bucket */
       const char    *end;
   };
   
  +
  +/*  *****  Reference-counted bucket types  *****  */
  +
  +
   typedef struct ap_bucket_heap ap_bucket_heap;
   
   /**
  - * A bucket containing data allocated off the heap.
  + * A bucket referring to data allocated off the heap.
    */
   struct ap_bucket_heap {
  +    /** Number of buckets using this memory */
  +    ap_bucket_refcount  refcount;
       /** The start of the data actually allocated.  This should never be
        * modified, it is only used to free the bucket.
        */
  -    char    *alloc_addr;
  +    char    *base;
       /** how much memory was allocated.  This may not be necessary */
       size_t  alloc_len;
  -    /** Where does the data the bucket is actually referencing start */
  -    char    *start;
  -    /** Where does the data the bucket cares about end */               
  -    char    *end;
   };
   
   typedef struct ap_bucket_mmap ap_bucket_mmap;
  -typedef struct ap_mmap_sub_bucket ap_mmap_sub_bucket;
   
   /**
  - * The sub mmap bucket.  This is the meat of the reference count implementation
  - * mmaps aren't actually un-mapped until the ref count is zero.
  + * A bucket referring to an mmap()ed file
    */
  -struct ap_mmap_sub_bucket {
  +struct ap_bucket_mmap {
  +    /** Number of buckets using this memory */
  +    ap_bucket_refcount  refcount;
       /** The mmap this sub_bucket refers to */
  -    const apr_mmap_t *mmap;
  -    /** The current reference count for this sub_bucket */
  -    int refcount;
  +    apr_mmap_t *mmap;
   };
   
  -/** A bucket representing an mmap object */
  -struct ap_bucket_mmap {
  -    /** Where does this buckets section of the mmap start */
  -    char      *start;
  -    /** Where does this buckets section of the mmap end */
  -    char      *end;
  -    /** The mmap sub_bucket referenced by this bucket */
  -    ap_mmap_sub_bucket *sub;  /* The mmap and ref count */    
  -};
   
  -/*   ******  Bucket Brigade Functions  *****  */
  +/*  *****  Bucket Brigade Functions  *****  */
   
   /**
    * Create a new bucket brigade.  The bucket brigade is originally empty.
    * @param The pool to associate with the brigade.  Data is not allocated out
  - *        of the pool, but a cleanup is registered.
  +q *        of the pool, but a cleanup is registered.
    * @return The empty bucket brigade
    * @deffunc ap_bucket_brigade *ap_brigade_create(apr_pool_t *p)
    */
  @@ -290,7 +315,7 @@
   
   /**
    * append bucket(s) to a bucket_brigade.  This is the correct way to add
  - * buckets to the end of a bucket brigades bucket list.  This will accept
  + * buckets to the end of a bucket briagdes bucket list.  This will accept
    * a list of buckets of any length.
    * @param b The bucket brigade to append to
    * @param e The bucket list to append
  @@ -365,8 +390,9 @@
    */
   API_EXPORT(int) ap_brigade_vprintf(ap_bucket_brigade *b, const char *fmt, va_list va);
   
  -/*   ******  Bucket Functions  *****  */
   
  +/*  *****  Bucket Functions  *****  */
  +
   /**
    * free the resources used by a bucket. If multiple buckets refer to
    * the same resource it is freed when the last one goes away.
  @@ -374,63 +400,154 @@
    * @deffunc apr_status_t ap_bucket_destroy(ap_bucket *e)
    */
   API_EXPORT(apr_status_t) ap_bucket_destroy(ap_bucket *e);
  +
  +
  +/*  *****  Shared reference-counted buckets  *****  */
   
  -/****** Functions to Create Buckets of varying type ******/
  +/**
  + * Initialize a bucket containing reference-counted data that may be
  + * shared. The caller must allocate the bucket if necessary and
  + * initialize its type-dependent fields, and allocate and initialize
  + * its own private data structure. This function should only be called
  + * by type-specific bucket creation functions.
  + * @param b The bucket to initialize,
  + *          or NULL if a new one should be allocated
  + * @param data A pointer to the private data structure
  + *             with the reference count at the start
  + * @param start The start of the data in the bucket
  + *              relative to the private base pointer
  + * @param end The end of the data in the bucket
  + *            relative to the private base pointer
  + * @return The new bucket, or NULL if allocation failed
  + * @deffunc API_EXPORT(ap_bucket *) ap_bucket_shared_create(ap_bucket_refcount *r, apr_off_t start, apr_off_t end) */
  +API_EXPORT(ap_bucket *) ap_bucket_make_shared(ap_bucket *b, void *data,
  +					      apr_off_t start, apr_off_t end);
  +
  +/**
  + * Decrement the refcount of the data in the bucket and free the
  + * ap_bucket_shared structure. This function should only be called by
  + * type-specific bucket destruction functions.
  + * @param b The bucket to be destroyed
  + * @return NULL if nothing needs to be done,
  + *         otherwise a pointer to the private data structure which
  + *         must be destroyed because its reference count is zero
  + * @deffunc API_EXPORT(void *) ap_bucket_shared_destroy(ap_bucket *b) */
  +API_EXPORT(void *) ap_bucket_destroy_shared(ap_bucket *b);
  +
  +/**
  + * Split a bucket into two at the given point, and adjust the refcount
  + * to the underlying data. Most reference-counting bucket types will
  + * be able to use this function as their split function without any
  + * additional type-specific handling.
  + * @param b The bucket to be split
  + * @param point The offset of the first byte in the new bucket
  + * @return APR_EINVAL if the point is not within the bucket;
  + *         APR_ENOMEM if allocation failed;
  + *         or APR_SUCCESS
  + * @deffunc API_EXPORT(apr_status_t) ap_bucket_shared_split(ap_bucket *b, apr_off_t point)
  + */
  +API_EXPORT(apr_status_t) ap_bucket_split_shared(ap_bucket *b, apr_off_t point);
  +
  +
  +/*  *****  Functions to Create Buckets of varying type  *****  */
  +
  +/**
  + * Each bucket type foo has two initialization functions:
  + * ap_bucket_make_foo which sets up some already-allocated memory as a
  + * bucket of type foo; and ap_bucket_create_foo which allocates memory
  + * for the bucket, calls ap_bucket_make_foo, and initializes the
  + * bucket's list pointers. The ap_bucket_make_foo functions are used
  + * inside the bucket code to change the type of buckets in place;
  + * other code should call ap_bucket_create_foo. All the initialization
  + * functions change nothing if they fail.
  + */
   
   /*
  - * All of these functions are responsibly for creating a bucket and filling
  - * it out with an initial value.  Some buckets can be over-written, others
  - * can't.  What should happen is that buckets that can't be over-written,
  - * will have NULL write functions.  That is currently broken, although it is
  - * easy to fix.  The creation routines may not allocate the space for the
  - * buckets, because we may be using a free list.  Regardless, creation
  - * routines are responsible for getting space for a bucket from someplace
  - * and inserting the initial data.
  + * This macro implements the guts of ap_bucket_create_foo
    */
  +#define ap_bucket_do_create(do_make)		\
  +    do {					\
  +	ap_bucket *b, *ap__b;			\
  +	b = calloc(1, sizeof(*b));		\
  +	if (b == NULL) {			\
  +	    return NULL;			\
  +	}					\
  +	ap__b = do_make;			\
  +	if (ap__b == NULL) {			\
  +	    free(b);				\
  +	    return NULL;			\
  +	}					\
  +	ap__b->next = NULL;			\
  +	ap__b->prev = NULL;			\
  +	return ap__b;				\
  +    } while(0)
   
  +
   /**
  - * Create a bucket referring to memory on the heap. This always
  - * allocates 4K of memory, so that the bucket can grow without
  - * requiring another allocation.
  - * @param buf The buffer to insert into the bucket
  - * @param nbyte The size of the buffer to insert.
  - * @param w The number of bytes actually inserted into the bucket
  - * @return The new bucket
  - * @deffunc ap_bucket *ap_bucket_heap_create(const char *buf, apr_size_t nbyte, apr_ssize_t *w)
  + * Create an End of Stream bucket.  This indicates that there is no more data
  + * coming from down the filter stack
  + * @return The new bucket, or NULL if allocation failed
  + * @deffunc ap_bucket *ap_bucket_create_eos(void)
    */
  -API_EXPORT(ap_bucket *) ap_bucket_heap_create(const char *buf,
  -                                apr_size_t nbyte, apr_ssize_t *w);
  +API_EXPORT(ap_bucket *) ap_bucket_create_eos(void);
  +API_EXPORT(ap_bucket *) ap_bucket_make_eos(ap_bucket *b);
   
   
   /**
  - * Create a mmap memory bucket, and initialize the ref count to 1
  - * @param buf The mmap to insert into the bucket
  - * @param nbyte The size of the mmap to insert.
  - * @param w The number of bytes actually inserted into the bucket
  - * @return The new bucket
  - * @deffunc ap_bucket *ap_bucket_mmap_create(const apr_mmap_t *buf, apr_size_t nbyte, apr_ssize_t *w)
  + * Create a bucket referring to long-lived data.
  + * @param buf The data to insert into the bucket
  + * @param nbyte The size of the data to insert.
  + * @return The new bucket, or NULL if allocation failed
  + * @deffunc ap_bucket *ap_bucket_create_transient(const char *buf, apr_size_t nbyte, apr_ssize_t *w)
    */
  -API_EXPORT(ap_bucket *) ap_bucket_mmap_create(const apr_mmap_t *buf,
  -                                      apr_size_t nbytes, apr_ssize_t *w);
  +API_EXPORT(ap_bucket *) ap_bucket_create_immortal(
  +		const char *buf, apr_size_t nbyte);
  +API_EXPORT(ap_bucket *) ap_bucket_make_immortal(ap_bucket *b,
  +		const char *buf, apr_size_t nbyte);
   
   /**
  - * Create a transient memory bucket.
  + * Create a bucket referring to data on the stack.
    * @param buf The data to insert into the bucket
    * @param nbyte The size of the data to insert.
  - * @param w The number of bytes actually inserted into the bucket
  - * @return The new bucket
  - * @deffunc ap_bucket *ap_bucket_transient_create(const char *buf, apr_size_t nbyte, apr_ssize_t *w)
  + * @return The new bucket, or NULL if allocation failed
  + * @deffunc ap_bucket *ap_bucket_create_transient(const char *buf, apr_size_t nbyte, apr_ssize_t *w)
    */
  -API_EXPORT(ap_bucket *) ap_bucket_transient_create(const char *buf,
  -                               apr_size_t nbyte, apr_ssize_t *w);
  +API_EXPORT(ap_bucket *) ap_bucket_create_transient(
  +		const char *buf, apr_size_t nbyte);
  +API_EXPORT(ap_bucket *) ap_bucket_make_transient(ap_bucket *b,
  +		const char *buf, apr_size_t nbyte);
   
   /**
  - * Create an End of Stream bucket.  This indicates that there is no more data
  - * coming from down the filter stack
  - * @return The new bucket
  - * @deffunc ap_bucket *ap_bucket_eos_create(void)
  - */
  -API_EXPORT(ap_bucket *) ap_bucket_eos_create(void);
  + * Create a bucket referring to memory on the heap. If the caller asks
  + * for the data to be copied, this function always allocates 4K of
  + * memory so that more data can be added to the bucket without
  + * requiring another allocation. Therefore not all the data may be put
  + * into the bucket. If copying is not requested then the bucket takes
  + * over responsibility for free()ing the memory.
  + * @param buf The buffer to insert into the bucket
  + * @param nbyte The size of the buffer to insert.
  + * @param copy Whether to copy the data into newly-allocated memory or not
  + * @param w The number of bytes actually copied into the bucket
  + * @return The new bucket, or NULL if allocation failed
  + * @deffunc ap_bucket *ap_bucket_create_heap(const char *buf, apr_size_t nbyte, apr_ssize_t *w)
  + */
  +API_EXPORT(ap_bucket *) ap_bucket_create_heap(
  +		const char *buf, apr_size_t nbyte, int copy, apr_ssize_t *w);
  +API_EXPORT(ap_bucket *) ap_bucket_make_heap(ap_bucket *b,
  +		const char *buf, apr_size_t nbyte, int copy, apr_ssize_t *w);
  +
  +/**
  + * Create a bucket referring to mmap()ed memory.
  + * @param mmap The mmap to insert into the bucket
  + * @param start The offset of the first byte in the mmap
  + *              that this bucket refers to
  + * @param length The number of bytes referred to by this bucket
  + * @return The new bucket, or NULL if allocation failed
  + * @deffunc ap_bucket *ap_bucket_create_mmap(const apr_mmap_t *buf, apr_size_t nbyte, apr_ssize_t *w)
  + */
  +API_EXPORT(ap_bucket *) ap_bucket_create_mmap(
  +		apr_mmap_t *mm, apr_off_t start, apr_size_t length);
  +API_EXPORT(ap_bucket *) ap_bucket_make_mmap(ap_bucket *b,
  +		apr_mmap_t *mm, apr_off_t start, apr_size_t length);
   
   #endif
  -
  
  
  
  1.105     +3 -4      apache-2.0/src/main/http_core.c
  
  Index: http_core.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
  retrieving revision 1.104
  retrieving revision 1.105
  diff -u -u -r1.104 -r1.105
  --- http_core.c	2000/08/18 04:46:07	1.104
  +++ http_core.c	2000/08/19 06:04:57	1.105
  @@ -2923,7 +2923,6 @@
   {
       ap_bucket *dptr = b->head;
       int len = 0;
  -    int tempint = 0;
       char lenstr[6];
       int hit_eos = 0;
   
  @@ -2938,11 +2937,11 @@
       }
   
       apr_snprintf(lenstr, 6, "%x\r\n", len);
  -    dptr = ap_bucket_transient_create(lenstr, strlen(lenstr), &tempint);
  +    dptr = ap_bucket_create_transient(lenstr, strlen(lenstr));
       b->head->prev = dptr;
       dptr->next = b->head;
       b->head = dptr;
  -    dptr = ap_bucket_transient_create("\r\n", 2, &tempint);
  +    dptr = ap_bucket_create_transient("\r\n", 2);
       if (hit_eos) {
           b->tail->prev->next = dptr;
           dptr->prev = b->tail->prev;
  @@ -2954,7 +2953,7 @@
       }
   
       if (hit_eos && len != 0) {
  -        dptr = ap_bucket_transient_create("0\r\n\r\n", 5, &tempint);
  +        dptr = ap_bucket_create_transient("0\r\n\r\n", 5);
           b->tail->prev->next = dptr;
           dptr->prev = b->tail->prev;
           b->tail->prev = dptr;
  
  
  
  1.113     +10 -14    apache-2.0/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
  retrieving revision 1.112
  retrieving revision 1.113
  diff -u -u -r1.112 -r1.113
  --- http_protocol.c	2000/08/18 18:48:11	1.112
  +++ http_protocol.c	2000/08/19 06:04:57	1.113
  @@ -1330,7 +1330,7 @@
       ap_bucket_brigade *bb;
   
       bb = ap_brigade_create(r->pool);
  -    ap_brigade_append_buckets(bb, ap_bucket_eos_create());
  +    ap_brigade_append_buckets(bb, ap_bucket_create_eos());
       ap_pass_brigade(r->filters, bb);
   }
   
  @@ -2521,8 +2521,7 @@
        * until after the commit to actually write the code.
        */
       bb = ap_brigade_create(r->pool);
  -    ap_brigade_append_buckets(bb, 
  -                              ap_bucket_mmap_create(mm, mm->size, &bytes_sent));
  +    ap_brigade_append_buckets(bb, ap_bucket_create_mmap(mm, 0, mm->size));
       bytes_sent = ap_pass_brigade(r->filters, bb);
   
       return bytes_sent;
  @@ -2532,15 +2531,13 @@
   API_EXPORT(int) ap_rputc(int c, request_rec *r)
   {
       ap_bucket_brigade *bb = NULL;
  -    apr_ssize_t written;
       char c2 = (char)c;
   
       if (r->connection->aborted)
           return EOF;
   
       bb = ap_brigade_create(r->pool);
  -    ap_brigade_append_buckets(bb,
  -                              ap_bucket_transient_create(&c2, 1, &written)); 
  +    ap_brigade_append_buckets(bb, ap_bucket_create_transient(&c2, 1)); 
       ap_pass_brigade(r->filters, bb);
   
       return c;
  @@ -2549,25 +2546,24 @@
   API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
   {
       ap_bucket_brigade *bb = NULL;
  -    apr_ssize_t written;
  +    apr_size_t len;
   
       if (r->connection->aborted)
           return EOF;
       if (*str == '\0')
           return 0;
  -    
  +
  +    len = strlen(str);
       bb = ap_brigade_create(r->pool);
  -    ap_brigade_append_buckets(bb, 
  -                           ap_bucket_transient_create(str, strlen(str), &written)); 
  +    ap_brigade_append_buckets(bb, ap_bucket_create_transient(str, len));
       ap_pass_brigade(r->filters, bb);
   
  -    return written;
  +    return len;
   }
   
   API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
   {
       ap_bucket_brigade *bb = NULL;
  -    apr_ssize_t written;
   
       if (r->connection->aborted)
           return EOF;
  @@ -2575,9 +2571,9 @@
           return 0;
   
       bb = ap_brigade_create(r->pool);
  -    ap_brigade_append_buckets(bb, ap_bucket_transient_create(buf, nbyte, &written)); 
  +    ap_brigade_append_buckets(bb, ap_bucket_create_transient(buf, nbyte)); 
       ap_pass_brigade(r->filters, bb);
  -    return written;
  +    return nbyte;
   }
   
   API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)