1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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
24void _STUB_vmpool(){}
25
26#else
27
28#include	"vmhdr.h"
29
30#define POOLFREE	0x55555555L	/* block free indicator	 */
31
32/*	Method for pool allocation.
33**	All elements in a pool have the same size.
34**	The following fields of Vmdata_t are used as:
35**		pool:	size of a block.
36**		free:	list of free blocks.
37**
38**	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
39*/
40
41#if __STD_C
42static Void_t* poolalloc(Vmalloc_t* vm, reg size_t size)
43#else
44static Void_t* poolalloc(vm, size )
45Vmalloc_t*	vm;
46reg size_t	size;
47#endif
48{
49	reg Vmdata_t*	vd = vm->data;
50	reg Block_t	*tp, *next;
51	reg size_t	s;
52	reg Seg_t*	seg;
53	reg int		local, inuse;
54
55	if(size <= 0)
56		return NIL(Void_t*);
57	if(size != vd->pool)
58	{	if(vd->pool <= 0)
59			vd->pool = size;
60		else	return NIL(Void_t*);
61	}
62
63	SETINUSE(vd, inuse);
64	if(!(local = vd->mode&VM_TRUST) )
65	{	GETLOCAL(vd,local);
66		if(ISLOCK(vd, local))
67		{	CLRINUSE(vd, inuse);
68			return NIL(Void_t*);
69		}
70		SETLOCK(vd, local);
71	}
72
73	if((tp = vd->free) ) /* there is a ready free block */
74	{	vd->free = SEGLINK(tp);
75		goto done;
76	}
77
78	size = ROUND(size,ALIGN);
79
80	/* look thru all segments for a suitable free block */
81	for(tp = NIL(Block_t*), seg = vd->seg; seg; seg = seg->next)
82	{	if((tp = seg->free) &&
83		   (s = (SIZE(tp) & ~BITS) + sizeof(Head_t)) >= size )
84			goto has_blk;
85	}
86
87	for(;;) /* must extend region */
88	{	if((tp = (*_Vmextend)(vm,ROUND(size,vd->incr),NIL(Vmsearch_f))) )
89		{	s = (SIZE(tp) & ~BITS) + sizeof(Head_t);
90			seg = SEG(tp);
91			goto has_blk;
92		}
93		else if(vd->mode&VM_AGAIN)
94			vd->mode &= ~VM_AGAIN;
95		else	goto done;
96	}
97
98has_blk: /* if get here, (tp, s, seg) must be well-defined */
99	next = (Block_t*)((Vmuchar_t*)tp+size);
100	if((s -= size) <= (size + sizeof(Head_t)) )
101	{	for(; s >= size; s -= size)
102		{	SIZE(next) = POOLFREE;
103			SEGLINK(next) = vd->free;
104			vd->free = next;
105			next = (Block_t*)((Vmuchar_t*)next + size);
106		}
107		seg->free = NIL(Block_t*);
108	}
109	else
110	{	SIZE(next) = s - sizeof(Head_t);
111		SEG(next) = seg;
112		seg->free = next;
113	}
114
115done:
116	if(!local && (vd->mode&VM_TRACE) && _Vmtrace && tp)
117		(*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)tp,vd->pool,0);
118
119	CLRLOCK(vd, local);
120	ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)tp, vm->disc);
121	CLRINUSE(vd, inuse);
122	return (Void_t*)tp;
123}
124
125#if __STD_C
126static long pooladdr(Vmalloc_t* vm, reg Void_t* addr)
127#else
128static long pooladdr(vm, addr)
129Vmalloc_t*	vm;
130reg Void_t*	addr;
131#endif
132{
133	reg Block_t	*bp, *tp;
134	reg Vmuchar_t	*laddr, *baddr;
135	reg size_t	size;
136	reg Seg_t*	seg;
137	reg long	offset;
138	reg Vmdata_t*	vd = vm->data;
139	reg int		local, inuse;
140
141	SETINUSE(vd, inuse);
142	if(!(local = vd->mode&VM_TRUST))
143	{	GETLOCAL(vd,local);
144		if(ISLOCK(vd,local))
145		{	CLRINUSE(vd, inuse);
146			return -1L;
147		}
148		SETLOCK(vd,local);
149	}
150
151	offset = -1L;
152	for(seg = vd->seg; seg; seg = seg->next)
153	{	laddr = (Vmuchar_t*)SEGBLOCK(seg);
154		baddr = seg->baddr-sizeof(Head_t);
155		if((Vmuchar_t*)addr < laddr || (Vmuchar_t*)addr >= baddr)
156			continue;
157
158		/* the block that has this address */
159		size = ROUND(vd->pool,ALIGN);
160		tp = (Block_t*)(laddr + (((Vmuchar_t*)addr-laddr)/size)*size );
161
162		/* see if this block has been freed */
163		if(SIZE(tp) == POOLFREE) /* may be a coincidence - make sure */
164			for(bp = vd->free; bp; bp = SEGLINK(bp))
165				if(bp == tp)
166					goto done;
167
168		offset = (Vmuchar_t*)addr - (Vmuchar_t*)tp;
169		goto done;
170	}
171
172done :
173	CLRLOCK(vd,local);
174	CLRINUSE(vd, inuse);
175	return offset;
176}
177
178#if __STD_C
179static int poolfree(reg Vmalloc_t* vm, reg Void_t* data )
180#else
181static int poolfree(vm, data)
182reg Vmalloc_t*	vm;
183reg Void_t*	data;
184#endif
185{
186	reg Block_t*	bp;
187	reg Vmdata_t*	vd = vm->data;
188	reg int		local, inuse;
189
190	if(!data)
191		return 0;
192
193	SETINUSE(vd, inuse);
194	if(!(local = vd->mode&VM_TRUST))
195	{	GETLOCAL(vd, local);
196
197		if(ISLOCK(vd, local) || vd->pool <= 0)
198		{	CLRINUSE(vd, inuse);
199			return -1;
200		}
201
202		if(KPVADDR(vm,data,pooladdr) != 0)
203		{	if(vm->disc->exceptf)
204				(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
205			CLRINUSE(vd, inuse);
206			return -1;
207		}
208
209		SETLOCK(vd, local);
210	}
211
212	bp = (Block_t*)data;
213	SIZE(bp) = POOLFREE;
214	SEGLINK(bp) = vd->free;
215	vd->free = bp;
216
217	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
218		(*_Vmtrace)(vm, (Vmuchar_t*)data, NIL(Vmuchar_t*), vd->pool, 0);
219
220	CLRLOCK(vd,local);
221	ANNOUNCE(local, vm, VM_FREE, data, vm->disc);
222	CLRINUSE(vd, inuse);
223	return 0;
224}
225
226#if __STD_C
227static Void_t* poolresize(Vmalloc_t* vm, Void_t* data, size_t size, int type )
228#else
229static Void_t* poolresize(vm, data, size, type )
230Vmalloc_t*	vm;
231Void_t*		data;
232size_t		size;
233int		type;
234#endif
235{
236	int		local, inuse;
237	reg Vmdata_t*	vd = vm->data;
238
239	NOTUSED(type);
240
241	SETINUSE(vd, inuse);
242	if(!data)
243	{	if((data = poolalloc(vm,size)) && (type&VM_RSZERO) )
244		{	reg int	*d = (int*)data, *ed = (int*)((char*)data+size);
245			do { *d++ = 0;} while(d < ed);
246		}
247		CLRINUSE(vd, inuse);
248		return data;
249	}
250	if(size == 0)
251	{	(void)poolfree(vm,data);
252		CLRINUSE(vd, inuse);
253		return NIL(Void_t*);
254	}
255
256	if(!(local = vd->mode&VM_TRUST) )
257	{	GETLOCAL(vd, local);
258
259		if(ISLOCK(vd, local) )
260		{	CLRINUSE(vd, inuse);
261			return NIL(Void_t*);
262		}
263
264		if(size != vd->pool || KPVADDR(vm,data,pooladdr) != 0)
265		{	if(vm->disc->exceptf)
266				(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
267			CLRINUSE(vd, inuse);
268			return NIL(Void_t*);
269		}
270
271		if((vd->mode&VM_TRACE) && _Vmtrace)
272			(*_Vmtrace)(vm, (Vmuchar_t*)data, (Vmuchar_t*)data, size, 0);
273	}
274
275	ANNOUNCE(local, vm, VM_RESIZE, data, vm->disc);
276	CLRINUSE(vd, inuse);
277	return data;
278}
279
280#if __STD_C
281static long poolsize(Vmalloc_t* vm, Void_t* addr)
282#else
283static long poolsize(vm, addr)
284Vmalloc_t*	vm;
285Void_t*		addr;
286#endif
287{
288	return pooladdr(vm,addr) == 0 ? (long)vm->data->pool : -1L;
289}
290
291#if __STD_C
292static int poolcompact(Vmalloc_t* vm)
293#else
294static int poolcompact(vm)
295Vmalloc_t*	vm;
296#endif
297{
298	reg Block_t*	fp;
299	reg Seg_t	*seg, *next;
300	reg size_t	s;
301	reg Vmdata_t*	vd = vm->data;
302	reg int		inuse;
303
304	SETINUSE(vd, inuse);
305	if(!(vd->mode&VM_TRUST))
306	{	if(ISLOCK(vd,0))
307		{	CLRINUSE(vd, inuse);
308			return -1;
309		}
310		SETLOCK(vd,0);
311	}
312
313	for(seg = vd->seg; seg; seg = next)
314	{	next = seg->next;
315
316		if(!(fp = seg->free))
317			continue;
318
319		seg->free = NIL(Block_t*);
320		if(seg->size == (s = SIZE(fp)&~BITS))
321			s = seg->extent;
322		else	s += sizeof(Head_t);
323
324		if((*_Vmtruncate)(vm,seg,s,1) == s)
325			seg->free = fp;
326	}
327
328	if((vd->mode&VM_TRACE) && _Vmtrace)
329		(*_Vmtrace)(vm, (Vmuchar_t*)0, (Vmuchar_t*)0, 0, 0);
330
331	CLRLOCK(vd,0);
332	CLRINUSE(vd, inuse);
333	return 0;
334}
335
336#if __STD_C
337static Void_t* poolalign(Vmalloc_t* vm, size_t size, size_t align)
338#else
339static Void_t* poolalign(vm, size, align)
340Vmalloc_t*	vm;
341size_t		size;
342size_t		align;
343#endif
344{
345	NOTUSED(vm);
346	NOTUSED(size);
347	NOTUSED(align);
348	return NIL(Void_t*);
349}
350
351/* Public interface */
352static Vmethod_t _Vmpool =
353{
354	poolalloc,
355	poolresize,
356	poolfree,
357	pooladdr,
358	poolsize,
359	poolcompact,
360	poolalign,
361	VM_MTPOOL
362};
363
364__DEFINE__(Vmethod_t*,Vmpool,&_Vmpool);
365
366#ifdef NoF
367NoF(vmpool)
368#endif
369
370#endif
371