vmpool.c revision 1
1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#if defined(_UWIN) && defined(_BLD_ast)
1N/A
1N/Avoid _STUB_vmpool(){}
1N/A
1N/A#else
1N/A
1N/A#include "vmhdr.h"
1N/A
1N/A#define POOLFREE 0x55555555L /* block free indicator */
1N/A
1N/A/* Method for pool allocation.
1N/A** All elements in a pool have the same size.
1N/A** The following fields of Vmdata_t are used as:
1N/A** pool: size of a block.
1N/A** free: list of free blocks.
1N/A**
1N/A** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
1N/A*/
1N/A
1N/A#if __STD_C
1N/Astatic Void_t* poolalloc(Vmalloc_t* vm, reg size_t size)
1N/A#else
1N/Astatic Void_t* poolalloc(vm, size )
1N/AVmalloc_t* vm;
1N/Areg size_t size;
1N/A#endif
1N/A{
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg Block_t *tp, *next;
1N/A reg size_t s;
1N/A reg Seg_t* seg;
1N/A reg int local, inuse;
1N/A
1N/A if(size <= 0)
1N/A return NIL(Void_t*);
1N/A if(size != vd->pool)
1N/A { if(vd->pool <= 0)
1N/A vd->pool = size;
1N/A else return NIL(Void_t*);
1N/A }
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(!(local = vd->mode&VM_TRUST) )
1N/A { GETLOCAL(vd,local);
1N/A if(ISLOCK(vd, local))
1N/A { CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A SETLOCK(vd, local);
1N/A }
1N/A
1N/A if((tp = vd->free) ) /* there is a ready free block */
1N/A { vd->free = SEGLINK(tp);
1N/A goto done;
1N/A }
1N/A
1N/A size = ROUND(size,ALIGN);
1N/A
1N/A /* look thru all segments for a suitable free block */
1N/A for(tp = NIL(Block_t*), seg = vd->seg; seg; seg = seg->next)
1N/A { if((tp = seg->free) &&
1N/A (s = (SIZE(tp) & ~BITS) + sizeof(Head_t)) >= size )
1N/A goto has_blk;
1N/A }
1N/A
1N/A for(;;) /* must extend region */
1N/A { if((tp = (*_Vmextend)(vm,ROUND(size,vd->incr),NIL(Vmsearch_f))) )
1N/A { s = (SIZE(tp) & ~BITS) + sizeof(Head_t);
1N/A seg = SEG(tp);
1N/A goto has_blk;
1N/A }
1N/A else if(vd->mode&VM_AGAIN)
1N/A vd->mode &= ~VM_AGAIN;
1N/A else goto done;
1N/A }
1N/A
1N/Ahas_blk: /* if get here, (tp, s, seg) must be well-defined */
1N/A next = (Block_t*)((Vmuchar_t*)tp+size);
1N/A if((s -= size) <= (size + sizeof(Head_t)) )
1N/A { for(; s >= size; s -= size)
1N/A { SIZE(next) = POOLFREE;
1N/A SEGLINK(next) = vd->free;
1N/A vd->free = next;
1N/A next = (Block_t*)((Vmuchar_t*)next + size);
1N/A }
1N/A seg->free = NIL(Block_t*);
1N/A }
1N/A else
1N/A { SIZE(next) = s - sizeof(Head_t);
1N/A SEG(next) = seg;
1N/A seg->free = next;
1N/A }
1N/A
1N/Adone:
1N/A if(!local && (vd->mode&VM_TRACE) && _Vmtrace && tp)
1N/A (*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)tp,vd->pool,0);
1N/A
1N/A CLRLOCK(vd, local);
1N/A ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)tp, vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return (Void_t*)tp;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic long pooladdr(Vmalloc_t* vm, reg Void_t* addr)
1N/A#else
1N/Astatic long pooladdr(vm, addr)
1N/AVmalloc_t* vm;
1N/Areg Void_t* addr;
1N/A#endif
1N/A{
1N/A reg Block_t *bp, *tp;
1N/A reg Vmuchar_t *laddr, *baddr;
1N/A reg size_t size;
1N/A reg Seg_t* seg;
1N/A reg long offset;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int local, inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(!(local = vd->mode&VM_TRUST))
1N/A { GETLOCAL(vd,local);
1N/A if(ISLOCK(vd,local))
1N/A { CLRINUSE(vd, inuse);
1N/A return -1L;
1N/A }
1N/A SETLOCK(vd,local);
1N/A }
1N/A
1N/A offset = -1L;
1N/A for(seg = vd->seg; seg; seg = seg->next)
1N/A { laddr = (Vmuchar_t*)SEGBLOCK(seg);
1N/A baddr = seg->baddr-sizeof(Head_t);
1N/A if((Vmuchar_t*)addr < laddr || (Vmuchar_t*)addr >= baddr)
1N/A continue;
1N/A
1N/A /* the block that has this address */
1N/A size = ROUND(vd->pool,ALIGN);
1N/A tp = (Block_t*)(laddr + (((Vmuchar_t*)addr-laddr)/size)*size );
1N/A
1N/A /* see if this block has been freed */
1N/A if(SIZE(tp) == POOLFREE) /* may be a coincidence - make sure */
1N/A for(bp = vd->free; bp; bp = SEGLINK(bp))
1N/A if(bp == tp)
1N/A goto done;
1N/A
1N/A offset = (long)((Vmuchar_t*)addr - (Vmuchar_t*)tp);
1N/A goto done;
1N/A }
1N/A
1N/Adone :
1N/A CLRLOCK(vd,local);
1N/A CLRINUSE(vd, inuse);
1N/A return offset;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic int poolfree(reg Vmalloc_t* vm, reg Void_t* data )
1N/A#else
1N/Astatic int poolfree(vm, data)
1N/Areg Vmalloc_t* vm;
1N/Areg Void_t* data;
1N/A#endif
1N/A{
1N/A reg Block_t* bp;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int local, inuse;
1N/A
1N/A if(!data)
1N/A return 0;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(!(local = vd->mode&VM_TRUST))
1N/A { GETLOCAL(vd, local);
1N/A
1N/A if(ISLOCK(vd, local) || vd->pool <= 0)
1N/A { CLRINUSE(vd, inuse);
1N/A return -1;
1N/A }
1N/A
1N/A if(KPVADDR(vm,data,pooladdr) != 0)
1N/A { if(vm->disc->exceptf)
1N/A (void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return -1;
1N/A }
1N/A
1N/A SETLOCK(vd, local);
1N/A }
1N/A
1N/A bp = (Block_t*)data;
1N/A SIZE(bp) = POOLFREE;
1N/A SEGLINK(bp) = vd->free;
1N/A vd->free = bp;
1N/A
1N/A if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
1N/A (*_Vmtrace)(vm, (Vmuchar_t*)data, NIL(Vmuchar_t*), vd->pool, 0);
1N/A
1N/A CLRLOCK(vd,local);
1N/A ANNOUNCE(local, vm, VM_FREE, data, vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return 0;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic Void_t* poolresize(Vmalloc_t* vm, Void_t* data, size_t size, int type )
1N/A#else
1N/Astatic Void_t* poolresize(vm, data, size, type )
1N/AVmalloc_t* vm;
1N/AVoid_t* data;
1N/Asize_t size;
1N/Aint type;
1N/A#endif
1N/A{
1N/A int local, inuse;
1N/A reg Vmdata_t* vd = vm->data;
1N/A
1N/A NOTUSED(type);
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(!data)
1N/A { if((data = poolalloc(vm,size)) && (type&VM_RSZERO) )
1N/A { reg int *d = (int*)data, *ed = (int*)((char*)data+size);
1N/A do { *d++ = 0;} while(d < ed);
1N/A }
1N/A CLRINUSE(vd, inuse);
1N/A return data;
1N/A }
1N/A if(size == 0)
1N/A { (void)poolfree(vm,data);
1N/A CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A
1N/A if(!(local = vd->mode&VM_TRUST) )
1N/A { GETLOCAL(vd, local);
1N/A
1N/A if(ISLOCK(vd, local) )
1N/A { CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A
1N/A if(size != vd->pool || KPVADDR(vm,data,pooladdr) != 0)
1N/A { if(vm->disc->exceptf)
1N/A (void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A
1N/A if((vd->mode&VM_TRACE) && _Vmtrace)
1N/A (*_Vmtrace)(vm, (Vmuchar_t*)data, (Vmuchar_t*)data, size, 0);
1N/A }
1N/A
1N/A ANNOUNCE(local, vm, VM_RESIZE, data, vm->disc);
1N/A CLRINUSE(vd, inuse);
1N/A return data;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic long poolsize(Vmalloc_t* vm, Void_t* addr)
1N/A#else
1N/Astatic long poolsize(vm, addr)
1N/AVmalloc_t* vm;
1N/AVoid_t* addr;
1N/A#endif
1N/A{
1N/A return pooladdr(vm,addr) == 0 ? (long)vm->data->pool : -1L;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic int poolcompact(Vmalloc_t* vm)
1N/A#else
1N/Astatic int poolcompact(vm)
1N/AVmalloc_t* vm;
1N/A#endif
1N/A{
1N/A reg Block_t* fp;
1N/A reg Seg_t *seg, *next;
1N/A reg size_t s;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int inuse;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(!(vd->mode&VM_TRUST))
1N/A { if(ISLOCK(vd,0))
1N/A { CLRINUSE(vd, inuse);
1N/A return -1;
1N/A }
1N/A SETLOCK(vd,0);
1N/A }
1N/A
1N/A for(seg = vd->seg; seg; seg = next)
1N/A { next = seg->next;
1N/A
1N/A if(!(fp = seg->free))
1N/A continue;
1N/A
1N/A seg->free = NIL(Block_t*);
1N/A if(seg->size == (s = SIZE(fp)&~BITS))
1N/A s = seg->extent;
1N/A else s += sizeof(Head_t);
1N/A
1N/A if((*_Vmtruncate)(vm,seg,s,1) == s)
1N/A seg->free = fp;
1N/A }
1N/A
1N/A if((vd->mode&VM_TRACE) && _Vmtrace)
1N/A (*_Vmtrace)(vm, (Vmuchar_t*)0, (Vmuchar_t*)0, 0, 0);
1N/A
1N/A CLRLOCK(vd,0);
1N/A CLRINUSE(vd, inuse);
1N/A return 0;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic Void_t* poolalign(Vmalloc_t* vm, size_t size, size_t align)
1N/A#else
1N/Astatic Void_t* poolalign(vm, size, align)
1N/AVmalloc_t* vm;
1N/Asize_t size;
1N/Asize_t align;
1N/A#endif
1N/A{
1N/A NOTUSED(vm);
1N/A NOTUSED(size);
1N/A NOTUSED(align);
1N/A return NIL(Void_t*);
1N/A}
1N/A
1N/A/* Public interface */
1N/Astatic Vmethod_t _Vmpool =
1N/A{
1N/A poolalloc,
1N/A poolresize,
1N/A poolfree,
1N/A pooladdr,
1N/A poolsize,
1N/A poolcompact,
1N/A poolalign,
1N/A VM_MTPOOL
1N/A};
1N/A
1N/A__DEFINE__(Vmethod_t*,Vmpool,&_Vmpool);
1N/A
1N/A#ifdef NoF
1N/ANoF(vmpool)
1N/A#endif
1N/A
1N/A#endif