| 1 | /* $Id$ $Revision$ */ |
| 2 | /* vim:set shiftwidth=4 ts=8: */ |
| 3 | |
| 4 | /************************************************************************* |
| 5 | * Copyright (c) 2011 AT&T Intellectual Property |
| 6 | * All rights reserved. This program and the accompanying materials |
| 7 | * are made available under the terms of the Eclipse Public License v1.0 |
| 8 | * which accompanies this distribution, and is available at |
| 9 | * http://www.eclipse.org/legal/epl-v10.html |
| 10 | * |
| 11 | * Contributors: See CVS logs. Details at http://www.graphviz.org/ |
| 12 | *************************************************************************/ |
| 13 | |
| 14 | #include "vmhdr.h" |
| 15 | |
| 16 | /* Opening a new region of allocation. |
| 17 | ** Note that because of possible exotic memory types, |
| 18 | ** all region data must be stored within the space given |
| 19 | ** by the discipline. |
| 20 | ** |
| 21 | ** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94. |
| 22 | */ |
| 23 | |
| 24 | typedef struct _vminit_ { |
| 25 | Vmdata_t vd; /* space for the region itself */ |
| 26 | Seg_t seg; /* space for segment */ |
| 27 | Block_t block; /* space for a block */ |
| 28 | Head_t head; /* space for the fake header */ |
| 29 | char a[3 * ALIGN]; /* extra to fuss with alignment */ |
| 30 | } Vminit_t; |
| 31 | |
| 32 | /** |
| 33 | * @param disc discipline to get segments |
| 34 | * @param meth method to manage space |
| 35 | * @param mode type of region |
| 36 | */ |
| 37 | Vmalloc_t *vmopen(Vmdisc_t * disc, Vmethod_t * meth, int mode) |
| 38 | { |
| 39 | reg Vmalloc_t *vm; |
| 40 | reg Vmdata_t *vd; |
| 41 | reg size_t s, a, incr; |
| 42 | reg Block_t *b; |
| 43 | reg Seg_t *seg; |
| 44 | Vmuchar_t *addr; |
| 45 | reg Vmemory_f memoryf; |
| 46 | reg int e; |
| 47 | |
| 48 | if (!meth || !disc || !(memoryf = disc->memoryf)) |
| 49 | return NIL(Vmalloc_t *); |
| 50 | |
| 51 | GETPAGESIZE(_Vmpagesize); |
| 52 | |
| 53 | /* note that Vmalloc_t space must be local to process since that's |
| 54 | where the meth&disc function addresses are going to be stored */ |
| 55 | if (!(vm = (Vmalloc_t *) vmalloc(Vmheap, sizeof(Vmalloc_t)))) |
| 56 | return NIL(Vmalloc_t *); |
| 57 | vm->meth = *meth; |
| 58 | vm->disc = disc; |
| 59 | vm->file = NIL(char *); |
| 60 | vm->line = 0; |
| 61 | |
| 62 | if (disc->exceptf) { |
| 63 | addr = NIL(Vmuchar_t *); |
| 64 | if ((e = |
| 65 | (*disc->exceptf) (vm, VM_OPEN, (void *) (&addr), |
| 66 | disc)) != 0) { |
| 67 | if (e < 0 || !addr) |
| 68 | goto open_error; |
| 69 | |
| 70 | /* align this address */ |
| 71 | if ((a = (size_t) (VLONG(addr) % ALIGN)) != 0) |
| 72 | addr += ALIGN - a; |
| 73 | |
| 74 | /* see if it's a valid region */ |
| 75 | vd = (Vmdata_t *) addr; |
| 76 | if ((vd->mode & meth->meth) != 0) { |
| 77 | vm->data = vd; |
| 78 | return vm; |
| 79 | } else { |
| 80 | open_error: |
| 81 | vmfree(Vmheap, vm); |
| 82 | return NIL(Vmalloc_t *); |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /* make sure vd->incr is properly rounded */ |
| 88 | incr = disc->round <= 0 ? _Vmpagesize : disc->round; |
| 89 | incr = MULTIPLE(incr, ALIGN); |
| 90 | |
| 91 | /* get space for region data */ |
| 92 | s = ROUND(sizeof(Vminit_t), incr); |
| 93 | if (!(addr = (Vmuchar_t *) (*memoryf) (vm, NIL(void *), 0, s, disc))) { |
| 94 | vmfree(Vmheap, vm); |
| 95 | return NIL(Vmalloc_t *); |
| 96 | } |
| 97 | |
| 98 | /* make sure that addr is aligned */ |
| 99 | if ((a = (size_t) (VLONG(addr) % ALIGN)) != 0) |
| 100 | addr += ALIGN - a; |
| 101 | |
| 102 | /* initialize region */ |
| 103 | vd = (Vmdata_t *) addr; |
| 104 | vd->mode = (mode & VM_FLAGS) | meth->meth; |
| 105 | vd->incr = incr; |
| 106 | vd->pool = 0; |
| 107 | vd->free = vd->wild = NIL(Block_t *); |
| 108 | |
| 109 | if (vd->mode & (VM_TRACE | VM_MTDEBUG)) |
| 110 | vd->mode &= ~VM_TRUST; |
| 111 | |
| 112 | if (vd->mode & (VM_MTBEST | VM_MTDEBUG | VM_MTPROFILE)) { |
| 113 | vd->root = NIL(Block_t *); |
| 114 | for (e = S_TINY - 1; e >= 0; --e) |
| 115 | TINY(vd)[e] = NIL(Block_t *); |
| 116 | for (e = S_CACHE; e >= 0; --e) |
| 117 | CACHE(vd)[e] = NIL(Block_t *); |
| 118 | incr = sizeof(Vmdata_t); |
| 119 | } else |
| 120 | incr = OFFSET(Vmdata_t, root); |
| 121 | |
| 122 | vd->seg = (Seg_t *) (addr + ROUND(incr, ALIGN)); |
| 123 | /**/ ASSERT(VLONG(vd->seg) % ALIGN == 0); |
| 124 | |
| 125 | seg = vd->seg; |
| 126 | seg->next = NIL(Seg_t *); |
| 127 | seg->vm = vm; |
| 128 | seg->addr = (void *) (addr - (a ? ALIGN - a : 0)); |
| 129 | seg->extent = s; |
| 130 | seg->baddr = addr + s - (a ? ALIGN : 0); |
| 131 | seg->size = s; /* this size is larger than usual so that the segment |
| 132 | will not be freed until the region is closed. */ |
| 133 | seg->free = NIL(Block_t *); |
| 134 | |
| 135 | /* make a data block out of the remainder */ |
| 136 | b = SEGBLOCK(seg); |
| 137 | SEG(b) = seg; |
| 138 | SIZE(b) = seg->baddr - (Vmuchar_t *) b - 2 * sizeof(Head_t); |
| 139 | *SELF(b) = b; |
| 140 | /**/ ASSERT(SIZE(b) % ALIGN == 0); |
| 141 | /**/ ASSERT(VLONG(b) % ALIGN == 0); |
| 142 | |
| 143 | /* make a fake header for next block in case of noncontiguous segments */ |
| 144 | SEG(NEXT(b)) = seg; |
| 145 | SIZE(NEXT(b)) = BUSY | PFREE; |
| 146 | |
| 147 | if (vd->mode & (VM_MTLAST | VM_MTPOOL)) |
| 148 | seg->free = b; |
| 149 | else |
| 150 | vd->wild = b; |
| 151 | |
| 152 | vm->data = vd; |
| 153 | |
| 154 | /* put into linked list of regions */ |
| 155 | vm->next = Vmheap->next; |
| 156 | Vmheap->next = vm; |
| 157 | |
| 158 | return vm; |
| 159 | } |
| 160 | |