1 /* $XConsortium: vmprivate.c /main/2 1996/05/08 20:04:31 drk $ */
2 /***************************************************************
6 * THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
9 * Copyright (c) 1995 AT&T Corp. *
10 * All Rights Reserved *
12 * This software is licensed by AT&T Corp. *
13 * under the terms and conditions of the license in *
14 * http://www.research.att.com/orgs/ssr/book/reuse *
16 * This software was created by the *
17 * Software Engineering Research Department *
18 * AT&T Bell Laboratories *
20 * For further information contact *
21 * gsf@research.att.com *
23 ***************************************************************/
26 /* Private code used in the vmalloc library
28 ** Written by (Kiem-)Phong Vo, kpv@research.att.com, 01/16/94.
31 /* Get more memory for a region */
33 static Block_t* vmextend(reg Vmalloc_t* vm, size_t size, Vmsearch_f searchf )
35 static Block_t* vmextend(vm, size, searchf )
36 reg Vmalloc_t* vm; /* region to increase in size */
37 size_t size; /* desired amount of space */
38 Vmsearch_f searchf; /* tree search function */
45 reg Vmdata_t* vd = vm->data;
46 reg Vmemory_f memoryf = vm->disc->memoryf;
47 reg Vmexcept_f exceptf = vm->disc->exceptf;
49 GETPAGESIZE(_Vmpagesize);
51 if(vd->incr <= 0) /* this is just _Vmheap on the first call */
52 vd->incr = _Vmpagesize;
54 /* Get slightly more for administrative data */
55 s = size + sizeof(Seg_t) + sizeof(Block_t) + sizeof(Head_t) + 2*ALIGN;
56 if(s <= size) /* size was too large and we have wrapped around */
58 if((size = ROUND(s,vd->incr)) < s)
61 /* first see if we can extend the current segment */
65 { if(!vd->wild || SEG(vd->wild) != seg)
68 { s = SIZE(vd->wild) + sizeof(Head_t);
69 if((s = (s/vd->incr)*vd->incr) == size)
72 addr = (uchar*)(*memoryf)(vm,seg->addr,seg->extent,
73 seg->extent+size-s,vm->disc);
75 { /**/ASSERT(addr == (uchar*)seg->addr);
81 while(!addr) /* try to get space */
82 { if((addr = (uchar*)(*memoryf)(vm,NIL(Void_t*),0,size,vm->disc)) )
85 /* check with exception handler to see if we should continue */
90 lock = vd->mode&VM_LOCK;
92 rv = (*exceptf)(vm,VM_NOMEM,(Void_t*)size,vm->disc);
102 /* search segment list to see if this is attachable to any of them */
103 for(seg = vd->seg; seg; seg = seg->next)
104 if(addr == ((uchar*)seg->addr+seg->extent) )
107 { /* extending a current segment */
108 bp = BLOCK(seg->baddr); /**/ ASSERT((SIZE(bp)&~BITS) == 0);
109 /**/ ASSERT(SEG(bp) == seg);
111 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE) )
112 { if(!ISPFREE(SIZE(bp)) )
113 SIZE(bp) = size - sizeof(Head_t);
115 { /**/ ASSERT(searchf);
118 vd->wild = NIL(Block_t*);
119 else DELETE(vd,bp,INDEX(SIZE(bp)),t,(*searchf));
126 seg->free = NIL(Block_t*);
129 else SIZE(bp) = size - sizeof(Head_t);
137 { /* creating a new segment */
138 reg Seg_t *sp, *lastsp;
140 if((s = (size_t)(ULONG(addr)%ALIGN)) != 0)
145 seg->addr = (Void_t*)(addr - (s ? ALIGN-s : 0));
147 seg->baddr = addr + size - (s ? 2*ALIGN : 0);
148 seg->free = NIL(Block_t*);
151 SIZE(bp) = seg->baddr - (uchar*)bp - 2*sizeof(Head_t);
153 /* NOTE: for Vmbest, Vmdebug and Vmprofile the region's segment list
154 is reversely ordered by addresses. This is so that we can easily
155 check for the wild block.
157 lastsp = NIL(Seg_t*);
159 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE))
160 for(; sp; lastsp = sp, sp = sp->next)
161 if(seg->addr > sp->addr)
168 seg->size = SIZE(bp);
171 /* make a fake header for possible segmented memory */
176 /* see if the wild block is still wild */
177 if((t = vd->wild) && (seg = SEG(t)) != vd->seg)
178 { CLRPFREE(SIZE(NEXT(t)));
179 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE) )
180 { SIZE(t) |= BUSY|JUNK;
181 LINK(t) = CACHE(vd)[C_INDEX(SIZE(t))];
182 CACHE(vd)[C_INDEX(SIZE(t))] = t;
186 vd->wild = NIL(Block_t*);
192 /* Truncate a segment if possible */
194 vmtruncate(Vmalloc_t* vm, Seg_t* seg, size_t size, int exact)
196 vmtruncate(vm, seg, size, exact)
197 Vmalloc_t* vm; /* containing region */
198 Seg_t* seg; /* the one to be truncated */
199 size_t size; /* amount of free space */
200 int exact; /* amount given was exact */
205 reg Vmdata_t* vd = vm->data;
206 reg Vmemory_f memoryf = vm->disc->memoryf;
213 /* the truncated amount must satisfy the discipline requirement */
214 if((less = vm->disc->round) <= 0)
216 less = (size/less)*less;
217 less = (less/ALIGN)*ALIGN;
219 if(!exact) /* only truncate multiples of incr */
220 less = (less/vd->incr)*vd->incr;
222 if(less > 0 && size > less && (size-less) < sizeof(Block_t) )
226 (*memoryf)(vm,caddr,seg->extent,seg->extent-less,vm->disc) != caddr)
232 SIZE(BLOCK(seg->baddr)) = BUSY;
236 /* unlink segment from region */
238 { vd->seg = seg->next;
242 { for(last = vd->seg; last->next != seg; last = last->next)
244 last->next = seg->next;
248 if((*memoryf)(vm,caddr,seg->extent,0,vm->disc) == caddr)
251 /* space reduction failed, reinsert segment */
253 { seg->next = last->next;
257 { seg->next = vd->seg;
263 /* Externally visible names but local to library */
264 Vmextern_t _Vmextern =
266 vmextend, /* _Vmextend */
267 vmtruncate, /* _Vmtruncate */
269 NIL(char*(*)_ARG_((char*,char*,int))), /* _Vmstrcpy */
270 NIL(char*(*)_ARG_((ulong,int))), /* _Vmitoa */
271 NIL(void(*)_ARG_((Vmalloc_t*,uchar*,uchar*,size_t))), /* _Vmtrace */
272 NIL(void(*)_ARG_((Vmalloc_t*))) /* _Vmpfclose */
275 char* _Vmfile; /* current file */
276 int _Vmline; /* current line */