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 | |