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_vmlast()24 void _STUB_vmlast(){}
25 
26 #else
27 
28 #include	"vmhdr.h"
29 
30 /*	Allocation with freeing and reallocing of last allocated block only.
31 **
32 **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
33 */
34 
35 #if __STD_C
lastalloc(Vmalloc_t * vm,size_t size,int local)36 static Void_t* lastalloc(Vmalloc_t* vm, size_t size, int local)
37 #else
38 static Void_t* lastalloc(vm, size, local)
39 Vmalloc_t*	vm;
40 size_t		size;
41 int		local;
42 #endif
43 {
44 	Block_t		*tp, *next;
45 	Seg_t		*seg, *last;
46 	size_t		s;
47 	Vmdata_t	*vd = vm->data;
48 	size_t		orgsize = size;
49 
50 	SETLOCK(vm, local);
51 
52 	size = size < ALIGN ? ALIGN : ROUND(size,ALIGN);
53 	for(last = NIL(Seg_t*), seg = vd->seg; seg; last = seg, seg = seg->next)
54 	{	if(!(tp = seg->free) || (SIZE(tp)+sizeof(Head_t)) < size)
55 			continue;
56 		if(last)
57 		{	last->next = seg->next;
58 			seg->next = vd->seg;
59 			vd->seg = seg;
60 		}
61 		goto got_block;
62 	}
63 
64 	/* there is no usable free space in region, try extending */
65 	if((tp = (*_Vmextend)(vm,size,NIL(Vmsearch_f))) )
66 	{	seg = SEG(tp);
67 		goto got_block;
68 	}
69 	else	goto done;
70 
71 got_block:
72 	if((s = SIZE(tp)) >= size)
73 	{	next = (Block_t*)((Vmuchar_t*)tp+size);
74 		SIZE(next) = s - size;
75 		SEG(next) = seg;
76 		seg->free = next;
77 	}
78 	else	seg->free = NIL(Block_t*);
79 
80 	vd->free = seg->last = tp;
81 
82 	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
83 		(*_Vmtrace)(vm, NIL(Vmuchar_t*), (Vmuchar_t*)tp, orgsize, 0);
84 
85 done:
86 	CLRLOCK(vm, local);
87 
88 	return (Void_t*)tp;
89 }
90 
91 #if __STD_C
lastfree(Vmalloc_t * vm,reg Void_t * data,int local)92 static int lastfree(Vmalloc_t* vm, reg Void_t* data, int local )
93 #else
94 static int lastfree(vm, data, local)
95 Vmalloc_t*	vm;
96 Void_t*		data;
97 int		local;
98 #endif
99 {
100 	Seg_t		*seg;
101 	Block_t		*fp;
102 	size_t		s;
103 	Vmdata_t	*vd = vm->data;
104 
105 	if(!data)
106 		return 0;
107 
108 	SETLOCK(vm, local);
109 
110 	if(data != (Void_t*)vd->free)
111 		data = NIL(Void_t*); /* signaling an error */
112 	else
113 	{	seg = vd->seg;
114 		if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
115 		{	if(seg->free )
116 				s = (Vmuchar_t*)(seg->free) - (Vmuchar_t*)data;
117 			else	s = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
118 			(*_Vmtrace)(vm, (Vmuchar_t*)data, NIL(Vmuchar_t*), s, 0);
119 		}
120 
121 		vd->free = NIL(Block_t*);
122 		fp = (Block_t*)data;
123 		SEG(fp)  = seg;
124 		SIZE(fp) = ((Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data) - sizeof(Head_t);
125 		seg->free = fp;
126 		seg->last = NIL(Block_t*);
127 	}
128 
129 	CLRLOCK(vm, local);
130 
131 	return data ? 0 : -1;
132 }
133 
134 #if __STD_C
lastresize(Vmalloc_t * vm,reg Void_t * data,size_t size,int type,int local)135 static Void_t* lastresize(Vmalloc_t* vm, reg Void_t* data, size_t size, int type, int local)
136 #else
137 static Void_t* lastresize(vm, data, size, type, local )
138 Vmalloc_t*	vm;
139 reg Void_t*	data;
140 size_t		size;
141 int		type;
142 int		local;
143 #endif
144 {
145 	Block_t		*tp;
146 	Seg_t		*seg;
147 	ssize_t		s, ds;
148 	Void_t		*addr;
149 	size_t		oldsize = 0;
150 	Void_t		*orgdata = data;
151 	size_t		orgsize = size;
152 	Vmdata_t	*vd = vm->data;
153 
154 	if(!data)
155 	{	data = lastalloc(vm, size, local);
156 		if(data && (type&VM_RSZERO) )
157 			memset(data, 0, size);
158 		return data;
159 	}
160 	if(size <= 0)
161 	{	(void)lastfree(vm, data, local);
162 		return NIL(Void_t*);
163 	}
164 
165 	SETLOCK(vm, local);
166 
167 	if(data == (Void_t*)vd->free)
168 		seg = vd->seg;
169 	else
170 	{	/* see if it was one of ours */
171 		for(seg = vd->seg; seg; seg = seg->next)
172 			if(data >= seg->addr && data < (Void_t*)seg->baddr)
173 				break;
174 		if(!seg || (VLONG(data)%ALIGN) != 0 ||
175 		   (seg->last && (Vmuchar_t*)data > (Vmuchar_t*)seg->last) )
176 		{	data = NIL(Void_t*);
177 			goto done;
178 		}
179 	}
180 
181 	/* set 's' to be the current available space */
182 	if(data != seg->last)
183 	{	if(seg->last && (Vmuchar_t*)data < (Vmuchar_t*)seg->last)
184 			oldsize = (Vmuchar_t*)seg->last - (Vmuchar_t*)data;
185 		else	oldsize = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
186 		s = -1;
187 	}
188 	else
189 	{	s = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
190 		if(!(tp = seg->free) )
191 			oldsize = s;
192 		else
193 		{	oldsize = (Vmuchar_t*)tp - (Vmuchar_t*)data;
194 			seg->free = NIL(Block_t*);
195 		}
196 	}
197 
198 	size = size < ALIGN ? ALIGN : ROUND(size,ALIGN);
199 	if(s < 0 || (ssize_t)size > s)
200 	{	if(s >= 0) /* amount to extend */
201 		{	ds = size-s; ds = ROUND(ds,vd->incr);
202 			addr = (*vm->disc->memoryf)(vm, seg->addr, seg->extent,
203 						    seg->extent+ds, vm->disc);
204 			if(addr == seg->addr)
205 			{	s += ds;
206 				seg->size += ds;
207 				seg->extent += ds;
208 				seg->baddr += ds;
209 				SIZE(BLOCK(seg->baddr)) = BUSY;
210 			}
211 			else	goto do_alloc;
212 		}
213 		else
214 		{ do_alloc:
215 			if(!(type&(VM_RSMOVE|VM_RSCOPY)) )
216 				data = NIL(Void_t*);
217 			else
218 			{	tp = vd->free;
219 				if(!(addr = KPVALLOC(vm,size,lastalloc)) )
220 				{	vd->free = tp;
221 					data = NIL(Void_t*);
222 				}
223 				else
224 				{	if(type&VM_RSCOPY)
225 					{	ds = oldsize < size ? oldsize : size;
226 						memcpy(addr, data, ds);
227 					}
228 
229 					if(s >= 0 && seg != vd->seg)
230 					{	tp = (Block_t*)data;
231 						SEG(tp) = seg;
232 						SIZE(tp) = s - sizeof(Head_t);
233 						seg->free = tp;
234 					}
235 
236 					/* new block and size */
237 					data = addr;
238 					seg = vd->seg;
239 					s = (Vmuchar_t*)BLOCK(seg->baddr) -
240 					    (Vmuchar_t*)data;
241 					seg->free = NIL(Block_t*);
242 				}
243 			}
244 		}
245 	}
246 
247 	if(data)
248 	{	if(s >= (ssize_t)(size+sizeof(Head_t)) )
249 		{	tp = (Block_t*)((Vmuchar_t*)data + size);
250 			SEG(tp) = seg;
251 			SIZE(tp) = (s - size) - sizeof(Head_t);
252 			seg->free = tp;
253 		}
254 
255 		vd->free = seg->last = (Block_t*)data;
256 
257 		if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
258 			(*_Vmtrace)(vm,(Vmuchar_t*)orgdata,(Vmuchar_t*)data,orgsize,0);
259 
260 		if((type&VM_RSZERO) && size > oldsize)
261 			memset((Void_t*)((Vmuchar_t*)data + oldsize), 0, size-oldsize);
262 	}
263 
264 done:	CLRLOCK(vm, local);
265 
266 	return data;
267 }
268 
269 
270 #if __STD_C
lastaddr(Vmalloc_t * vm,Void_t * addr,int local)271 static long lastaddr(Vmalloc_t* vm, Void_t* addr, int local)
272 #else
273 static long lastaddr(vm, addr, local)
274 Vmalloc_t*	vm;
275 Void_t*		addr;
276 int		local;
277 #endif
278 {
279 	long		offset;
280 	Vmdata_t	*vd = vm->data;
281 
282 	SETLOCK(vm, local);
283 
284 	if(!vd->free || addr < (Void_t*)vd->free || addr >= (Void_t*)vd->seg->baddr)
285 		offset = -1L;
286 	else	offset = (long)((Vmuchar_t*)addr - (Vmuchar_t*)vd->free);
287 
288 	CLRLOCK(vm, local);
289 
290 	return offset;
291 }
292 
293 #if __STD_C
lastsize(Vmalloc_t * vm,Void_t * addr,int local)294 static long lastsize(Vmalloc_t* vm, Void_t* addr, int local)
295 #else
296 static long lastsize(vm, addr, local)
297 Vmalloc_t*	vm;
298 Void_t*		addr;
299 int		local;
300 #endif
301 {
302 	long		size;
303 	Vmdata_t	*vd = vm->data;
304 
305 	SETLOCK(vm, local);
306 
307 	if(!vd->free || addr != (Void_t*)vd->free )
308 		size = -1L;
309 	else if(vd->seg->free)
310 		size = (long)((Vmuchar_t*)vd->seg->free - (Vmuchar_t*)addr);
311 	else	size = (long)((Vmuchar_t*)vd->seg->baddr - (Vmuchar_t*)addr - sizeof(Head_t));
312 
313 	CLRLOCK(vm, local);
314 
315 	return size;
316 }
317 
318 #if __STD_C
lastcompact(Vmalloc_t * vm,int local)319 static int lastcompact(Vmalloc_t* vm, int local)
320 #else
321 static int lastcompact(vm, local)
322 Vmalloc_t*	vm;
323 int		local;
324 #endif
325 {
326 	ssize_t		s;
327 	Block_t		*fp;
328 	Seg_t		*seg, *next;
329 	Vmdata_t	*vd = vm->data;
330 
331 	SETLOCK(vm, local);
332 
333 	for(seg = vd->seg; seg; seg = next)
334 	{	next = seg->next;
335 
336 		if(!(fp = seg->free))
337 			continue;
338 
339 		seg->free = NIL(Block_t*);
340 		if(seg->size == (s = SIZE(fp)&~BITS))
341 			s = seg->extent;
342 		else	s += sizeof(Head_t);
343 
344 		if((*_Vmtruncate)(vm,seg,s,1) == s)
345 			seg->free = fp;
346 	}
347 
348 	if((vd->mode&VM_TRACE) && _Vmtrace)
349 		(*_Vmtrace)(vm,(Vmuchar_t*)0,(Vmuchar_t*)0,0,0);
350 
351 	CLRLOCK(vm, local);
352 	return 0;
353 }
354 
355 #if __STD_C
lastalign(Vmalloc_t * vm,size_t size,size_t align,int local)356 static Void_t* lastalign(Vmalloc_t* vm, size_t size, size_t align, int local)
357 #else
358 static Void_t* lastalign(vm, size, align, local)
359 Vmalloc_t*	vm;
360 size_t		size;
361 size_t		align;
362 int		local;
363 #endif
364 {
365 	Vmuchar_t	*data;
366 	Seg_t		*seg;
367 	Block_t		*next;
368 	size_t		s, orgsize = size, orgalign = align;
369 	Vmdata_t	*vd = vm->data;
370 
371 	if(size <= 0 || align <= 0)
372 		return NIL(Void_t*);
373 
374 	SETLOCK(vm, local);
375 
376 	size = size <= TINYSIZE ? TINYSIZE : ROUND(size,ALIGN);
377 	align = MULTIPLE(align,ALIGN);
378 
379 	s = size + align;
380 	if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,lastalloc)) )
381 		goto done;
382 
383 	/* find the segment containing this block */
384 	for(seg = vd->seg; seg; seg = seg->next)
385 		if(seg->last == (Block_t*)data)
386 			break;
387 	/**/ASSERT(seg);
388 
389 	/* get a suitably aligned address */
390 	if((s = (size_t)(VLONG(data)%align)) != 0)
391 		data += align-s; /**/ASSERT((VLONG(data)%align) == 0);
392 
393 	/* free the unused tail */
394 	next = (Block_t*)(data+size);
395 	if((s = (seg->baddr - (Vmuchar_t*)next)) >= sizeof(Block_t))
396 	{	SEG(next) = seg;
397 		SIZE(next) = s - sizeof(Head_t);
398 		seg->free = next;
399 	}
400 
401 	vd->free = seg->last = (Block_t*)data;
402 
403 	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
404 		(*_Vmtrace)(vm,NIL(Vmuchar_t*),data,orgsize,orgalign);
405 
406 done:
407 	CLRLOCK(vm, local);
408 
409 	return (Void_t*)data;
410 }
411 
412 /* Public method for free-1 allocation */
413 static Vmethod_t _Vmlast =
414 {
415 	lastalloc,
416 	lastresize,
417 	lastfree,
418 	lastaddr,
419 	lastsize,
420 	lastcompact,
421 	lastalign,
422 	VM_MTLAST
423 };
424 
425 __DEFINE__(Vmethod_t*,Vmlast,&_Vmlast);
426 
427 #ifdef NoF
428 NoF(vmlast)
429 #endif
430 
431 #endif
432