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