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
24typedef 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 */
37Vmalloc_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