home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / may94 / util / edit / jade.lha / Jade / src / stringmem.c < prev    next >
C/C++ Source or Header  |  1994-04-19  |  6KB  |  257 lines

  1. /* stringmem.c -- Allocation of small pieces of memory
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4. This file is part of Jade.
  5.  
  6. Jade is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. Jade is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with Jade; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <assert.h>
  26.  
  27. int
  28. sm_init(STRMEM *sm)
  29. {
  30.     int i;
  31.     for(i = 0; i < NUMBUCKETS; i++)
  32.     {
  33.     NewMList(&(sm->sm_MemBuckets[i].mbu_MemBlocks));
  34.     sm->sm_ChunksPerBlock[i] = MBLOCKSIZE / MCHNK_SIZE((i + 1) * GRAIN);
  35. #ifdef STRMEM_STATS
  36.     sm->sm_AllocCount[i] = sm->sm_FreeCount[i] = 0;
  37. #endif
  38.     }
  39.     sm->sm_MallocChain = NULL;
  40.     return(TRUE);
  41. }
  42.  
  43. void
  44. sm_kill(STRMEM *sm)
  45. {
  46.     int i;
  47.     for(i = 0; i < NUMBUCKETS; i++)
  48.     {
  49.     MEMBLOCK *nxt, *mbl = (MEMBLOCK *)sm->sm_MemBuckets[i].mbu_MemBlocks.mlh_Head;
  50.     while((nxt = (MEMBLOCK *)mbl->mbl_Node.mln_Succ))
  51.     {
  52.         myfree(mbl);
  53.         mbl = nxt;
  54.     }
  55.     }
  56.     if(sm->sm_UseMallocChain)
  57.     {
  58.     MEMCHUNK *mc = sm->sm_MallocChain;
  59.     while(mc)
  60.     {
  61.         MEMCHUNK *nxtmc = mc->mc_Header.next;
  62.         myfree(mc);
  63.         mc = nxtmc;
  64.     }
  65.     }
  66. }
  67.  
  68. static int
  69. newmemblock(STRMEM *sm, MEMBUCKET *mbu, int sizeIndex)
  70. {
  71.     MEMBLOCK *mbl;
  72.     int numchunks = sm->sm_ChunksPerBlock[sizeIndex];
  73.     int chnkbytes = (sizeIndex + 1) * GRAIN;
  74.     mbl = mymalloc(MBLK_SIZE(chnkbytes, numchunks));
  75.     if(mbl)
  76.     {
  77.     MEMCHUNK *mc = mbl->mbl_Chunks;
  78.     int i, mcsiz = MCHNK_SIZE(chnkbytes);
  79.     AddMTail(&mbu->mbu_MemBlocks, &mbl->mbl_Node);
  80.     for(i = 0; i < (numchunks - 1); i++)
  81.     {
  82.         MEMCHUNK *nxt = (MEMCHUNK *)((char *)mc + mcsiz);
  83.         mc->mc_BlkType = MBT_FREE;
  84.         mc->mc_Mem.nextfree = nxt;
  85.         mc = nxt;
  86.     }
  87.     mc->mc_BlkType = MBT_FREE;
  88.     mc->mc_Mem.nextfree = mbu->mbu_FreeList;
  89.     mbu->mbu_FreeList = mbl->mbl_Chunks;
  90.     return(TRUE);
  91.     }
  92.     return(FALSE);
  93. }
  94.  
  95. void *
  96. sm_alloc(STRMEM *sm, int size)
  97. {
  98.     MEMCHUNK *mc;
  99.     assert(size > 0);
  100.     if(size > MAXBUCKETSIZE)
  101.     {
  102.     mc = mymalloc(MCHNK_SIZE(size));
  103.     if(mc)
  104.     {
  105. #ifdef STRMEM_STATS
  106.         sm->sm_AllocCount[NUMBUCKETS]++;
  107. #endif
  108.         if(sm->sm_UseMallocChain)
  109.         {
  110.         mc->mc_Header.next = sm->sm_MallocChain;
  111.         sm->sm_MallocChain = mc;
  112.         }
  113.         else
  114.         mc->mc_BlkType = MBT_MALLOC;
  115.     }
  116.     else
  117.         return(NULL);
  118.     }
  119.     else
  120.     {
  121.     MEMBUCKET *mbu;
  122.     int bucket = (size - 1) / GRAIN;
  123.     mbu = &sm->sm_MemBuckets[bucket];
  124.     if(!(mc = mbu->mbu_FreeList))
  125.     {
  126.         if(!newmemblock(sm, mbu, bucket))
  127.         return(NULL);
  128.         if(!(mc = mbu->mbu_FreeList))
  129.         return(NULL);
  130.     }
  131.     mc->mc_BlkType = bucket;
  132.     mbu->mbu_FreeList = mc->mc_Mem.nextfree;
  133. #ifdef STRMEM_STATS
  134.     sm->sm_AllocCount[bucket]++;
  135. #endif
  136.     }
  137.     return(mc->mc_Mem.mem);
  138. }
  139.  
  140. u_char *
  141. sm_strdupn(STRMEM *sm, const u_char *old, int len)
  142. {
  143.     char *new = sm_alloc(sm, len + 1);
  144.     if(new)
  145.     {
  146.     memcpy(new, old, len);
  147.     new[len] = 0;
  148.     }
  149.     return(new);
  150. }
  151.  
  152. u_char *
  153. sm_strdup(STRMEM *sm, const u_char *str)
  154. {
  155.     return(sm_strdupn(sm, str, strlen(str)));
  156. }
  157.  
  158. /*
  159.  * This scans through all allocated MEMBLOCKs in a MEMBUCKET looking
  160.  * for any which totally consist of unused entrys, any found are
  161.  * released.
  162.  */
  163. static void
  164. flushbucket(STRMEM *sm, int bucketIndex)
  165. {
  166.     MEMBLOCK *mbl = (MEMBLOCK *)sm->sm_MemBuckets[bucketIndex].mbu_MemBlocks.mlh_Head;
  167.     MEMBLOCK *nxt;
  168.     int chnksiz = MCHNK_SIZE((bucketIndex + 1) * GRAIN);
  169.     int numchnks = sm->sm_ChunksPerBlock[bucketIndex];
  170.     while((nxt = (MEMBLOCK *)mbl->mbl_Node.mln_Succ))
  171.     {
  172.     MEMCHUNK *mc = mbl->mbl_Chunks;
  173.     int j;
  174.     for(j = 0; j < numchnks; j++)
  175.     {
  176.         if(mc->mc_BlkType != MBT_FREE)
  177.         break;
  178.         mc = (MEMCHUNK *)((char *)mc + chnksiz);
  179.     }
  180.     if(j == numchnks)
  181.     {
  182.         mc = mbl->mbl_Chunks;
  183.         for(j = 0; j < numchnks; j++)
  184.         {
  185.         MEMCHUNK *last = NULL;
  186.         MEMCHUNK *list = sm->sm_MemBuckets[bucketIndex].mbu_FreeList;
  187.         while(list)
  188.         {
  189.             if(list == mc)
  190.             {
  191.             if(last)
  192.                 last->mc_Mem.nextfree = list->mc_Mem.nextfree;
  193.             else
  194.                 sm->sm_MemBuckets[bucketIndex].mbu_FreeList = list->mc_Mem.nextfree;
  195.             break;
  196.             }
  197.             last = list;
  198.             list = list->mc_Mem.nextfree;
  199.         }
  200.         mc = (MEMCHUNK *)((char *)mc + chnksiz);
  201.         }
  202.         RemoveM(&mbl->mbl_Node);
  203.         myfree(mbl);
  204.     }
  205.     mbl = nxt;
  206.     }
  207. }
  208.  
  209. void
  210. sm_free(STRMEM *sm, void *mem)
  211. {
  212.     if(mem)
  213.     {
  214.     MEMCHUNK *mc = (MEMCHUNK *)(((char *)mem) - sizeof(union mc_header));
  215.     int bucketnum = mc->mc_BlkType;
  216.     if(bucketnum == MBT_MALLOC)
  217.     {
  218.         myfree(mc);
  219. #ifdef STRMEM_STATS
  220.         sm->sm_FreeCount[NUMBUCKETS]++;
  221. #endif
  222.     }
  223.     else
  224.     {
  225.         MEMBUCKET *mbu;
  226.         assert(bucketnum <= NUMBUCKETS);
  227.         mbu = &sm->sm_MemBuckets[bucketnum];
  228.         mc->mc_Mem.nextfree = mbu->mbu_FreeList;
  229.         mc->mc_BlkType = MBT_FREE;
  230.         mbu->mbu_FreeList = mc;
  231.         if(sm->sm_FreesBeforeFlush)
  232.         {
  233.         /* check whether to flush this bucket... */
  234.         if(++mbu->mbu_FreeCount >= (sm->sm_FreesBeforeFlush * sm->sm_ChunksPerBlock[bucketnum]))
  235.         {
  236.             mbu->mbu_FreeCount = 0;
  237.             flushbucket(sm, bucketnum);
  238.         }
  239.         }
  240. #ifdef STRMEM_STATS
  241.         sm->sm_FreeCount[bucketnum]++;
  242. #endif
  243.     }
  244.     }
  245. }
  246.  
  247. /*
  248.  * called when malloc() fails, tries to release any memory we can
  249.  */
  250. void
  251. sm_flush(STRMEM *sm)
  252. {
  253.     int i;
  254.     for(i = 0; i < NUMBUCKETS; i++)
  255.     flushbucket(sm, i);
  256. }
  257.