home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Web / Servers / apache-1.2.4-MIHS / original-source / src / alloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-26  |  27.4 KB  |  1,134 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1997 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission.
  24.  *
  25.  * 5. Redistributions of any form whatsoever must retain the following
  26.  *    acknowledgment:
  27.  *    "This product includes software developed by the Apache Group
  28.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  31.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  34.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  41.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  * ====================================================================
  43.  *
  44.  * This software consists of voluntary contributions made by many
  45.  * individuals on behalf of the Apache Group and was originally based
  46.  * on public domain software written at the National Center for
  47.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  48.  * For more information on the Apache Group and the Apache HTTP server
  49.  * project, please see <http://www.apache.org/>.
  50.  *
  51.  */
  52.  
  53.  
  54. /*
  55.  * Resource allocation code... the code here is responsible for making
  56.  * sure that nothing leaks.
  57.  *
  58.  * rst --- 4/95 --- 6/95
  59.  */
  60.  
  61. #include "httpd.h"
  62.  
  63. #include <stdarg.h>
  64.  
  65. /*****************************************************************
  66.  *
  67.  * Managing free storage blocks...
  68.  */
  69.  
  70. union align
  71. {
  72.   /* Types which are likely to have the longest RELEVANT alignment
  73.    * restrictions...
  74.    */
  75.   
  76.   char *cp;
  77.   void (*f)();
  78.   long l;
  79.   FILE *fp;
  80.   double d;
  81. };
  82.  
  83. #define CLICK_SZ (sizeof(union align))
  84.  
  85. union block_hdr
  86. {
  87.   union align a;
  88.   
  89.   /* Actual header... */
  90.   
  91.   struct {
  92.     char *endp;
  93.     union block_hdr *next;
  94.     char *first_avail;
  95.   } h;
  96. };
  97.  
  98. union block_hdr *block_freelist = NULL;
  99.  
  100.  
  101.  
  102. /* Get a completely new block from the system pool. Note that we rely on
  103. malloc() to provide aligned memory. */
  104.  
  105. union block_hdr *malloc_block (int size)
  106. {
  107.   union block_hdr *blok =
  108.     (union block_hdr *)malloc(size + sizeof(union block_hdr));
  109.  
  110.   if (blok == NULL) {
  111.       fprintf (stderr, "Ouch!  malloc failed in malloc_block()\n");
  112.       exit (1);
  113.   }
  114.   blok->h.next = NULL;
  115.   blok->h.first_avail = (char *)(blok + 1);
  116.   blok->h.endp = size + blok->h.first_avail;
  117.   
  118.   return blok;
  119. }
  120.  
  121.  
  122.  
  123. void chk_on_blk_list (union block_hdr *blok, union block_hdr *free_blk)
  124. {
  125.   /* Debugging code.  Left in for the moment. */
  126.     
  127.   while (free_blk) {
  128.     if (free_blk == blok) {
  129.       fprintf (stderr, "Ouch!  Freeing free block\n");
  130.       exit (1);
  131.     }
  132.     free_blk = free_blk->h.next;
  133.   }
  134. }
  135.  
  136. /* Free a chain of blocks --- must be called with alarms blocked. */
  137.  
  138. void free_blocks (union block_hdr *blok)
  139. {
  140.   /* First, put new blocks at the head of the free list ---
  141.    * we'll eventually bash the 'next' pointer of the last block
  142.    * in the chain to point to the free blocks we already had.
  143.    */
  144.   
  145.   union block_hdr *old_free_list = block_freelist;
  146.  
  147.   if (blok == NULL) return;    /* Sanity check --- freeing empty pool? */
  148.   
  149.   block_freelist = blok;
  150.   
  151.   /*
  152.    * Next, adjust first_avail pointers of each block --- have to do it
  153.    * sooner or later, and it simplifies the search in new_block to do it
  154.    * now.
  155.    */
  156.  
  157.   while (blok->h.next != NULL) {
  158.     chk_on_blk_list (blok, old_free_list);
  159.     blok->h.first_avail = (char *)(blok + 1);
  160.     blok = blok->h.next;
  161.   }
  162.  
  163.   chk_on_blk_list (blok, old_free_list);
  164.   blok->h.first_avail = (char *)(blok + 1);
  165.  
  166.   /* Finally, reset next pointer to get the old free blocks back */
  167.  
  168.   blok->h.next = old_free_list;
  169. }
  170.  
  171.  
  172.  
  173.  
  174. /* Get a new block, from our own free list if possible, from the system
  175.  * if necessary.  Must be called with alarms blocked.
  176.  */
  177.  
  178. union block_hdr *new_block (int min_size)
  179. {
  180.   union block_hdr **lastptr = &block_freelist;
  181.   union block_hdr *blok = block_freelist;
  182.   
  183.   /* First, see if we have anything of the required size
  184.    * on the free list...
  185.    */
  186.  
  187.   while (blok != NULL) {
  188.     if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) {
  189.       *lastptr = blok->h.next;
  190.       blok->h.next = NULL;
  191.       return blok;
  192.     }
  193.     else {
  194.       lastptr = &blok->h.next;
  195.       blok = blok->h.next;
  196.     }
  197.   }
  198.  
  199.   /* Nope. */
  200.  
  201.   min_size += BLOCK_MINFREE;
  202.   return malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC);
  203. }
  204.  
  205.  
  206.  
  207. /* Accounting */
  208.  
  209. long bytes_in_block_list (union block_hdr *blok)
  210. {
  211.   long size = 0;
  212.  
  213.   while (blok) {
  214.     size += blok->h.endp - (char *)(blok + 1);
  215.     blok = blok->h.next;
  216.   }
  217.  
  218.   return size;
  219. }
  220.  
  221.  
  222. /*****************************************************************
  223.  *
  224.  * Pool internals and management...
  225.  * NB that subprocesses are not handled by the generic cleanup code,
  226.  * basically because we don't want cleanups for multiple subprocesses
  227.  * to result in multiple three-second pauses.
  228.  */
  229.  
  230. struct process_chain;
  231. struct cleanup;
  232.  
  233. static void run_cleanups (struct cleanup *);
  234. static void free_proc_chain (struct process_chain *);
  235.  
  236. struct pool {
  237.   union block_hdr *first;
  238.   union block_hdr *last;
  239.   struct cleanup *cleanups;
  240.   struct process_chain *subprocesses;
  241.   struct pool *sub_pools;
  242.   struct pool *sub_next;
  243.   struct pool *sub_prev;
  244.   struct pool *parent;
  245.   char *free_first_avail;
  246. };
  247.  
  248. pool *permanent_pool;
  249.  
  250. /* Each pool structure is allocated in the start of its own first block,
  251.  * so we need to know how many bytes that is (once properly aligned...).
  252.  * This also means that when a pool's sub-pool is destroyed, the storage
  253.  * associated with it is *completely* gone, so we have to make sure it
  254.  * gets taken off the parent's sub-pool list...
  255.  */
  256.  
  257. #define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ))
  258. #define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ)             
  259.  
  260. struct pool *make_sub_pool (struct pool *p)
  261. {
  262.   union block_hdr *blok;
  263.   pool *new_pool;
  264.  
  265.   block_alarms();
  266.   
  267.   blok = new_block (0);
  268.   new_pool = (pool *)blok->h.first_avail;
  269.   blok->h.first_avail += POOL_HDR_BYTES;
  270.  
  271.   memset ((char *)new_pool, '\0', sizeof (struct pool));
  272.   new_pool->free_first_avail = blok->h.first_avail;
  273.   new_pool->first = new_pool->last = blok;
  274.     
  275.   if (p) {
  276.     new_pool->parent = p;
  277.     new_pool->sub_next = p->sub_pools;
  278.     if (new_pool->sub_next) new_pool->sub_next->sub_prev = new_pool;
  279.     p->sub_pools = new_pool;
  280.   }
  281.   
  282.   unblock_alarms();
  283.   
  284.   return new_pool;
  285. }
  286.  
  287. void init_alloc() { permanent_pool = make_sub_pool (NULL); }
  288.  
  289. void clear_pool (struct pool *a)
  290. {
  291.   block_alarms();
  292.   
  293.   while (a->sub_pools)
  294.     destroy_pool (a->sub_pools);
  295.     
  296.   a->sub_pools = NULL;
  297.   
  298.   run_cleanups (a->cleanups);        a->cleanups = NULL;
  299.   free_proc_chain (a->subprocesses); a->subprocesses = NULL;
  300.   free_blocks (a->first->h.next);    a->first->h.next = NULL;
  301.  
  302.   a->last = a->first;
  303.   a->first->h.first_avail = a->free_first_avail;
  304.  
  305.   unblock_alarms();
  306. }
  307.  
  308. void destroy_pool (pool *a)
  309. {
  310.   block_alarms();
  311.   clear_pool (a);
  312.  
  313.   if (a->parent) {
  314.     if (a->parent->sub_pools == a) a->parent->sub_pools = a->sub_next;
  315.     if (a->sub_prev) a->sub_prev->sub_next = a->sub_next;
  316.     if (a->sub_next) a->sub_next->sub_prev = a->sub_prev;
  317.   }
  318.   
  319.   free_blocks (a->first);
  320.   unblock_alarms();
  321. }
  322.  
  323. long bytes_in_pool (pool *p) { return bytes_in_block_list (p->first); }
  324. long bytes_in_free_blocks () { return bytes_in_block_list (block_freelist); }
  325.  
  326. /*****************************************************************
  327.  *
  328.  * Allocating stuff...
  329.  */
  330.  
  331.  
  332. void *palloc (struct pool *a, int reqsize)
  333. {
  334.   /* Round up requested size to an even number of alignment units (core clicks)
  335.    */
  336.   
  337.   int nclicks = 1 + ((reqsize - 1) / CLICK_SZ);
  338.   int size = nclicks * CLICK_SZ;
  339.  
  340.   /* First, see if we have space in the block most recently
  341.    * allocated to this pool
  342.    */
  343.   
  344.   union block_hdr *blok = a->last; 
  345.   char *first_avail = blok->h.first_avail;
  346.   char *new_first_avail;
  347.  
  348.   if(reqsize <= 0)
  349.       return NULL;
  350.   
  351.   new_first_avail = first_avail + size;
  352.   
  353.   if (new_first_avail <= blok->h.endp) {
  354.     blok->h.first_avail = new_first_avail;
  355.     return (void *)first_avail;
  356.   }
  357.  
  358.   /* Nope --- get a new one that's guaranteed to be big enough */
  359.   
  360.   block_alarms();
  361.   blok = new_block (size);
  362.   a->last->h.next = blok;
  363.   a->last = blok;
  364.   unblock_alarms();
  365.  
  366.   first_avail = blok->h.first_avail;
  367.   blok->h.first_avail += size;
  368.  
  369.   return (void *)first_avail;
  370. }
  371.  
  372. void *pcalloc(struct pool *a, int size)
  373. {
  374.   void *res = palloc (a, size);
  375.   memset (res, '\0', size);
  376.   return res;
  377. }
  378.  
  379. char *pstrdup(struct pool *a, const char *s)
  380. {
  381.   char *res;
  382.   if (s == NULL) return NULL;
  383.   res = palloc (a, strlen(s) + 1);
  384.   strcpy (res, s);
  385.   return res;
  386. }
  387.  
  388. char *pstrndup(struct pool *a, const char *s, int n)
  389. {
  390.   char *res;
  391.   if (s == NULL) return NULL;
  392.   res = palloc (a, n + 1);
  393.   strncpy (res, s, n);
  394.   res[n] = '\0';
  395.   return res;
  396. }
  397.  
  398. char *pstrcat(pool *a, ...)
  399. {
  400.   char *cp, *argp, *res;
  401.   
  402.   /* Pass one --- find length of required string */
  403.   
  404.   int len = 0;
  405.   va_list adummy;
  406.   
  407.   va_start (adummy, a);
  408.  
  409.   while ((cp = va_arg (adummy, char *)) != NULL) 
  410.     len += strlen(cp);
  411.  
  412.   va_end (adummy);
  413.  
  414.   /* Allocate the required string */
  415.  
  416.   res = (char *)palloc(a, len + 1);
  417.   cp = res;
  418.  
  419.   /* Pass two --- copy the argument strings into the result space */
  420.  
  421.   va_start (adummy, a);
  422.   
  423.   while ((argp = va_arg (adummy, char *)) != NULL) {
  424.     strcpy (cp, argp);
  425.     cp += strlen(argp);
  426.   }
  427.  
  428.   va_end (adummy);
  429.  
  430.   /* Return the result string */
  431.  
  432.   return res;
  433. }
  434.  
  435.  
  436. /*****************************************************************
  437.  *
  438.  * The 'array' functions...
  439.  */
  440.  
  441. array_header *make_array (pool *p, int nelts, int elt_size)
  442. {
  443.   array_header *res = (array_header *)palloc(p, sizeof(array_header));
  444.  
  445.   if (nelts < 1) nelts = 1;    /* Assure sanity if someone asks for
  446.                  * array of zero elts.
  447.                  */
  448.   
  449.   res->elts = pcalloc (p, nelts * elt_size);
  450.   
  451.   res->pool = p;
  452.   res->elt_size = elt_size;
  453.   res->nelts = 0;        /* No active elements yet... */
  454.   res->nalloc = nelts;        /* ...but this many allocated */
  455.  
  456.   return res;
  457. }
  458.  
  459. void *push_array (array_header *arr)
  460. {
  461.   if (arr->nelts == arr->nalloc) {
  462.     int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2;
  463.     char *new_data;
  464.     
  465.     new_data = pcalloc (arr->pool, arr->elt_size * new_size);
  466.  
  467.     memcpy (new_data, arr->elts, arr->nalloc * arr->elt_size);
  468.     arr->elts = new_data;
  469.     arr->nalloc = new_size;
  470.   }
  471.  
  472.   ++arr->nelts;
  473.   return arr->elts + (arr->elt_size * (arr->nelts - 1));
  474. }
  475.  
  476. void array_cat (array_header *dst, const array_header *src)
  477. {
  478.   int elt_size = dst->elt_size;
  479.   
  480.   if (dst->nelts + src->nelts > dst->nalloc) {
  481.     int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2;
  482.     char *new_data;
  483.  
  484.     while (dst->nelts + src->nelts > new_size)
  485.       new_size *= 2;
  486.  
  487.     new_data = pcalloc (dst->pool, elt_size * new_size);
  488.     memcpy (new_data, dst->elts, dst->nalloc * elt_size);
  489.     
  490.     dst->elts = new_data;
  491.     dst->nalloc = new_size;
  492.   }
  493.  
  494.   memcpy (dst->elts + dst->nelts * elt_size, src->elts, elt_size * src->nelts);
  495.   dst->nelts += src->nelts;
  496. }
  497.  
  498. array_header *copy_array (pool *p, const array_header *arr)
  499. {
  500.   array_header *res = make_array (p, arr->nalloc, arr->elt_size);
  501.  
  502.   memcpy (res->elts, arr->elts, arr->elt_size * arr->nelts);
  503.   res->nelts = arr->nelts;
  504.   return res;
  505. }
  506.  
  507. /* This cute function copies the array header *only*, but arranges
  508.  * for the data section to be copied on the first push or arraycat.
  509.  * It's useful when the elements of the array being copied are
  510.  * read only, but new stuff *might* get added on the end; we have the
  511.  * overhead of the full copy only where it is really needed.
  512.  */
  513.  
  514. array_header *copy_array_hdr (pool *p, const array_header *arr)
  515. {
  516.   array_header *res = (array_header *)palloc(p, sizeof(array_header));
  517.  
  518.   res->elts = arr->elts;
  519.   
  520.   res->pool = p;
  521.   res->elt_size = arr->elt_size;
  522.   res->nelts = arr->nelts;
  523.   res->nalloc = arr->nelts;    /* Force overflow on push */
  524.  
  525.   return res;
  526. }
  527.  
  528. /* The above is used here to avoid consing multiple new array bodies... */
  529.  
  530. array_header *append_arrays (pool *p,
  531.                  const array_header *first,
  532.                  const array_header *second)
  533. {
  534.   array_header *res = copy_array_hdr (p, first);
  535.  
  536.   array_cat (res, second);
  537.   return res;
  538. }
  539.  
  540.  
  541. /*****************************************************************
  542.  *
  543.  * The "table" functions.
  544.  */
  545.  
  546. table *make_table (pool *p, int nelts) {
  547.     return make_array (p, nelts, sizeof (table_entry));
  548. }
  549.  
  550. table *copy_table (pool *p, const table *t) {
  551.     return copy_array (p, t);
  552. }
  553.  
  554. void clear_table (table *t)
  555. {
  556.     t->nelts = 0;
  557. }
  558.  
  559. array_header *table_elts (table *t) { return t; }
  560.  
  561. char *table_get (const table *t, const char *key)
  562. {
  563.     table_entry *elts = (table_entry *)t->elts;
  564.     int i;
  565.  
  566.     if (key == NULL) return NULL;
  567.     
  568.     for (i = 0; i < t->nelts; ++i)
  569.         if (!strcasecmp (elts[i].key, key))
  570.         return elts[i].val;
  571.  
  572.     return NULL;
  573. }
  574.  
  575. void table_set (table *t, const char *key, const char *val)
  576. {
  577.     register int i, j, k;
  578.     table_entry *elts = (table_entry *)t->elts;
  579.     int done = 0;
  580.  
  581.     for (i = 0; i < t->nelts; ++i)
  582.     if (!strcasecmp (elts[i].key, key)) {
  583.         if (!done) {
  584.             elts[i].val = pstrdup(t->pool, val);
  585.             done = 1;
  586.         }
  587.         else {     /* delete an extraneous element */
  588.                 for (j = i, k = i + 1; k < t->nelts; ++j, ++k) {
  589.                     elts[j].key = elts[k].key;
  590.                     elts[j].val = elts[k].val;
  591.                 }
  592.                 --t->nelts;
  593.         }
  594.     }
  595.  
  596.     if (!done) {
  597.         elts = (table_entry *)push_array(t);
  598.         elts->key = pstrdup (t->pool, key);
  599.         elts->val = pstrdup (t->pool, val);
  600.     }
  601. }
  602.  
  603. void table_unset( table *t, const char *key ) 
  604. {
  605.     register int i, j, k;   
  606.     table_entry *elts = (table_entry *)t->elts;
  607.  
  608.     for (i = 0; i < t->nelts; ++i)
  609.         if (!strcasecmp (elts[i].key, key)) {
  610.  
  611.             /* found an element to skip over
  612.              * there are any number of ways to remove an element from
  613.              * a contiguous block of memory.  I've chosen one that
  614.              * doesn't do a memcpy/bcopy/array_delete, *shrug*...
  615.              */
  616.             for (j = i, k = i + 1; k < t->nelts; ++j, ++k) {
  617.                 elts[j].key = elts[k].key;
  618.                 elts[j].val = elts[k].val;
  619.             }
  620.             --t->nelts;
  621.         }
  622. }     
  623.  
  624. void table_merge (table *t, const char *key, const char *val)
  625. {
  626.     table_entry *elts = (table_entry *)t->elts;
  627.     int i;
  628.  
  629.     for (i = 0; i < t->nelts; ++i)
  630.         if (!strcasecmp (elts[i].key, key)) {
  631.         elts[i].val = pstrcat (t->pool, elts[i].val, ", ", val, NULL);
  632.         return;
  633.     }
  634.  
  635.     elts = (table_entry *)push_array(t);
  636.     elts->key = pstrdup (t->pool, key);
  637.     elts->val = pstrdup (t->pool, val);
  638. }
  639.  
  640. void table_add (table *t, const char *key, const char *val)
  641. {
  642.     table_entry *elts = (table_entry *)t->elts;
  643.  
  644.     elts = (table_entry *)push_array(t);
  645.     elts->key = pstrdup (t->pool, key);
  646.     elts->val = pstrdup (t->pool, val);
  647. }
  648.  
  649. table* overlay_tables (pool *p, const table *overlay, const table *base)
  650. {
  651.     return append_arrays (p, overlay, base);
  652. }
  653.  
  654. /* And now for something completely abstract ...
  655.  *
  656.  * For each key value given as a vararg:
  657.  *   run the function pointed to as
  658.  *     int comp(void *r, char *key, char *value);
  659.  *   on each valid key-value pair in the table t that matches the vararg key,
  660.  *   or once for every valid key-value pair if the vararg list is empty,
  661.  *   until the function returns false (0) or we finish the table.
  662.  *
  663.  * Note that we restart the traversal for each vararg, which means that
  664.  * duplicate varargs will result in multiple executions of the function
  665.  * for each matching key.  Note also that if the vararg list is empty,
  666.  * only one traversal will be made and will cut short if comp returns 0.
  667.  *
  668.  * Note that the table_get and table_merge functions assume that each key in
  669.  * the table is unique (i.e., no multiple entries with the same key).  This
  670.  * function does not make that assumption, since it (unfortunately) isn't
  671.  * true for some of Apache's tables.
  672.  *
  673.  * Note that rec is simply passed-on to the comp function, so that the
  674.  * caller can pass additional info for the task.
  675.  */
  676. void table_do (int (*comp)(void *, const char *, const char *), void *rec,
  677.                const table *t, ...)
  678. {
  679.     va_list vp;
  680.     char *argp;
  681.     table_entry *elts = (table_entry *)t->elts;
  682.     int rv, i;
  683.   
  684.     va_start(vp, t);
  685.  
  686.     argp = va_arg(vp, char *);
  687.  
  688.     do {
  689.         for (rv = 1, i = 0; rv && (i < t->nelts); ++i) {
  690.             if (elts[i].key && (!argp || !strcasecmp(elts[i].key, argp))) {
  691.                 rv = (*comp)(rec, elts[i].key, elts[i].val);
  692.             }
  693.         }
  694.     } while (argp && ((argp = va_arg(vp, char *)) != NULL));
  695.  
  696.     va_end(vp);
  697. }
  698.  
  699. /*****************************************************************
  700.  *
  701.  * Managing generic cleanups.  
  702.  */
  703.  
  704. struct cleanup {
  705.   void *data;
  706.   void (*plain_cleanup)(void *);
  707.   void (*child_cleanup)(void *);
  708.   struct cleanup *next;
  709. };
  710.  
  711. void register_cleanup (pool *p, void *data, void (*plain_cleanup)(void *),
  712.                void (*child_cleanup)(void *))
  713. {
  714.   struct cleanup *c = (struct cleanup *)palloc(p, sizeof (struct cleanup));
  715.   c->data = data;
  716.   c->plain_cleanup = plain_cleanup;
  717.   c->child_cleanup = child_cleanup;
  718.   c->next = p->cleanups;
  719.   p->cleanups = c;
  720. }
  721.  
  722. void kill_cleanup (pool *p, void *data, void (*cleanup)(void *))
  723. {
  724.   struct cleanup *c = p->cleanups;
  725.   struct cleanup **lastp = &p->cleanups;
  726.     
  727.   while (c) {
  728.     if (c->data == data && c->plain_cleanup == cleanup) {
  729.       *lastp = c->next;
  730.       break;
  731.     }
  732.  
  733.     lastp = &c->next;
  734.     c = c->next;
  735.   }
  736. }
  737.  
  738. void run_cleanup (pool *p, void *data, void (*cleanup)(void *))
  739. {
  740.   block_alarms();        /* Run cleanup only once! */
  741.   (*cleanup)(data);
  742.   kill_cleanup (p, data, cleanup);
  743.   unblock_alarms();
  744. }
  745.  
  746. static void run_cleanups (struct cleanup *c)
  747. {
  748.   while (c) {
  749.     (*c->plain_cleanup)(c->data);
  750.     c = c->next;
  751.   }
  752. }
  753.  
  754. static void run_child_cleanups (struct cleanup *c)
  755. {
  756.   while (c) {
  757.     (*c->child_cleanup)(c->data);
  758.     c = c->next;
  759.   }
  760. }
  761.  
  762. static void cleanup_pool_for_exec (pool *p)
  763. {
  764.   run_child_cleanups (p->cleanups);
  765.   p->cleanups = NULL;
  766.  
  767.   for (p = p->sub_pools; p; p = p->sub_next)
  768.     cleanup_pool_for_exec (p);
  769. }
  770.  
  771. void cleanup_for_exec()
  772. {
  773.   block_alarms();
  774.   cleanup_pool_for_exec (permanent_pool);
  775.   unblock_alarms();
  776. }
  777.  
  778. /*****************************************************************
  779.  *
  780.  * Files and file descriptors; these are just an application of the
  781.  * generic cleanup interface.
  782.  */
  783.  
  784. static void fd_cleanup (void *fdv) { close ((int)fdv); }
  785.  
  786. void note_cleanups_for_fd (pool *p, int fd) {
  787.   register_cleanup (p, (void *)fd, fd_cleanup, fd_cleanup);
  788. }
  789.  
  790. void kill_cleanups_for_fd(pool *p,int fd)
  791.     {
  792.     kill_cleanup(p,(void *)fd,fd_cleanup);
  793.     }
  794.  
  795. int popenf(pool *a, const char *name, int flg, int mode)
  796. {
  797.   int fd;
  798.   int save_errno;
  799.  
  800.   block_alarms();
  801.   fd = open(name, flg, mode);
  802.   save_errno = errno;
  803.   if (fd >= 0) {
  804.     fd = ap_slack (fd, AP_SLACK_HIGH);
  805.     note_cleanups_for_fd (a, fd);
  806.   }
  807.   unblock_alarms();
  808.   errno = save_errno;
  809.   return fd;
  810. }
  811.  
  812. int pclosef(pool *a, int fd)
  813. {
  814.   int res;
  815.   int save_errno;
  816.   
  817.   block_alarms();
  818.   res = close(fd);
  819.   save_errno = errno;
  820.   kill_cleanup(a, (void *)fd, fd_cleanup);
  821.   unblock_alarms();
  822.   errno = save_errno;
  823.   return res;
  824. }
  825.  
  826. /* Note that we have separate plain_ and child_ cleanups for FILE *s,
  827.  * since fclose() would flush I/O buffers, which is extremely undesirable;
  828.  * we just close the descriptor.
  829.  */
  830.  
  831. static void file_cleanup (void *fpv) { fclose ((FILE *)fpv); }
  832. static void file_child_cleanup (void *fpv) { close (fileno ((FILE *)fpv)); }
  833.  
  834. void note_cleanups_for_file (pool *p, FILE *fp) {
  835.   register_cleanup (p, (void *)fp, file_cleanup, file_child_cleanup);
  836. }
  837.  
  838. FILE *pfopen(pool *a, const char *name, const char *mode)
  839. {
  840.   FILE *fd = NULL;
  841.   int baseFlag, desc;
  842.  
  843.   block_alarms();
  844.  
  845.   if (*mode == 'a') {
  846.     /* Work around faulty implementations of fopen */
  847.     baseFlag = (*(mode+1) == '+') ? O_RDWR : O_WRONLY;
  848.     desc = open(name, baseFlag | O_APPEND | O_CREAT,
  849.         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  850.     if (desc >= 0) {
  851.       desc = ap_slack(desc, AP_SLACK_LOW);
  852.       fd = fdopen(desc, mode);
  853.     }
  854.   } else {
  855.     fd = fopen(name, mode);
  856.   }
  857.  
  858.   if (fd != NULL) note_cleanups_for_file (a, fd);
  859.   unblock_alarms();
  860.   return fd;
  861. }
  862.  
  863. FILE *pfdopen(pool *a,int fd, const char *mode)
  864. {
  865.   FILE *f;
  866.  
  867.   block_alarms();
  868.   f=fdopen(fd,mode);
  869.   if(f != NULL)
  870.     note_cleanups_for_file(a,f);
  871.   unblock_alarms();
  872.   return f;
  873. }
  874.  
  875.  
  876. int pfclose(pool *a, FILE *fd)
  877. {
  878.   int res;
  879.   
  880.   block_alarms();
  881.   res = fclose(fd);
  882.   kill_cleanup(a, (void *)fd, file_cleanup);
  883.   unblock_alarms();
  884.   return res;
  885. }
  886.  
  887. /*
  888.  * Here's a pool-based interface to POSIX regex's regcomp().
  889.  * Note that we return regex_t instead of being passed one.
  890.  * The reason is that if you use an already-used regex_t structure,
  891.  * the memory that you've already allocated gets forgotten, and
  892.  * regfree() doesn't clear it. So we don't allow it.
  893.  */
  894.  
  895. static void regex_cleanup (void *preg) { regfree ((regex_t *)preg); }
  896.  
  897. regex_t *pregcomp(pool *p, const char *pattern, int cflags) {
  898.     regex_t *preg = palloc(p, sizeof(regex_t));
  899.  
  900.     if (regcomp(preg, pattern, cflags))
  901.     return NULL;
  902.  
  903.     register_cleanup (p, (void *)preg, regex_cleanup, regex_cleanup);
  904.  
  905.     return preg;
  906. }
  907.  
  908.  
  909. void pregfree(pool *p, regex_t *reg)
  910. {
  911.     block_alarms();
  912.     regfree (reg);
  913.     kill_cleanup (p, (void *)reg, regex_cleanup);
  914.     unblock_alarms();
  915. }
  916.  
  917. /*****************************************************************
  918.  *
  919.  * More grotty system stuff... subprocesses.  Frump.  These don't use
  920.  * the generic cleanup interface because I don't want multiple
  921.  * subprocesses to result in multiple three-second pauses; the
  922.  * subprocesses have to be "freed" all at once.  If someone comes
  923.  * along with another resource they want to allocate which has the
  924.  * same property, we might want to fold support for that into the
  925.  * generic interface, but for now, it's a special case
  926.  */
  927.  
  928. struct process_chain {
  929.   pid_t pid;
  930.   enum kill_conditions kill_how;
  931.   struct process_chain *next;
  932. };
  933.  
  934. void note_subprocess (pool *a, int pid, enum kill_conditions how)
  935. {
  936.   struct process_chain *new =
  937.     (struct process_chain *)palloc(a, sizeof(struct process_chain));
  938.  
  939.   new->pid = pid;
  940.   new->kill_how = how;
  941.   new->next = a->subprocesses;
  942.   a->subprocesses = new;
  943. }
  944.  
  945. int spawn_child_err (pool *p, void (*func)(void *), void *data,
  946.              enum kill_conditions kill_how,
  947.              FILE **pipe_in, FILE **pipe_out, FILE **pipe_err)
  948. {
  949.   int pid;
  950.   int in_fds[2];
  951.   int out_fds[2];
  952.   int err_fds[2];
  953.   int save_errno;
  954.  
  955.   block_alarms();
  956.   
  957.   if (pipe_in && pipe (in_fds) < 0)
  958.   {
  959.       save_errno = errno;
  960.       unblock_alarms();
  961.       errno = save_errno;
  962.       return 0;
  963.   }
  964.   
  965.   if (pipe_out && pipe (out_fds) < 0) {
  966.     save_errno = errno;
  967.     if (pipe_in) {
  968.       close (in_fds[0]); close (in_fds[1]);
  969.     }
  970.     unblock_alarms();
  971.     errno = save_errno;
  972.     return 0;
  973.   }
  974.  
  975.   if (pipe_err && pipe (err_fds) < 0) {
  976.     save_errno = errno;
  977.     if (pipe_in) {
  978.       close (in_fds[0]); close (in_fds[1]);
  979.     }
  980.     if (pipe_out) {
  981.       close (out_fds[0]); close (out_fds[1]);
  982.     }
  983.     unblock_alarms();
  984.     errno = save_errno;
  985.     return 0;
  986.   }
  987.  
  988.   if ((pid = fork()) < 0) {
  989.     save_errno = errno;
  990.     if (pipe_in) {
  991.       close (in_fds[0]); close (in_fds[1]);
  992.     }
  993.     if (pipe_out) {
  994.       close (out_fds[0]); close (out_fds[1]);
  995.     }
  996.     if (pipe_err) {
  997.       close (err_fds[0]); close (err_fds[1]);
  998.     }
  999.     unblock_alarms();
  1000.     errno = save_errno;
  1001.     return 0;
  1002.   }
  1003.  
  1004.   if (!pid) {
  1005.     /* Child process */
  1006.     
  1007.     if (pipe_out) {
  1008.       close (out_fds[0]);
  1009.       dup2 (out_fds[1], STDOUT_FILENO);
  1010.       close (out_fds[1]);
  1011.     }
  1012.  
  1013.     if (pipe_in) {
  1014.       close (in_fds[1]);
  1015.       dup2 (in_fds[0], STDIN_FILENO);
  1016.       close (in_fds[0]);
  1017.     }
  1018.  
  1019.     if (pipe_err) {
  1020.       close (err_fds[0]);
  1021.       dup2 (err_fds[1], STDERR_FILENO);
  1022.       close (err_fds[1]);
  1023.     }
  1024.  
  1025.     /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */
  1026.     signal (SIGCHLD, SIG_DFL);    /* Was that it? */
  1027.     
  1028.     func (data);
  1029.     exit (0);            /* Should never get here... */
  1030.   }
  1031.  
  1032.   /* Parent process */
  1033.  
  1034.   note_subprocess (p, pid, kill_how);
  1035.   
  1036.   if (pipe_out) {
  1037.     close (out_fds[1]);
  1038. #ifdef __EMX__
  1039.     /* Need binary mode set for OS/2. */
  1040.     *pipe_out = fdopen (out_fds[0], "rb");
  1041. #else
  1042.     *pipe_out = fdopen (out_fds[0], "r");
  1043. #endif  
  1044.   
  1045.     if (*pipe_out) note_cleanups_for_file (p, *pipe_out);
  1046.   }
  1047.  
  1048.   if (pipe_in) {
  1049.     close (in_fds[0]);
  1050. #ifdef __EMX__
  1051.     /* Need binary mode set for OS/2 */
  1052.     *pipe_in = fdopen (in_fds[1], "wb");
  1053. #else
  1054.     *pipe_in = fdopen (in_fds[1], "w");
  1055. #endif
  1056.     
  1057.     if (*pipe_in) note_cleanups_for_file (p, *pipe_in);
  1058.   }
  1059.  
  1060.   if (pipe_err) {
  1061.     close (err_fds[1]);
  1062. #ifdef __EMX__
  1063.     /* Need binary mode set for OS/2. */
  1064.     *pipe_err = fdopen (err_fds[0], "rb");
  1065. #else
  1066.     *pipe_err = fdopen (err_fds[0], "r");
  1067. #endif
  1068.   
  1069.     if (*pipe_err) note_cleanups_for_file (p, *pipe_err);
  1070.   }
  1071.  
  1072.   unblock_alarms();
  1073.   return pid;
  1074. }
  1075.  
  1076. static void free_proc_chain (struct process_chain *procs)
  1077. {
  1078.   /* Dispose of the subprocesses we've spawned off in the course of
  1079.    * whatever it was we're cleaning up now.  This may involve killing
  1080.    * some of them off...
  1081.    */
  1082.  
  1083.   struct process_chain *p;
  1084.   int need_timeout = 0;
  1085.   int status;
  1086.  
  1087.   if (procs == NULL) return;    /* No work.  Whew! */
  1088.  
  1089.   /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL
  1090.    * dance with any of the processes we're cleaning up.  If we've got
  1091.    * any kill-on-sight subprocesses, ditch them now as well, so they
  1092.    * don't waste any more cycles doing whatever it is that they shouldn't
  1093.    * be doing anymore.
  1094.    */
  1095.  
  1096. #ifndef NEED_WAITPID
  1097.   /* Pick up all defunct processes */
  1098.   for (p = procs; p; p = p->next) {
  1099.     if (waitpid (p->pid, (int *) 0, WNOHANG) > 0) {
  1100.       p->kill_how = kill_never;
  1101.     }
  1102.   }
  1103. #endif
  1104.  
  1105.   for (p = procs; p; p = p->next) {
  1106.     if (p->kill_how == kill_after_timeout) {
  1107.       /* Subprocess may be dead already.  Only need the timeout if not. */
  1108.       if (kill (p->pid, SIGTERM) != -1)
  1109.     need_timeout = 1;
  1110.     } else if (p->kill_how == kill_always) {
  1111.       kill (p->pid, SIGKILL);
  1112.     }
  1113.   }
  1114.  
  1115.   /* Sleep only if we have to... */
  1116.  
  1117.   if (need_timeout) sleep (3);
  1118.  
  1119.   /* OK, the scripts we just timed out for have had a chance to clean up
  1120.    * --- now, just get rid of them, and also clean up the system accounting
  1121.    * goop...
  1122.    */
  1123.  
  1124.   for (p = procs; p; p = p->next){
  1125.     
  1126.     if (p->kill_how == kill_after_timeout) 
  1127.       kill (p->pid, SIGKILL);
  1128.  
  1129.     if (p->kill_how != kill_never)
  1130.       waitpid (p->pid, &status, 0);
  1131.   }
  1132. }
  1133.  
  1134.