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