1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
23
_STUB_vmprivate()24 void _STUB_vmprivate(){}
25
26 #else
27
28 #include "vmhdr.h"
29
30 static char* Version = "\n@(#)$Id: Vmalloc (AT&T Labs - Research) 2011-08-08 $\0\n";
31
32
33 /* Private code used in the vmalloc library
34 **
35 ** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
36 */
37
38 /* Get more memory for a region */
39 #if __STD_C
_vmextend(reg Vmalloc_t * vm,size_t size,Vmsearch_f searchf)40 static Block_t* _vmextend(reg Vmalloc_t* vm, size_t size, Vmsearch_f searchf )
41 #else
42 static Block_t* _vmextend(vm, size, searchf )
43 reg Vmalloc_t* vm; /* region to increase in size */
44 size_t size; /* desired amount of space */
45 Vmsearch_f searchf; /* tree search function */
46 #endif
47 {
48 reg size_t s;
49 reg Seg_t* seg;
50 reg Block_t *bp, *tp, *np;
51 reg Vmuchar_t* addr = (Vmuchar_t*)Version; /* shut compiler warning */
52 reg Vmdata_t* vd = vm->data;
53
54 GETPAGESIZE(_Vmpagesize);
55
56 if(vd->incr <= 0) /* this is just _Vmheap on the first call */
57 vd->incr = _Vmpagesize*sizeof(Void_t*);
58
59 /* Get slightly more for administrative data */
60 s = size + sizeof(Seg_t) + sizeof(Block_t) + sizeof(Head_t) + 2*ALIGN;
61 if(s <= size) /* size was too large and we have wrapped around */
62 return NIL(Block_t*);
63 if((size = ROUND(s,vd->incr)) < s)
64 return NIL(Block_t*);
65
66 /* increase the rounding factor to reduce # of future extensions */
67 if(size > 2*vd->incr && vm->disc->round < vd->incr)
68 vd->incr *= 2;
69
70 if(!(seg = vd->seg) ) /* there is no current segment */
71 addr = NIL(Vmuchar_t*);
72 else /* see if we can extend the current segment */
73 { addr = (Vmuchar_t*)(*vm->disc->memoryf)(vm,seg->addr,seg->extent,
74 seg->extent+size,vm->disc);
75 if(addr == (Vmuchar_t*)seg->addr)
76 addr += seg->extent; /* seg successfully extended */
77 else seg = NIL(Seg_t*); /* a new segment was created */
78 }
79
80 if(!addr) /* create a new segment */
81 { if(!(addr = (Vmuchar_t*)(*vm->disc->memoryf)(vm, NIL(Void_t*), 0, size, vm->disc)) )
82 { if(vm->disc->exceptf) /* announce that no more memory is available */
83 {
84 CLRLOCK(vm, 0);
85 (void)(*vm->disc->exceptf)(vm, VM_NOMEM, (Void_t*)size, vm->disc);
86 SETLOCK(vm, 0);
87 }
88 return NIL(Block_t*);
89 }
90 }
91
92 if(seg)
93 { /* extending current segment */
94 bp = BLOCK(seg->baddr);
95
96 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE) )
97 { /**/ ASSERT((SIZE(bp)&~BITS) == 0);
98 /**/ ASSERT(SEG(bp) == seg);
99
100 if(!ISPFREE(SIZE(bp)) )
101 SIZE(bp) = size - sizeof(Head_t);
102 else
103 { /**/ ASSERT(searchf);
104 bp = LAST(bp);
105 if(bp == vd->wild)
106 vd->wild = NIL(Block_t*);
107 else REMOVE(vd,bp,INDEX(SIZE(bp)),tp,(*searchf));
108 SIZE(bp) += size;
109 }
110 }
111 else
112 { if(seg->free)
113 { bp = seg->free;
114 seg->free = NIL(Block_t*);
115 SIZE(bp) += size;
116 }
117 else
118 { SEG(bp) = seg;
119 SIZE(bp) = size - sizeof(Head_t);
120 }
121 }
122
123 seg->size += size;
124 seg->extent += size;
125 seg->baddr += size;
126 }
127 else
128 { /* creating a new segment */
129 reg Seg_t *sp, *lastsp;
130
131 if((s = (size_t)(VLONG(addr)%ALIGN)) != 0)
132 addr += ALIGN-s;
133
134 seg = (Seg_t*)addr;
135 seg->vmdt = vd;
136 seg->addr = (Void_t*)(addr - (s ? ALIGN-s : 0));
137 seg->extent = size;
138 seg->baddr = addr + size - (s ? 2*ALIGN : 0);
139 seg->free = NIL(Block_t*);
140 bp = SEGBLOCK(seg);
141 SEG(bp) = seg;
142 SIZE(bp) = seg->baddr - (Vmuchar_t*)bp - 2*sizeof(Head_t);
143
144 /* NOTE: for Vmbest, Vmdebug and Vmprofile the region's segment list
145 is reversely ordered by addresses. This is so that we can easily
146 check for the wild block.
147 */
148 lastsp = NIL(Seg_t*);
149 sp = vd->seg;
150 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE))
151 for(; sp; lastsp = sp, sp = sp->next)
152 if(seg->addr > sp->addr)
153 break;
154 seg->next = sp;
155 if(lastsp)
156 lastsp->next = seg;
157 else vd->seg = seg;
158
159 seg->size = SIZE(bp);
160 }
161
162 /* make a fake header for possible segmented memory */
163 tp = NEXT(bp);
164 SEG(tp) = seg;
165 SIZE(tp) = BUSY;
166
167 /* see if the wild block is still wild */
168 if((tp = vd->wild) && (seg = SEG(tp)) != vd->seg)
169 { np = NEXT(tp);
170 CLRPFREE(SIZE(np));
171 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE) )
172 { SIZE(tp) |= BUSY|JUNK;
173 LINK(tp) = CACHE(vd)[C_INDEX(SIZE(tp))];
174 CACHE(vd)[C_INDEX(SIZE(tp))] = tp;
175 }
176 else seg->free = tp;
177
178 vd->wild = NIL(Block_t*);
179 }
180
181 return bp;
182 }
183
184 /* Truncate a segment if possible */
185 #if __STD_C
_vmtruncate(Vmalloc_t * vm,Seg_t * seg,size_t size,int exact)186 static ssize_t _vmtruncate(Vmalloc_t* vm, Seg_t* seg, size_t size, int exact)
187 #else
188 static ssize_t _vmtruncate(vm, seg, size, exact)
189 Vmalloc_t* vm; /* containing region */
190 Seg_t* seg; /* the one to be truncated */
191 size_t size; /* amount of free space */
192 int exact;
193 #endif
194 {
195 reg Void_t* caddr;
196 reg Seg_t* last;
197 reg Vmdata_t* vd = vm->data;
198 reg Vmemory_f memoryf = vm->disc->memoryf;
199
200 caddr = seg->addr;
201
202 if(size < seg->size)
203 { reg ssize_t less;
204
205 if(exact)
206 less = size;
207 else /* keep truncated amount to discipline requirements */
208 { if((less = vm->disc->round) <= 0)
209 less = _Vmpagesize;
210 less = (size/less)*less;
211 less = (less/vd->incr)*vd->incr;
212 if(less > 0 && (ssize_t)size > less && (size-less) < sizeof(Block_t) )
213 less = less <= (ssize_t)vd->incr ? 0 : less - vd->incr;
214 }
215
216 if(less <= 0 ||
217 (*memoryf)(vm,caddr,seg->extent,seg->extent-less,vm->disc) != caddr)
218 return 0;
219
220 seg->extent -= less;
221 seg->size -= less;
222 seg->baddr -= less;
223 SEG(BLOCK(seg->baddr)) = seg;
224 SIZE(BLOCK(seg->baddr)) = BUSY;
225
226 return less;
227 }
228 else
229 { /* unlink segment from region */
230 if(seg == vd->seg)
231 { vd->seg = seg->next;
232 last = NIL(Seg_t*);
233 }
234 else
235 { for(last = vd->seg; last->next != seg; last = last->next)
236 ;
237 last->next = seg->next;
238 }
239
240 /* now delete it */
241 if((*memoryf)(vm,caddr,seg->extent,0,vm->disc) == caddr)
242 return size;
243
244 /* space reduction failed, reinsert segment */
245 if(last)
246 { seg->next = last->next;
247 last->next = seg;
248 }
249 else
250 { seg->next = vd->seg;
251 vd->seg = seg;
252 }
253 return 0;
254 }
255 }
256
_vmlock(Vmalloc_t * vm,int locking)257 int _vmlock(Vmalloc_t* vm, int locking)
258 {
259 if(!vm) /* some sort of global locking */
260 { if(!locking) /* turn off lock */
261 asolock(&_Vmlock, 1, ASO_UNLOCK);
262 else asolock(&_Vmlock, 1, ASO_SPINLOCK);
263 }
264 else if(vm->data->mode&VM_SHARE)
265 { if(!locking) /* turning off the lock */
266 asolock(&vm->data->lock, 1, ASO_UNLOCK);
267 else asolock(&vm->data->lock, 1, ASO_SPINLOCK);
268 }
269 else
270 { if(!locking)
271 vm->data->lock = 0;
272 else vm->data->lock = 1;
273 }
274 return 0;
275 }
276
277
278 /* Externally visible names but local to library */
279 Vmextern_t _Vmextern =
280 { _vmextend, /* _Vmextend */
281 _vmtruncate, /* _Vmtruncate */
282 0, /* _Vmpagesize */
283 NIL(char*(*)_ARG_((char*,const char*,int))), /* _Vmstrcpy */
284 NIL(char*(*)_ARG_((Vmulong_t,int))), /* _Vmitoa */
285 NIL(void(*)_ARG_((Vmalloc_t*,
286 Vmuchar_t*,Vmuchar_t*,size_t,size_t))), /* _Vmtrace */
287 NIL(void(*)_ARG_((Vmalloc_t*))) /* _Vmpfclose */
288 };
289
290 #endif
291