pool.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:16k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD - FTP server daemon
  3.  * Copyright (c) 1997, 1998 Public Flood Software
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  18.  */
  19. /*
  20.  * Resource allocation code
  21.  */
  22. #include "conf.h"
  23. /* Manage free storage blocks */
  24. union align
  25. {
  26.   char *cp;
  27.   void (*f)();
  28.   long l;
  29.   FILE *fp;
  30.   double d;
  31. };
  32. #define CLICK_SZ (sizeof(union align))
  33. union block_hdr
  34. {
  35.   union align a;
  36.   /* Actual header */
  37.   struct {
  38.     char *endp;
  39.     union block_hdr *next;
  40.     char *first_avail;
  41.   } h;
  42. };
  43. union block_hdr *block_freelist = NULL;
  44. /* Statistics */
  45. unsigned int stat_malloc = 0; /* incr when malloc required */
  46. unsigned int stat_freehit = 0; /* incr when freelist used */
  47. /* Lowest level memory allocation functions
  48.  */
  49. static void *null_alloc(size_t size)
  50. {
  51.   void *ret = 0;
  52.   if(size == 0)
  53.     ret = malloc(size);
  54.   if(ret == 0) {
  55.     log_pri(LOG_ERR,"Fatal: Memory exhausted.");
  56.     exit(1);
  57.   }
  58.   return ret;
  59. }
  60. void *xmalloc(size_t size)
  61. {
  62.   void *ret;
  63.   ret = malloc(size);
  64.   if(ret == 0)
  65.     ret = null_alloc(size);
  66.   return ret;
  67. }
  68. void *xcalloc(size_t num, size_t size)
  69. {
  70.   void *ret;
  71.   ret = calloc(num,size);
  72.   if(ret == 0)
  73.     ret = null_alloc(num * size);
  74.   return ret;
  75. }
  76. void *xrealloc(void *p, size_t size)
  77. {
  78.   if(p == 0)
  79.     return xmalloc(size);
  80.   p = realloc(p,size);
  81.   if(p == 0)
  82.     p = null_alloc(size);
  83.   return p;
  84. }
  85. /* Grab a completely new block from the system pool.  Relies on malloc()
  86.  * to return truely aligned memory.
  87.  */
  88. union block_hdr *malloc_block(int size)
  89. {
  90.   union block_hdr *blok =
  91.     (union block_hdr*)xmalloc(size + sizeof(union block_hdr));
  92.   blok->h.next = NULL;
  93.   blok->h.first_avail = (char *)(blok+1);
  94.   blok->h.endp = size + blok->h.first_avail;
  95.   return blok;
  96. }
  97. void chk_on_blk_list(union block_hdr *blok, union block_hdr *free_blk)
  98. {
  99.   /* Debug code */
  100.   while(free_blk) {
  101.     if(free_blk == blok) {
  102.       log_pri(LOG_ERR,"Fatal: DEBUG: Attempt to free already free block in chk_on_blk_list().");
  103.       exit(1);
  104.     }
  105.     free_blk = free_blk->h.next;
  106.   }
  107. }
  108. /* Free a chain of blocks -- _must_ call with alarms blocked. */
  109. void free_blocks(union block_hdr *blok)
  110. {
  111.   /* Puts new blocks at head of block list, point next pointer of
  112.    * last block in chain to free blocks we already had.
  113.    */
  114.   union block_hdr *old_free_list = block_freelist;
  115.   if(!blok)
  116.     return; /* Shouldn't be freeing an empty pool */
  117.   block_freelist = blok;
  118.   /* Adjust first_avail pointers */
  119.   while(blok->h.next) {
  120.     chk_on_blk_list(blok,old_free_list);
  121.     blok->h.first_avail = (char *)(blok + 1);
  122.     blok = blok->h.next;
  123.   }
  124.   chk_on_blk_list(blok,old_free_list);
  125.   blok->h.first_avail = (char*)(blok + 1);
  126.   blok->h.next = old_free_list;
  127. }
  128. /* Get a new block, from the free list if possible, otherwise malloc
  129.  * a new one.  *BLOCK ALARMS BEFORE CALLING*
  130.  */
  131. union block_hdr *new_block(int min_size)
  132. {
  133.   int biggest = 0;
  134.   union block_hdr **lastptr = &block_freelist;
  135.   union block_hdr *blok = block_freelist;
  136.   min_size = 1 + ((min_size - 1) / BLOCK_MINFREE);
  137.   min_size *= BLOCK_MINFREE;
  138.   while(blok) {
  139.     biggest = blok->h.endp - blok->h.first_avail;
  140.     if(min_size <= blok->h.endp - blok->h.first_avail) {
  141.       /* It's available */
  142.       *lastptr = blok->h.next;
  143.       stat_freehit++;
  144.       blok->h.next = NULL;
  145.       return blok;
  146.     } else {
  147.       lastptr = &blok->h.next;
  148.       blok = blok->h.next;
  149.     }
  150.   }
  151.   /* malloc a new one */
  152.   stat_malloc++;
  153.   return malloc_block(min_size);
  154. }
  155. /* accounting */
  156. long bytes_in_block_list(union block_hdr *blok)
  157. {
  158.   long size = 0;
  159.   while(blok) {
  160.     size += blok->h.endp - (char*)(blok+1);
  161.     blok = blok->h.next;
  162.   }
  163.   return size;
  164. }
  165. struct cleanup;
  166. static void run_cleanups(struct cleanup *);
  167. /* Pool internal and management */
  168. struct pool {
  169.   union block_hdr *first;
  170.   union block_hdr *last;
  171.   struct cleanup *cleanups;
  172.   struct pool *sub_pools;
  173.   struct pool *sub_next;
  174.   struct pool *sub_prev;
  175.   struct pool *parent;
  176.   char *free_first_avail;
  177.   char symbol;
  178. };
  179. pool *permanent_pool = NULL;
  180. /* Each pool structure is allocated in the start of it's own first block,
  181.  * so there is a need to know how many bytes that is (once properly
  182.  * aligned).
  183.  */
  184. #define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ))
  185. #define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ)
  186. /* walk all pools, starting with top level permanent pool, displaying a
  187.  * tree.
  188.  */
  189. static long __walk_pools(pool *p, int level)
  190. {
  191.   char _levelpad[80] = "";
  192.   long total = 0;
  193.   if(!p)
  194.     return 0;
  195.   if(level > 1) {
  196.     memset(_levelpad,' ',sizeof(_levelpad)-1);
  197.     if((level - 1) * 3 >= sizeof(_levelpad))
  198.       _levelpad[sizeof(_levelpad)-1] = 0;
  199.     else
  200.       _levelpad[(level - 1) * 3] = '';
  201.   }
  202.   for(; p; p = p->sub_next) {
  203.     total += bytes_in_block_list(p->first);
  204.     if(level == 0) {
  205.       if(p->symbol)
  206.         log_pri(LOG_NOTICE,"(%s)0x%08x bytes",
  207. &p->symbol,
  208. bytes_in_block_list(p->first));
  209.       else
  210.         log_pri(LOG_NOTICE,"0x%08x bytes",
  211.           bytes_in_block_list(p->first));
  212.     } else {
  213.       if(p->symbol)
  214. log_pri(LOG_NOTICE,"%s(%s)\- 0x%08x bytes",_levelpad,
  215. &p->symbol,
  216. bytes_in_block_list(p->first));
  217.       else
  218.         log_pri(LOG_NOTICE,"%s\- 0x%08x bytes",_levelpad,
  219.               bytes_in_block_list(p->first));
  220.     }
  221.     
  222.     /* recurse */
  223.     if(p->sub_pools)
  224.       total += __walk_pools(p->sub_pools,level+1);  
  225.   }
  226.   return total;
  227. }
  228. void debug_pool_info()
  229. {
  230.   if(block_freelist)
  231.     log_pri(LOG_NOTICE,"Free block list: 0x%08x bytes",
  232.             bytes_in_block_list(block_freelist));
  233.   else
  234.     log_pri(LOG_NOTICE,"Free block list: EMPTY");
  235.   log_pri(LOG_NOTICE,"%u count blocks malloc'd.",stat_malloc);
  236.   log_pri(LOG_NOTICE,"%u count blocks reused.",stat_freehit); 
  237. }
  238. void debug_walk_pools()
  239. {
  240.   log_pri(LOG_NOTICE,"Memory pool allocation:");
  241.   log_pri(LOG_NOTICE,"Total 0x%08x bytes allocated",
  242.           __walk_pools(permanent_pool,0));
  243.   debug_pool_info();
  244. }
  245. /* Release the entire free block list */
  246. void pool_release_free_block_list(void)
  247. {
  248.   union block_hdr *blok,*next;
  249.   block_alarms();
  250.   
  251.   blok = block_freelist;
  252.   if(blok) {
  253.     for(next = blok->h.next; next; blok = next, next = blok->h.next)
  254.       free(blok);
  255.   }
  256.   block_freelist = NULL;
  257.   unblock_alarms();
  258. }
  259. struct pool *make_named_sub_pool(struct pool *p, const char *symbol)
  260. {
  261.   union block_hdr *blok;
  262.   pool *new_pool;
  263.   block_alarms();
  264.   blok = new_block(0);
  265.   new_pool = (pool *) blok->h.first_avail;
  266.   
  267.   blok->h.first_avail += POOL_HDR_BYTES;
  268.   memset((char *) new_pool, '', sizeof(struct pool));
  269.   if(symbol) {
  270.     /* This could be questionable... - MacGyver
  271.      */
  272.     sstrncpy(&new_pool->symbol, symbol, strlen(&new_pool->symbol));
  273.     
  274.     /* Alignment issues on Sparc, SGI, and probably other hardware,
  275.      * demand this.
  276.      */
  277.     blok->h.first_avail += (strlen(symbol) / POOL_HDR_BYTES + 1) *
  278.       POOL_HDR_BYTES;
  279.   }
  280.   
  281.   new_pool->free_first_avail = blok->h.first_avail;
  282.   new_pool->first = new_pool->last = blok;
  283.   
  284.   if(p) {
  285.     new_pool->parent = p;
  286.     new_pool->sub_next = p->sub_pools;
  287.     if(new_pool->sub_next)
  288.       new_pool->sub_next->sub_prev = new_pool;
  289.     p->sub_pools = new_pool;
  290.   }
  291.   unblock_alarms();
  292.   return new_pool;
  293. }
  294. struct pool *make_sub_pool(struct pool *p)
  295. {
  296.   return make_named_sub_pool(p,NULL);
  297. }
  298. /* Initialize the pool system by creating the base permanent_pool. */
  299. void init_alloc() { permanent_pool = make_named_sub_pool(NULL,"permanent_pool"); }
  300. static void clear_pool(struct pool *p)
  301. {
  302.   if(!p)
  303.     return; /* Sanity check */
  304.   block_alarms();
  305.   run_cleanups(p->cleanups);   p->cleanups = NULL;
  306.   while(p->sub_pools)
  307.     destroy_pool(p->sub_pools);
  308.   p->sub_pools = NULL;
  309.   free_blocks(p->first->h.next); p->first->h.next = NULL;
  310.   p->last = p->first;
  311.   p->first->h.first_avail = p->free_first_avail;
  312.   unblock_alarms();
  313. }
  314. void destroy_pool(pool *p)
  315. {
  316.   block_alarms();
  317.   if(p->parent) {
  318.     if(p->parent->sub_pools == p) p->parent->sub_pools = p->sub_next;
  319.     if(p->sub_prev) p->sub_prev->sub_next = p->sub_next;
  320.     if(p->sub_next) p->sub_next->sub_prev = p->sub_prev;
  321.   }
  322.   clear_pool(p);
  323.   free_blocks(p->first);
  324.   unblock_alarms();
  325. }
  326. long bytes_in_pool(pool *p) { return bytes_in_block_list(p->first); }
  327. long bytes_in_free_blocks() { return bytes_in_block_list(block_freelist); }
  328. /* Allocation inteface ... 
  329.  */
  330. void *palloc(struct pool *p, int reqsize)
  331. {
  332.   /* Round up requested size to an even number of aligned units */
  333.   int nclicks = 1 + ((reqsize - 1) / CLICK_SZ);
  334.   int size = nclicks * CLICK_SZ;
  335.   /* For performance, see if space is availabe in most recently
  336.    * allocated block.
  337.    */
  338.   union block_hdr *blok = p->last;
  339.   char *first_avail = blok->h.first_avail;
  340.   char *new_first_avail;
  341.   if(reqsize <= 0)
  342.     return NULL;
  343.   block_alarms();
  344.   new_first_avail = first_avail + size;
  345.   if(new_first_avail <= blok->h.endp) {
  346.     blok->h.first_avail = new_first_avail;
  347.     unblock_alarms();
  348.     return (void *)first_avail;
  349.   }
  350.   /* Need a new one that's big enough */
  351.   blok = new_block(size);
  352.   p->last->h.next = blok;
  353.   p->last = blok;
  354.   first_avail = blok->h.first_avail;
  355.   blok->h.first_avail += size;
  356.   unblock_alarms();
  357.   return (void*)first_avail;
  358. }
  359. void *pcalloc(struct pool *p, int size)
  360. {
  361.   void *res = palloc(p,size);
  362.   memset(res,'',size);
  363.   return res;
  364. }
  365. char *pstrdup(struct pool *p, const char *s)
  366. {
  367.   char *res;
  368.   if(!s)
  369.     return NULL;
  370.   res = palloc(p, strlen(s) + 1);
  371.   sstrncpy(res, s, strlen(s) + 1);
  372.   return res;
  373. }
  374. char *pstrndup(struct pool *p, const char *s, int n)
  375. {
  376.   char *res;
  377.   if(!s)
  378.     return NULL;
  379.   res = palloc(p, n + 1);
  380.   sstrncpy(res, s, n + 1);
  381.   return res;
  382. }
  383. char *pdircat(pool *p, ...)
  384. {
  385.   char *argp, *res;
  386.   char last;
  387.   int len = 0;
  388.   va_list dummy;
  389.   va_start(dummy,p);
  390.   last = 0;
  391.   while((res = va_arg(dummy,char*)) != NULL) {
  392.     if(last && last != '/' && *res != '/')
  393.       len++;
  394.     else if(last && last == '/' && *res == '/')
  395.       len--;
  396.     len += strlen(res);
  397.     last = res[strlen(res) - 1];
  398.   }
  399.   va_end(dummy);
  400.   res = (char *) pcalloc(p, len + 1);
  401.   
  402.   va_start(dummy, p);
  403.   
  404.   last = 0;
  405.   
  406.   while((argp = va_arg(dummy, char *)) != NULL) {
  407.     if(last && last == '/' && *argp == '/')
  408.       argp++;
  409.     else if(last && last != '/' && *argp != '/')
  410.       sstrcat(res, "/", len + 1);
  411.     
  412.     sstrcat(res, argp, len + 1);
  413.     last = res[strlen(res) - 1];
  414.   }
  415.   va_end(dummy);
  416.   return res;
  417. }
  418. char *pstrcat(pool *p, ...)
  419. {
  420.   char *argp, *res;
  421.   int len = 0;
  422.   va_list dummy;
  423.   va_start(dummy,p);
  424.   
  425.   while((res = va_arg(dummy, char *)) != NULL)
  426.     len += strlen(res);
  427.   
  428.   va_end(dummy);
  429.   
  430.   res = (char*) pcalloc(p, len + 1);
  431.   
  432.   va_start(dummy,p);
  433.   
  434.   while((argp = va_arg(dummy, char *)) != NULL)
  435.     sstrcat(res, argp, len + 1);
  436.   
  437.   va_end(dummy);
  438.   
  439.   return res;
  440. }
  441. /*
  442.  * Array functions
  443.  */
  444. array_header *make_array(pool *p, int nelts, int elt_size)
  445. {
  446.   array_header *res = (array_header*) palloc(p, sizeof(array_header));
  447.   if(nelts < 1) nelts = 1;
  448.   res->elts = pcalloc(p, nelts * elt_size);
  449.   res->pool = p;
  450.   res->elt_size = elt_size;
  451.   res->nelts = 0;
  452.   res->nalloc = nelts;
  453.   return res;
  454. }
  455. void *push_array(array_header *arr)
  456. {
  457.   if(arr->nelts == arr->nalloc) {
  458.     char *new_data = pcalloc(arr->pool, arr->nalloc * arr->elt_size * 2);
  459.     memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size);
  460.     arr->elts = new_data;
  461.     arr->nalloc *= 2;
  462.   }
  463.   ++arr->nelts;
  464.   return ((char*)arr->elts) + (arr->elt_size * (arr->nelts - 1));
  465. }
  466. void array_cat(array_header *dst, const array_header *src)
  467. {
  468.   int elt_size = dst->elt_size;
  469.   if(dst->nelts + src->nelts > dst->nalloc) {
  470.     int new_size = dst->nalloc * 2;
  471.     char *new_data;
  472.     if(new_size == 0) ++new_size;
  473.     while(dst->nelts + src->nelts > new_size)
  474.       new_size *= 2;
  475.     new_data = pcalloc(dst->pool, elt_size * new_size);
  476.     memcpy(new_data, dst->elts, dst->nalloc * elt_size);
  477.     dst->elts = new_data;
  478.     dst->nalloc = new_size;
  479.   }
  480.   memcpy(((char*)dst->elts) + dst->nelts * elt_size, (char*)src->elts,
  481.          elt_size * src->nelts);
  482.   dst->nelts += src->nelts;
  483. }
  484. array_header *copy_array(pool *p, const array_header *arr)
  485. {
  486.   array_header *res = make_array(p,arr->nalloc,arr->elt_size);
  487.   memcpy(res->elts, arr->elts, arr->elt_size * arr->nelts);
  488.   res->nelts = arr->nelts;
  489.   return res;
  490. }
  491. array_header *copy_array_hdr(pool *p, const array_header *arr)
  492. {
  493.   array_header *res = (array_header *)palloc(p,sizeof(array_header));
  494.   res->elts = arr->elts;
  495.   res->pool = p;
  496.   res->elt_size = arr->elt_size;
  497.   res->nelts = arr->nelts;
  498.   res->nalloc = arr->nelts; /* Force overflow on push */
  499.   return res;
  500. }
  501. array_header *append_arrays(pool *p,
  502.                             const array_header *first,
  503.     const array_header *second)
  504. {
  505.   array_header *res = copy_array_hdr(p,first);
  506.   array_cat(res,second);
  507.   return res;
  508. }
  509. /*
  510.  * Generic cleanups
  511.  */
  512. struct cleanup {
  513.   void *data;
  514.   void (*plain_cleanup)(void*);
  515.   void (*child_cleanup)(void*);
  516.   struct cleanup *next;
  517. };
  518. void register_cleanup(pool *p, void *data, void (*plain_cleanup)(void*),
  519.                       void (*child_cleanup)(void*))
  520. {
  521.   struct cleanup *c = (struct cleanup*)palloc(p, sizeof(struct cleanup));
  522.   c->data = data;
  523.   c->plain_cleanup = plain_cleanup;
  524.   c->child_cleanup = child_cleanup;
  525.   c->next = p->cleanups;
  526.   p->cleanups = c;
  527. }
  528. void kill_cleanup(pool *p, void *data, void (*cleanup)(void*))
  529. {
  530.   struct cleanup *c = p->cleanups;
  531.   struct cleanup **lastp = &p->cleanups;
  532.   while(c) {
  533.     if(c->data == data && c->plain_cleanup == cleanup) {
  534.       *lastp = c->next;
  535.       break;
  536.     }
  537.     lastp = &c->next;
  538.     c = c->next;
  539.   }
  540. }
  541. void run_cleanup(pool *p, void *data, void (*cleanup)(void*))
  542. {
  543.   block_alarms();
  544.   (*cleanup)(data);
  545.   kill_cleanup(p,data,cleanup);
  546.   unblock_alarms();
  547. }
  548. static void run_cleanups(struct cleanup *c)
  549. {
  550.   while(c) {
  551.     (*c->plain_cleanup)(c->data);
  552.     c = c->next;
  553.   }
  554. }
  555. static void run_child_cleanups(struct cleanup *c)
  556. {
  557.   while(c) {
  558.     (*c->child_cleanup)(c->data);
  559.     c = c ->next;
  560.   }
  561. }
  562. static void cleanup_pool_for_exec(pool *p)
  563. {
  564.   run_child_cleanups(p->cleanups);
  565.   p->cleanups = NULL;
  566.   for(p = p->sub_pools; p; p = p->sub_next)
  567.     cleanup_pool_for_exec(p);
  568. }
  569. void cleanup_for_exec()
  570. {
  571.   block_alarms();
  572.   cleanup_pool_for_exec(permanent_pool);
  573.   unblock_alarms();
  574. }
  575. /*
  576.  * Files and file descriptors
  577.  */
  578. static void fd_cleanup(void *fdv) { close ((int)fdv); }
  579. void note_cleanups_for_fd(pool *p, int fd)
  580. {
  581.   register_cleanup(p,(void*)fd,fd_cleanup,fd_cleanup);
  582. }
  583. void kill_cleanups_for_fd(pool *p, int fd)
  584. {
  585.   kill_cleanup(p,(void*)fd,fd_cleanup);
  586. }
  587. int popenf(pool *p, const char *name, int flg, int mode)
  588. {
  589.   int fd;
  590.   block_alarms();
  591.   fd = open(name,flg,mode);
  592.   if(fd >= 0)
  593.     note_cleanups_for_fd(p,fd);
  594.   unblock_alarms();
  595.   return fd;
  596. }
  597. int pclosef(pool *p, int fd)
  598. {
  599.   int res;
  600.   block_alarms();
  601.   res = close(fd);
  602.   kill_cleanup(p, (void*)fd, fd_cleanup);
  603.   unblock_alarms();
  604.   return res;
  605. }
  606. /* Sep. plain and child cleanups for FILE *, since fclose() flushes
  607.  * the stream
  608.  */
  609. static void file_cleanup(void *fpv) { fclose((FILE*)fpv); }
  610. static void file_child_cleanup(void *fpv)
  611. { close(fileno((FILE*)fpv)); }
  612. void note_cleanups_for_file(pool *p, FILE *fp)
  613. {
  614.   register_cleanup(p,(void*)fp,file_cleanup,file_child_cleanup);
  615. }
  616. FILE *pfopen(pool *p, const char *name, const char *mode)
  617. {
  618.   FILE *fd = NULL;
  619.   int baseFlag, desc;
  620.   block_alarms();
  621.   if(*mode == 'a') {
  622.     baseFlag = (*(mode+1) == '+') ? O_RDWR : O_WRONLY;
  623.     desc = open(name, baseFlag | O_APPEND | O_CREAT,
  624.                 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
  625.     if(desc >= 0)
  626.       fd = fdopen(desc, mode);
  627.   } else {
  628.     fd = fopen(name, mode);
  629.   }
  630.   if(fd)
  631.     note_cleanups_for_file(p,fd);
  632.   unblock_alarms();
  633.   return fd;
  634. }
  635. FILE *pfdopen(pool *p, int fd, const char *mode)
  636. {
  637.   FILE *f;
  638.   block_alarms();
  639.   f = fdopen(fd,mode);
  640.   if(f)
  641.     note_cleanups_for_file(p,f);
  642.   unblock_alarms();
  643.   return f;
  644. }
  645. int pfclose(pool *p, FILE *fd)
  646. {
  647.   int res;
  648.   block_alarms();
  649.   res = fclose(fd);
  650.   kill_cleanup(p, (void*)fd, file_cleanup);
  651.   unblock_alarms();
  652.   return res;
  653. }