home *** CD-ROM | disk | FTP | other *** search
- /* stringmem.c -- Allocation of small pieces of memory
- Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
-
- This file is part of Jade.
-
- Jade is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- Jade is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Jade; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "jade.h"
- #include "jade_protos.h"
-
- #include <string.h>
- #include <stdlib.h>
- #include <assert.h>
-
- int
- sm_init(STRMEM *sm)
- {
- int i;
- for(i = 0; i < NUMBUCKETS; i++)
- {
- NewMList(&(sm->sm_MemBuckets[i].mbu_MemBlocks));
- sm->sm_ChunksPerBlock[i] = MBLOCKSIZE / MCHNK_SIZE((i + 1) * GRAIN);
- #ifdef STRMEM_STATS
- sm->sm_AllocCount[i] = sm->sm_FreeCount[i] = 0;
- #endif
- }
- sm->sm_MallocChain = NULL;
- return(TRUE);
- }
-
- void
- sm_kill(STRMEM *sm)
- {
- int i;
- for(i = 0; i < NUMBUCKETS; i++)
- {
- MEMBLOCK *nxt, *mbl = (MEMBLOCK *)sm->sm_MemBuckets[i].mbu_MemBlocks.mlh_Head;
- while((nxt = (MEMBLOCK *)mbl->mbl_Node.mln_Succ))
- {
- myfree(mbl);
- mbl = nxt;
- }
- }
- if(sm->sm_UseMallocChain)
- {
- MEMCHUNK *mc = sm->sm_MallocChain;
- while(mc)
- {
- MEMCHUNK *nxtmc = mc->mc_Header.next;
- myfree(mc);
- mc = nxtmc;
- }
- }
- }
-
- static int
- newmemblock(STRMEM *sm, MEMBUCKET *mbu, int sizeIndex)
- {
- MEMBLOCK *mbl;
- int numchunks = sm->sm_ChunksPerBlock[sizeIndex];
- int chnkbytes = (sizeIndex + 1) * GRAIN;
- mbl = mymalloc(MBLK_SIZE(chnkbytes, numchunks));
- if(mbl)
- {
- MEMCHUNK *mc = mbl->mbl_Chunks;
- int i, mcsiz = MCHNK_SIZE(chnkbytes);
- AddMTail(&mbu->mbu_MemBlocks, &mbl->mbl_Node);
- for(i = 0; i < (numchunks - 1); i++)
- {
- MEMCHUNK *nxt = (MEMCHUNK *)((char *)mc + mcsiz);
- mc->mc_BlkType = MBT_FREE;
- mc->mc_Mem.nextfree = nxt;
- mc = nxt;
- }
- mc->mc_BlkType = MBT_FREE;
- mc->mc_Mem.nextfree = mbu->mbu_FreeList;
- mbu->mbu_FreeList = mbl->mbl_Chunks;
- return(TRUE);
- }
- return(FALSE);
- }
-
- void *
- sm_alloc(STRMEM *sm, int size)
- {
- MEMCHUNK *mc;
- assert(size > 0);
- if(size > MAXBUCKETSIZE)
- {
- mc = mymalloc(MCHNK_SIZE(size));
- if(mc)
- {
- #ifdef STRMEM_STATS
- sm->sm_AllocCount[NUMBUCKETS]++;
- #endif
- if(sm->sm_UseMallocChain)
- {
- mc->mc_Header.next = sm->sm_MallocChain;
- sm->sm_MallocChain = mc;
- }
- else
- mc->mc_BlkType = MBT_MALLOC;
- }
- else
- return(NULL);
- }
- else
- {
- MEMBUCKET *mbu;
- int bucket = (size - 1) / GRAIN;
- mbu = &sm->sm_MemBuckets[bucket];
- if(!(mc = mbu->mbu_FreeList))
- {
- if(!newmemblock(sm, mbu, bucket))
- return(NULL);
- if(!(mc = mbu->mbu_FreeList))
- return(NULL);
- }
- mc->mc_BlkType = bucket;
- mbu->mbu_FreeList = mc->mc_Mem.nextfree;
- #ifdef STRMEM_STATS
- sm->sm_AllocCount[bucket]++;
- #endif
- }
- return(mc->mc_Mem.mem);
- }
-
- u_char *
- sm_strdupn(STRMEM *sm, const u_char *old, int len)
- {
- char *new = sm_alloc(sm, len + 1);
- if(new)
- {
- memcpy(new, old, len);
- new[len] = 0;
- }
- return(new);
- }
-
- u_char *
- sm_strdup(STRMEM *sm, const u_char *str)
- {
- return(sm_strdupn(sm, str, strlen(str)));
- }
-
- /*
- * This scans through all allocated MEMBLOCKs in a MEMBUCKET looking
- * for any which totally consist of unused entrys, any found are
- * released.
- */
- static void
- flushbucket(STRMEM *sm, int bucketIndex)
- {
- MEMBLOCK *mbl = (MEMBLOCK *)sm->sm_MemBuckets[bucketIndex].mbu_MemBlocks.mlh_Head;
- MEMBLOCK *nxt;
- int chnksiz = MCHNK_SIZE((bucketIndex + 1) * GRAIN);
- int numchnks = sm->sm_ChunksPerBlock[bucketIndex];
- while((nxt = (MEMBLOCK *)mbl->mbl_Node.mln_Succ))
- {
- MEMCHUNK *mc = mbl->mbl_Chunks;
- int j;
- for(j = 0; j < numchnks; j++)
- {
- if(mc->mc_BlkType != MBT_FREE)
- break;
- mc = (MEMCHUNK *)((char *)mc + chnksiz);
- }
- if(j == numchnks)
- {
- mc = mbl->mbl_Chunks;
- for(j = 0; j < numchnks; j++)
- {
- MEMCHUNK *last = NULL;
- MEMCHUNK *list = sm->sm_MemBuckets[bucketIndex].mbu_FreeList;
- while(list)
- {
- if(list == mc)
- {
- if(last)
- last->mc_Mem.nextfree = list->mc_Mem.nextfree;
- else
- sm->sm_MemBuckets[bucketIndex].mbu_FreeList = list->mc_Mem.nextfree;
- break;
- }
- last = list;
- list = list->mc_Mem.nextfree;
- }
- mc = (MEMCHUNK *)((char *)mc + chnksiz);
- }
- RemoveM(&mbl->mbl_Node);
- myfree(mbl);
- }
- mbl = nxt;
- }
- }
-
- void
- sm_free(STRMEM *sm, void *mem)
- {
- if(mem)
- {
- MEMCHUNK *mc = (MEMCHUNK *)(((char *)mem) - sizeof(union mc_header));
- int bucketnum = mc->mc_BlkType;
- if(bucketnum == MBT_MALLOC)
- {
- myfree(mc);
- #ifdef STRMEM_STATS
- sm->sm_FreeCount[NUMBUCKETS]++;
- #endif
- }
- else
- {
- MEMBUCKET *mbu;
- assert(bucketnum <= NUMBUCKETS);
- mbu = &sm->sm_MemBuckets[bucketnum];
- mc->mc_Mem.nextfree = mbu->mbu_FreeList;
- mc->mc_BlkType = MBT_FREE;
- mbu->mbu_FreeList = mc;
- if(sm->sm_FreesBeforeFlush)
- {
- /* check whether to flush this bucket... */
- if(++mbu->mbu_FreeCount >= (sm->sm_FreesBeforeFlush * sm->sm_ChunksPerBlock[bucketnum]))
- {
- mbu->mbu_FreeCount = 0;
- flushbucket(sm, bucketnum);
- }
- }
- #ifdef STRMEM_STATS
- sm->sm_FreeCount[bucketnum]++;
- #endif
- }
- }
- }
-
- /*
- * called when malloc() fails, tries to release any memory we can
- */
- void
- sm_flush(STRMEM *sm)
- {
- int i;
- for(i = 0; i < NUMBUCKETS; i++)
- flushbucket(sm, i);
- }
-