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_vmlast(){}
1N/A
1N/A#else
1N/A
1N/A#include "vmhdr.h"
1N/A
1N/A/* Allocation with freeing and reallocing of last allocated block only.
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* lastalloc(Vmalloc_t* vm, size_t size)
1N/A#else
1N/Astatic Void_t* lastalloc(vm, size)
1N/AVmalloc_t* vm;
1N/Asize_t size;
1N/A#endif
1N/A{
1N/A reg Block_t *tp, *next;
1N/A reg Seg_t *seg, *last;
1N/A reg size_t s;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int local, inuse;
1N/A size_t orgsize = 0;
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 orgsize = size;
1N/A }
1N/A
1N/A size = size < ALIGN ? ALIGN : ROUND(size,ALIGN);
1N/A for(;;)
1N/A { for(last = NIL(Seg_t*), seg = vd->seg; seg; last = seg, seg = seg->next)
1N/A { if(!(tp = seg->free) || (SIZE(tp)+sizeof(Head_t)) < size)
1N/A continue;
1N/A if(last)
1N/A { last->next = seg->next;
1N/A seg->next = vd->seg;
1N/A vd->seg = seg;
1N/A }
1N/A goto got_block;
1N/A }
1N/A
1N/A /* there is no usable free space in region, try extending */
1N/A if((tp = (*_Vmextend)(vm,size,NIL(Vmsearch_f))) )
1N/A { seg = SEG(tp);
1N/A goto got_block;
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/Agot_block:
1N/A if((s = SIZE(tp)) >= size)
1N/A { next = (Block_t*)((Vmuchar_t*)tp+size);
1N/A SIZE(next) = s - size;
1N/A SEG(next) = seg;
1N/A seg->free = next;
1N/A }
1N/A else seg->free = NIL(Block_t*);
1N/A
1N/A vd->free = seg->last = tp;
1N/A
1N/A if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
1N/A (*_Vmtrace)(vm, NIL(Vmuchar_t*), (Vmuchar_t*)tp, orgsize, 0);
1N/A
1N/Adone:
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 int lastfree(Vmalloc_t* vm, reg Void_t* data )
1N/A#else
1N/Astatic int lastfree(vm, data)
1N/AVmalloc_t* vm;
1N/Areg Void_t* data;
1N/A#endif
1N/A{
1N/A reg Seg_t* seg;
1N/A reg Block_t* fp;
1N/A reg size_t s;
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 if(ISLOCK(vd, local))
1N/A { CLRINUSE(vd, inuse);
1N/A return -1;
1N/A }
1N/A SETLOCK(vd, local);
1N/A }
1N/A if(data != (Void_t*)vd->free)
1N/A { if(!local && vm->disc->exceptf)
1N/A (void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
1N/A CLRLOCK(vd, local);
1N/A CLRINUSE(vd, inuse);
1N/A return -1;
1N/A }
1N/A
1N/A seg = vd->seg;
1N/A if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
1N/A { if(seg->free )
1N/A s = (Vmuchar_t*)(seg->free) - (Vmuchar_t*)data;
1N/A else s = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
1N/A (*_Vmtrace)(vm, (Vmuchar_t*)data, NIL(Vmuchar_t*), s, 0);
1N/A }
1N/A
1N/A vd->free = NIL(Block_t*);
1N/A fp = (Block_t*)data;
1N/A SEG(fp) = seg;
1N/A SIZE(fp) = ((Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data) - sizeof(Head_t);
1N/A seg->free = fp;
1N/A seg->last = NIL(Block_t*);
1N/A
1N/A CLRLOCK(vd, local);
1N/A ANNOUNCE(local, vm, VM_FREE, data, vm->disc);
1N/A
1N/A CLRINUSE(vd, inuse);
1N/A return 0;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic Void_t* lastresize(Vmalloc_t* vm, reg Void_t* data, size_t size, int type )
1N/A#else
1N/Astatic Void_t* lastresize(vm, data, size, type )
1N/AVmalloc_t* vm;
1N/Areg Void_t* data;
1N/Asize_t size;
1N/Aint type;
1N/A#endif
1N/A{
1N/A reg Block_t* tp;
1N/A reg Seg_t *seg;
1N/A reg size_t oldsize;
1N/A reg ssize_t s, ds;
1N/A reg Vmdata_t* vd = vm->data;
1N/A reg int local, inuse;
1N/A reg Void_t* addr;
1N/A Void_t* orgdata = NIL(Void_t*);
1N/A size_t orgsize = 0;
1N/A
1N/A SETINUSE(vd, inuse);
1N/A if(!data)
1N/A { oldsize = 0;
1N/A data = lastalloc(vm,size);
1N/A goto done;
1N/A }
1N/A if(size <= 0)
1N/A { (void)lastfree(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 if(ISLOCK(vd, local))
1N/A { CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A SETLOCK(vd, local);
1N/A orgdata = data;
1N/A orgsize = size;
1N/A }
1N/A
1N/A if(data == (Void_t*)vd->free)
1N/A seg = vd->seg;
1N/A else
1N/A { /* see if it was one of ours */
1N/A for(seg = vd->seg; seg; seg = seg->next)
1N/A if(data >= seg->addr && data < (Void_t*)seg->baddr)
1N/A break;
1N/A if(!seg || (VLONG(data)%ALIGN) != 0 ||
1N/A (seg->last && (Vmuchar_t*)data > (Vmuchar_t*)seg->last) )
1N/A { CLRLOCK(vd,0);
1N/A CLRINUSE(vd, inuse);
1N/A return NIL(Void_t*);
1N/A }
1N/A }
1N/A
1N/A /* set 's' to be the current available space */
1N/A if(data != seg->last)
1N/A { if(seg->last && (Vmuchar_t*)data < (Vmuchar_t*)seg->last)
1N/A oldsize = (Vmuchar_t*)seg->last - (Vmuchar_t*)data;
1N/A else oldsize = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
1N/A s = -1;
1N/A }
1N/A else
1N/A { s = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
1N/A if(!(tp = seg->free) )
1N/A oldsize = s;
1N/A else
1N/A { oldsize = (Vmuchar_t*)tp - (Vmuchar_t*)data;
1N/A seg->free = NIL(Block_t*);
1N/A }
1N/A }
1N/A
1N/A size = size < ALIGN ? ALIGN : ROUND(size,ALIGN);
1N/A if(s < 0 || (ssize_t)size > s)
1N/A { if(s >= 0) /* amount to extend */
1N/A { ds = size-s; ds = ROUND(ds,vd->incr);
1N/A addr = (*vm->disc->memoryf)(vm, seg->addr, seg->extent,
1N/A seg->extent+ds, vm->disc);
1N/A if(addr == seg->addr)
1N/A { s += ds;
1N/A seg->size += ds;
1N/A seg->extent += ds;
1N/A seg->baddr += ds;
1N/A SIZE(BLOCK(seg->baddr)) = BUSY;
1N/A }
1N/A else goto do_alloc;
1N/A }
1N/A else
1N/A { do_alloc:
1N/A if(!(type&(VM_RSMOVE|VM_RSCOPY)) )
1N/A data = NIL(Void_t*);
1N/A else
1N/A { tp = vd->free;
1N/A if(!(addr = KPVALLOC(vm,size,lastalloc)) )
1N/A { vd->free = tp;
1N/A data = NIL(Void_t*);
1N/A }
1N/A else
1N/A { if(type&VM_RSCOPY)
1N/A { ds = oldsize < size ? oldsize : size;
1N/A memcpy(addr, data, ds);
1N/A }
1N/A
1N/A if(s >= 0 && seg != vd->seg)
1N/A { tp = (Block_t*)data;
1N/A SEG(tp) = seg;
1N/A SIZE(tp) = s - sizeof(Head_t);
1N/A seg->free = tp;
1N/A }
1N/A
1N/A /* new block and size */
1N/A data = addr;
1N/A seg = vd->seg;
1N/A s = (Vmuchar_t*)BLOCK(seg->baddr) -
1N/A (Vmuchar_t*)data;
1N/A seg->free = NIL(Block_t*);
1N/A }
1N/A }
1N/A }
1N/A }
1N/A
1N/A if(data)
1N/A { if(s >= (ssize_t)(size+sizeof(Head_t)) )
1N/A { tp = (Block_t*)((Vmuchar_t*)data + size);
1N/A SEG(tp) = seg;
1N/A SIZE(tp) = (s - size) - sizeof(Head_t);
1N/A seg->free = tp;
1N/A }
1N/A
1N/A vd->free = seg->last = (Block_t*)data;
1N/A
1N/A if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
1N/A (*_Vmtrace)(vm,(Vmuchar_t*)orgdata,(Vmuchar_t*)data,orgsize,0);
1N/A }
1N/A
1N/A CLRLOCK(vd, local);
1N/A ANNOUNCE(local, vm, VM_RESIZE, data, vm->disc);
1N/A
1N/Adone: if(data && (type&VM_RSZERO) && size > oldsize)
1N/A memset((Void_t*)((Vmuchar_t*)data + oldsize), 0, size-oldsize);
1N/A
1N/A CLRINUSE(vd, inuse);
1N/A return data;
1N/A}
1N/A
1N/A
1N/A#if __STD_C
1N/Astatic long lastaddr(Vmalloc_t* vm, Void_t* addr)
1N/A#else
1N/Astatic long lastaddr(vm, addr)
1N/AVmalloc_t* vm;
1N/AVoid_t* addr;
1N/A#endif
1N/A{
1N/A reg Vmdata_t* vd = vm->data;
1N/A
1N/A if(!(vd->mode&VM_TRUST) && ISLOCK(vd,0))
1N/A return -1L;
1N/A if(!vd->free || addr < (Void_t*)vd->free || addr >= (Void_t*)vd->seg->baddr)
1N/A return -1L;
1N/A else return (Vmuchar_t*)addr - (Vmuchar_t*)vd->free;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic long lastsize(Vmalloc_t* vm, Void_t* addr)
1N/A#else
1N/Astatic long lastsize(vm, addr)
1N/AVmalloc_t* vm;
1N/AVoid_t* addr;
1N/A#endif
1N/A{
1N/A reg Vmdata_t* vd = vm->data;
1N/A
1N/A if(!(vd->mode&VM_TRUST) && ISLOCK(vd,0))
1N/A return -1L;
1N/A if(!vd->free || addr != (Void_t*)vd->free )
1N/A return -1L;
1N/A else if(vd->seg->free)
1N/A return (Vmuchar_t*)vd->seg->free - (Vmuchar_t*)addr;
1N/A else return (Vmuchar_t*)vd->seg->baddr - (Vmuchar_t*)addr - sizeof(Head_t);
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic int lastcompact(Vmalloc_t* vm)
1N/A#else
1N/Astatic int lastcompact(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* lastalign(Vmalloc_t* vm, size_t size, size_t align)
1N/A#else
1N/Astatic Void_t* lastalign(vm, size, align)
1N/AVmalloc_t* vm;
1N/Asize_t size;
1N/Asize_t align;
1N/A#endif
1N/A{
1N/A reg Vmuchar_t* data;
1N/A reg Seg_t* seg;
1N/A reg Block_t* next;
1N/A reg int local, inuse;
1N/A reg size_t s, orgsize = 0, orgalign = 0;
1N/A reg Vmdata_t* vd = vm->data;
1N/A
1N/A if(size <= 0 || align <= 0)
1N/A return NIL(Void_t*);
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 orgsize = size;
1N/A orgalign = align;
1N/A }
1N/A
1N/A size = size <= TINYSIZE ? TINYSIZE : ROUND(size,ALIGN);
1N/A align = MULTIPLE(align,ALIGN);
1N/A
1N/A s = size + align;
1N/A if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,lastalloc)) )
1N/A goto done;
1N/A
1N/A /* find the segment containing this block */
1N/A for(seg = vd->seg; seg; seg = seg->next)
1N/A if(seg->last == (Block_t*)data)
1N/A break;
1N/A /**/ASSERT(seg);
1N/A
1N/A /* get a suitably aligned address */
1N/A if((s = (size_t)(VLONG(data)%align)) != 0)
1N/A data += align-s; /**/ASSERT((VLONG(data)%align) == 0);
1N/A
1N/A /* free the unused tail */
1N/A next = (Block_t*)(data+size);
1N/A if((s = (seg->baddr - (Vmuchar_t*)next)) >= sizeof(Block_t))
1N/A { SEG(next) = seg;
1N/A SIZE(next) = s - sizeof(Head_t);
1N/A seg->free = next;
1N/A }
1N/A
1N/A vd->free = seg->last = (Block_t*)data;
1N/A
1N/A if(!local && !(vd->mode&VM_TRUST) && _Vmtrace && (vd->mode&VM_TRACE) )
1N/A (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,orgsize,orgalign);
1N/A
1N/Adone:
1N/A CLRLOCK(vd,local);
1N/A ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)data, vm->disc);
1N/A
1N/A CLRINUSE(vd, inuse);
1N/A return (Void_t*)data;
1N/A}
1N/A
1N/A/* Public method for free-1 allocation */
1N/Astatic Vmethod_t _Vmlast =
1N/A{
1N/A lastalloc,
1N/A lastresize,
1N/A lastfree,
1N/A lastaddr,
1N/A lastsize,
1N/A lastcompact,
1N/A lastalign,
1N/A VM_MTLAST
1N/A};
1N/A
1N/A__DEFINE__(Vmethod_t*,Vmlast,&_Vmlast);
1N/A
1N/A#ifdef NoF
1N/ANoF(vmlast)
1N/A#endif
1N/A
1N/A#endif