/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2012 AT&T Intellectual Property * * and is licensed under the * * Eclipse Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.eclipse.org/org/documents/epl-v10.html * * (with md5 checksum b35adb5213ca9657e911e9befb180842) * * * * 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_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. */ /* this structure lives in the top data segment of the region */ typedef struct _vminit_s { union { Vmdata_t vd; /* root of usable data space */ Vmuchar_t a[ROUND(sizeof(Vmdata_t),ALIGN)]; } vd; union { Vmalloc_t vm; /* embedded region if needed */ Vmuchar_t a[ROUND(sizeof(Vmalloc_t),ALIGN)]; } vm; union { Seg_t seg; /* space for segment */ Vmuchar_t a[ROUND(sizeof(Seg_t),ALIGN)]; } seg; Block_t block[16]; /* space for a few blocks */ } 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 { Vmalloc_t *vm, *vmp, vmproto; Vmdata_t *vd; Vminit_t *init; size_t algn, size, incr; Block_t *bp, *np; Seg_t *seg; Vmuchar_t *addr; int rv; if(!meth || !disc || !disc->memoryf ) return NIL(Vmalloc_t*); GETPAGESIZE(_Vmpagesize); vmp = &vmproto; /* avoid memory allocation here! */ memset(vmp, 0, sizeof(Vmalloc_t)); memcpy(&vmp->meth, meth, sizeof(Vmethod_t)); vmp->disc = disc; mode &= VM_FLAGS; /* start with user-settable flags */ size = 0; if(disc->exceptf) { addr = NIL(Vmuchar_t*); if((rv = (*disc->exceptf)(vmp,VM_OPEN,(Void_t*)(&addr),disc)) < 0) return NIL(Vmalloc_t*); else if(rv == 0 ) { if(addr) /* vm itself is in memory from disc->memoryf */ mode |= VM_MEMORYF; } else if(rv > 0) /* the data section is being restored */ { if(!(init = (Vminit_t*)addr) ) return NIL(Vmalloc_t*); size = -1; /* to tell that addr was not from disc->memoryf */ vd = &init->vd.vd; /**/ASSERT(VLONG(vd)%ALIGN == 0); goto done; } } /* make sure vd->incr is properly rounded and get initial memory */ incr = disc->round <= 0 ? _Vmpagesize : disc->round; incr = MULTIPLE(incr,ALIGN); size = ROUND(sizeof(Vminit_t),incr); /* get initial memory */ if(!(addr = (Vmuchar_t*)(*disc->memoryf)(vmp, NIL(Void_t*), 0, size, disc)) ) return NIL(Vmalloc_t*); memset(addr, 0, size); /* initialize region data */ algn = (size_t)(VLONG(addr)%ALIGN); init = (Vminit_t*)(addr + (algn ? ALIGN-algn : 0)); /**/ASSERT(VLONG(init)%ALIGN == 0); vd = &init->vd.vd; /**/ASSERT(VLONG(vd)%ALIGN == 0); vd->mode = mode | meth->meth; vd->incr = incr; vd->pool = 0; vd->free = vd->wild = NIL(Block_t*); if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE)) { int k; vd->root = NIL(Block_t*); for(k = S_TINY-1; k >= 0; --k) TINY(vd)[k] = NIL(Block_t*); for(k = S_CACHE; k >= 0; --k) CACHE(vd)[k] = NIL(Block_t*); } vd->seg = &init->seg.seg; /**/ ASSERT(VLONG(vd->seg)%ALIGN == 0); seg = vd->seg; seg->next = NIL(Seg_t*); seg->vmdt = vd; seg->addr = (Void_t*)addr; seg->extent = size; seg->baddr = addr + size; seg->size = size; /* Note: this size is unusually large to mark seg as the root segment and can be freed only at closing */ seg->free = NIL(Block_t*); /* make a data block out of the remainder */ bp = SEGBLOCK(seg); SEG(bp) = seg; size = ((seg->baddr - (Vmuchar_t*)bp)/ALIGN) * ALIGN; /**/ ASSERT(size > 0); SIZE(bp) = size - 2*sizeof(Head_t); /**/ASSERT(SIZE(bp) > 0 && (SIZE(bp)%ALIGN) == 0); SELF(bp) = bp; /**/ ASSERT(SIZE(bp)%ALIGN == 0); /**/ ASSERT(VLONG(bp)%ALIGN == 0); /* make a fake header for next block in case of noncontiguous segments */ np = NEXT(bp); SEG(np) = seg; SIZE(np) = BUSY|PFREE; if(vd->mode&(VM_MTLAST|VM_MTPOOL)) seg->free = bp; else vd->wild = bp; done: /* now make the region handle */ if(vd->mode&VM_MEMORYF) vm = &init->vm.vm; else if(!(vm = vmalloc(Vmheap, sizeof(Vmalloc_t))) ) { if(size > 0) (void)(*disc->memoryf)(vmp, addr, size, 0, disc); return NIL(Vmalloc_t*); } memcpy(vm, vmp, sizeof(Vmalloc_t)); vm->data = vd; if(disc->exceptf) /* signaling that vmopen succeeded */ (void)(*disc->exceptf)(vm, VM_ENDOPEN, NIL(Void_t*), disc); /* add to the linked list of regions */ _vmlock(NIL(Vmalloc_t*), 1); vm->next = Vmheap->next; Vmheap->next = vm; _vmlock(NIL(Vmalloc_t*), 0); return vm; } #endif