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