vmpool.c revision 34f9b3eef6fdadbda0a846aa4d68691ac40eace5
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2009 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 <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* *
***********************************************************************/
#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