diff options
Diffstat (limited to 'usr/src/lib/libast/common/vmalloc/vmopen.c')
-rw-r--r-- | usr/src/lib/libast/common/vmalloc/vmopen.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/usr/src/lib/libast/common/vmalloc/vmopen.c b/usr/src/lib/libast/common/vmalloc/vmopen.c new file mode 100644 index 0000000000..d441410906 --- /dev/null +++ b/usr/src/lib/libast/common/vmalloc/vmopen.c @@ -0,0 +1,176 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* 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_vmopen(){} + +#else + +#include "vmhdr.h" + +/* Opening a new region of allocation. +** Note that because of possible exotic memory types, +** all region data must be stored within the space given +** by the discipline. +** +** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94. +*/ + +typedef struct _vminit_ +{ + Vmdata_t vd; /* space for the region itself */ + Seg_t seg; /* space for segment */ + Block_t block; /* space for a block */ + Head_t head; /* space for the fake header */ + char a[3*ALIGN]; /* extra to fuss with alignment */ +} Vminit_t; + +#if __STD_C +Vmalloc_t* vmopen(Vmdisc_t* disc, Vmethod_t* meth, int mode) +#else +Vmalloc_t* vmopen(disc, meth, mode) +Vmdisc_t* disc; /* discipline to get segments */ +Vmethod_t* meth; /* method to manage space */ +int mode; /* type of region */ +#endif +{ + reg Vmalloc_t* vm; + reg Vmdata_t* vd; + reg size_t s, a, incr; + reg Block_t* b; + reg Seg_t* seg; + Vmuchar_t* addr; + reg Vmemory_f memoryf; + reg int e; + + if(!meth || !disc || !(memoryf = disc->memoryf) ) + return NIL(Vmalloc_t*); + + GETPAGESIZE(_Vmpagesize); + + /* note that Vmalloc_t space must be local to process since that's + where the meth&disc function addresses are going to be stored */ + if(!(vm = (Vmalloc_t*)vmalloc(Vmheap,sizeof(Vmalloc_t))) ) + return NIL(Vmalloc_t*); + vm->meth = *meth; + vm->disc = disc; + vm->file = NIL(char*); + vm->line = 0; + + if(disc->exceptf) + { addr = NIL(Vmuchar_t*); + if((e = (*disc->exceptf)(vm,VM_OPEN,(Void_t*)(&addr),disc)) != 0) + { if(e < 0 || !addr) + goto open_error; + + /* align this address */ + if((a = (size_t)(VLONG(addr)%ALIGN)) != 0) + addr += ALIGN-a; + + /* see if it's a valid region */ + vd = (Vmdata_t*)addr; + if((vd->mode&meth->meth) != 0) + { vm->data = vd; + return vm; + } + else + { open_error: + vmfree(Vmheap,vm); + return NIL(Vmalloc_t*); + } + } + } + + /* make sure vd->incr is properly rounded */ + incr = disc->round <= 0 ? _Vmpagesize : disc->round; + incr = MULTIPLE(incr,ALIGN); + + /* get space for region data */ + s = ROUND(sizeof(Vminit_t),incr); + if(!(addr = (Vmuchar_t*)(*memoryf)(vm,NIL(Void_t*),0,s,disc)) ) + { vmfree(Vmheap,vm); + return NIL(Vmalloc_t*); + } + + /* make sure that addr is aligned */ + if((a = (size_t)(VLONG(addr)%ALIGN)) != 0) + addr += ALIGN-a; + + /* initialize region */ + vd = (Vmdata_t*)addr; + vd->mode = (mode&VM_FLAGS) | meth->meth; + vd->incr = incr; + vd->pool = 0; + vd->free = vd->wild = NIL(Block_t*); + + if(vd->mode&(VM_TRACE|VM_MTDEBUG)) + vd->mode &= ~VM_TRUST; + + if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE)) + { vd->root = NIL(Block_t*); + for(e = S_TINY-1; e >= 0; --e) + TINY(vd)[e] = NIL(Block_t*); + for(e = S_CACHE; e >= 0; --e) + CACHE(vd)[e] = NIL(Block_t*); + incr = sizeof(Vmdata_t); + } + else incr = OFFSET(Vmdata_t,root); + + vd->seg = (Seg_t*)(addr + ROUND(incr,ALIGN)); + /**/ ASSERT(VLONG(vd->seg)%ALIGN == 0); + + seg = vd->seg; + seg->next = NIL(Seg_t*); + seg->vm = vm; + seg->addr = (Void_t*)(addr - (a ? ALIGN-a : 0)); + seg->extent = s; + seg->baddr = addr + s - (a ? ALIGN : 0); + seg->size = s; /* this size is larger than usual so that the segment + will not be freed until the region is closed. */ + seg->free = NIL(Block_t*); + + /* make a data block out of the remainder */ + b = SEGBLOCK(seg); + SEG(b) = seg; + SIZE(b) = seg->baddr - (Vmuchar_t*)b - 2*sizeof(Head_t); + *SELF(b) = b; + /**/ ASSERT(SIZE(b)%ALIGN == 0); + /**/ ASSERT(VLONG(b)%ALIGN == 0); + + /* make a fake header for next block in case of noncontiguous segments */ + SEG(NEXT(b)) = seg; + SIZE(NEXT(b)) = BUSY|PFREE; + + if(vd->mode&(VM_MTLAST|VM_MTPOOL)) + seg->free = b; + else vd->wild = b; + + vm->data = vd; + + /* put into linked list of regions */ + vm->next = Vmheap->next; + Vmheap->next = vm; + + return vm; +} + +#endif |