Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / vmalloc / vmprivate.c
1 /* $XConsortium: vmprivate.c /main/2 1996/05/08 20:04:31 drk $ */
2 /***************************************************************
3 *                                                              *
4 *                      AT&T - PROPRIETARY                      *
5 *                                                              *
6 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
7 *                          AT&T CORP.                          *
8 *                                                              *
9 *                Copyright (c) 1995 AT&T Corp.                 *
10 *                     All Rights Reserved                      *
11 *                                                              *
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        *
15 *                                                              *
16 *               This software was created by the               *
17 *           Software Engineering Research Department           *
18 *                    AT&T Bell Laboratories                    *
19 *                                                              *
20 *               For further information contact                *
21 *                     gsf@research.att.com                     *
22 *                                                              *
23 ***************************************************************/
24 #include        "vmhdr.h"
25
26 /*      Private code used in the vmalloc library
27 **
28 **      Written by (Kiem-)Phong Vo, kpv@research.att.com, 01/16/94.
29 */
30
31 /* Get more memory for a region */
32 #if __STD_C
33 static Block_t* vmextend(reg Vmalloc_t* vm, size_t size, Vmsearch_f searchf )
34 #else
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         */
39 #endif
40 {
41         reg size_t      s;
42         reg Seg_t*      seg;
43         reg Block_t     *bp, *t;
44         reg uchar*      addr;
45         reg Vmdata_t*   vd = vm->data;
46         reg Vmemory_f   memoryf = vm->disc->memoryf;
47         reg Vmexcept_f  exceptf = vm->disc->exceptf;
48
49         GETPAGESIZE(_Vmpagesize);
50
51         if(vd->incr <= 0) /* this is just _Vmheap on the first call */
52                 vd->incr = _Vmpagesize;
53
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 */
57                 return NIL(Block_t*);
58         if((size = ROUND(s,vd->incr)) < s)
59                 return NIL(Block_t*);
60
61         /* first see if we can extend the current segment */
62         if(!(seg = vd->seg) )
63                 addr = NIL(uchar*);
64         else
65         {       if(!vd->wild || SEG(vd->wild) != seg)
66                         s = 0;
67                 else
68                 {       s = SIZE(vd->wild) + sizeof(Head_t);
69                         if((s = (s/vd->incr)*vd->incr) == size)
70                                 size += vd->incr;
71                 }
72                 addr = (uchar*)(*memoryf)(vm,seg->addr,seg->extent,
73                                           seg->extent+size-s,vm->disc);
74                 if(addr)
75                 {       /**/ASSERT(addr == (uchar*)seg->addr);
76                         addr += seg->extent;
77                         size -= s;
78                 }
79         }
80
81         while(!addr)    /* try to get space */
82         {       if((addr = (uchar*)(*memoryf)(vm,NIL(Void_t*),0,size,vm->disc)) )
83                         break;
84
85                 /* check with exception handler to see if we should continue */
86                 if(!exceptf)
87                         return NIL(Block_t*);
88                 else
89                 {       int     rv, lock;
90                         lock = vd->mode&VM_LOCK;
91                         vd->mode &= ~VM_LOCK;
92                         rv = (*exceptf)(vm,VM_NOMEM,(Void_t*)size,vm->disc);
93                         vd->mode |= lock;
94                         if(rv <= 0)
95                         {       if(rv == 0)
96                                         vd->mode |= VM_AGAIN;
97                                 return NIL(Block_t*);
98                         }
99                 }
100         }
101
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) )
105                         break;
106         if(seg)
107         {       /* extending a current segment */
108                 bp = BLOCK(seg->baddr); /**/ ASSERT((SIZE(bp)&~BITS) == 0);
109                                         /**/ ASSERT(SEG(bp) == seg);
110
111                 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE) )
112                 {       if(!ISPFREE(SIZE(bp)) )
113                                 SIZE(bp) = size - sizeof(Head_t);
114                         else
115                         {       /**/ ASSERT(searchf);
116                                 bp = LAST(bp);
117                                 if(bp == vd->wild)
118                                         vd->wild = NIL(Block_t*);
119                                 else    DELETE(vd,bp,INDEX(SIZE(bp)),t,(*searchf));
120                                 SIZE(bp) += size;
121                         }
122                 }
123                 else
124                 {       if(seg->free)
125                         {       bp = seg->free;
126                                 seg->free = NIL(Block_t*);
127                                 SIZE(bp) += size;
128                         }
129                         else    SIZE(bp) = size - sizeof(Head_t);
130                 }
131
132                 seg->size += size;
133                 seg->extent += size;
134                 seg->baddr += size;
135         }
136         else
137         {       /* creating a new segment */
138                 reg Seg_t       *sp, *lastsp;
139
140                 if((s = (size_t)(ULONG(addr)%ALIGN)) != 0)
141                         addr += ALIGN-s;
142
143                 seg = (Seg_t*)addr;
144                 seg->vm = vm;
145                 seg->addr = (Void_t*)(addr - (s ? ALIGN-s : 0));
146                 seg->extent = size;
147                 seg->baddr = addr + size - (s ? 2*ALIGN : 0);
148                 seg->free = NIL(Block_t*);
149                 bp = SEGBLOCK(seg);
150                 SEG(bp) = seg;
151                 SIZE(bp) = seg->baddr - (uchar*)bp - 2*sizeof(Head_t);
152
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.
156                 */
157                 lastsp = NIL(Seg_t*);
158                 sp = vd->seg;
159                 if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE))
160                         for(; sp; lastsp = sp, sp = sp->next)
161                                 if(seg->addr > sp->addr)
162                                         break;
163                 seg->next = sp;
164                 if(lastsp)
165                         lastsp->next = seg;
166                 else    vd->seg = seg;
167
168                 seg->size = SIZE(bp);
169         }
170
171         /* make a fake header for possible segmented memory */
172         t = NEXT(bp);
173         SEG(t) = seg;
174         SIZE(t) = BUSY;
175
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;
183                 }
184                 else    seg->free = t;
185
186                 vd->wild = NIL(Block_t*);
187         }
188
189         return bp;
190 }
191
192 /* Truncate a segment if possible */
193 #if __STD_C
194 vmtruncate(Vmalloc_t* vm, Seg_t* seg, size_t size, int exact)
195 #else
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       */
201 #endif
202 {
203         reg Void_t*     caddr;
204         reg Seg_t*      last;
205         reg Vmdata_t*   vd = vm->data;
206         reg Vmemory_f   memoryf = vm->disc->memoryf;
207
208         caddr = seg->addr;
209
210         if(size < seg->size)
211         {       reg size_t      less;
212
213                 /* the truncated amount must satisfy the discipline requirement */
214                 if((less = vm->disc->round) <= 0)
215                         less = _Vmpagesize;
216                 less = (size/less)*less;
217                 less = (less/ALIGN)*ALIGN;
218
219                 if(!exact)      /* only truncate multiples of incr */
220                         less = (less/vd->incr)*vd->incr;
221
222                 if(less > 0 && size > less && (size-less) < sizeof(Block_t) )
223                         less -= vd->incr;
224
225                 if(less <= 0 ||
226                    (*memoryf)(vm,caddr,seg->extent,seg->extent-less,vm->disc) != caddr)
227                         return -1;
228
229                 seg->extent -= less;
230                 seg->size -= less;
231                 seg->baddr -= less;
232                 SIZE(BLOCK(seg->baddr)) = BUSY;
233                 return 0;
234         }
235
236         /* unlink segment from region */
237         if(seg == vd->seg)
238         {       vd->seg = seg->next;
239                 last = NIL(Seg_t*);
240         }
241         else
242         {       for(last = vd->seg; last->next != seg; last = last->next)
243                         ;
244                 last->next = seg->next;
245         }
246
247         /* now delete it */
248         if((*memoryf)(vm,caddr,seg->extent,0,vm->disc) == caddr)
249                 return 0;
250
251         /* space reduction failed, reinsert segment */
252         if(last)
253         {       seg->next = last->next;
254                 last->next = seg;
255         }
256         else
257         {       seg->next = vd->seg;
258                 vd->seg = seg;
259         }
260         return -1;
261 }
262
263 /* Externally visible names but local to library */
264 Vmextern_t      _Vmextern =
265 {       
266         vmextend,                                               /* _Vmextend    */
267         vmtruncate,                                             /* _Vmtruncate  */
268         0,                                                      /* _Vmpagesize  */
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   */
273 };
274
275 char*   _Vmfile;        /* current file */
276 int     _Vmline;        /* current line */