xref: /onnv-gate/usr/src/lib/libast/common/vmalloc/vmpool.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #if defined(_UWIN) && defined(_BLD_ast)
234887Schin 
_STUB_vmpool()244887Schin void _STUB_vmpool(){}
254887Schin 
264887Schin #else
274887Schin 
284887Schin #include	"vmhdr.h"
294887Schin 
304887Schin #define POOLFREE	0x55555555L	/* block free indicator	 */
314887Schin 
324887Schin /*	Method for pool allocation.
334887Schin **	All elements in a pool have the same size.
344887Schin **	The following fields of Vmdata_t are used as:
354887Schin **		pool:	size of a block.
364887Schin **		free:	list of free blocks.
374887Schin **
384887Schin **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
394887Schin */
404887Schin 
414887Schin #if __STD_C
poolalloc(Vmalloc_t * vm,reg size_t size)424887Schin static Void_t* poolalloc(Vmalloc_t* vm, reg size_t size)
434887Schin #else
444887Schin static Void_t* poolalloc(vm, size )
454887Schin Vmalloc_t*	vm;
464887Schin reg size_t	size;
474887Schin #endif
484887Schin {
494887Schin 	reg Vmdata_t*	vd = vm->data;
504887Schin 	reg Block_t	*tp, *next;
514887Schin 	reg size_t	s;
524887Schin 	reg Seg_t*	seg;
538462SApril.Chin@Sun.COM 	reg int		local, inuse;
544887Schin 
554887Schin 	if(size <= 0)
564887Schin 		return NIL(Void_t*);
57*12068SRoger.Faulkner@Oracle.COM 	if(size != vd->pool)
584887Schin 	{	if(vd->pool <= 0)
594887Schin 			vd->pool = size;
604887Schin 		else	return NIL(Void_t*);
614887Schin 	}
624887Schin 
638462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
644887Schin 	if(!(local = vd->mode&VM_TRUST) )
654887Schin 	{	GETLOCAL(vd,local);
664887Schin 		if(ISLOCK(vd, local))
678462SApril.Chin@Sun.COM 		{	CLRINUSE(vd, inuse);
684887Schin 			return NIL(Void_t*);
698462SApril.Chin@Sun.COM 		}
704887Schin 		SETLOCK(vd, local);
714887Schin 	}
724887Schin 
734887Schin 	if((tp = vd->free) ) /* there is a ready free block */
744887Schin 	{	vd->free = SEGLINK(tp);
754887Schin 		goto done;
764887Schin 	}
774887Schin 
784887Schin 	size = ROUND(size,ALIGN);
794887Schin 
804887Schin 	/* look thru all segments for a suitable free block */
814887Schin 	for(tp = NIL(Block_t*), seg = vd->seg; seg; seg = seg->next)
824887Schin 	{	if((tp = seg->free) &&
834887Schin 		   (s = (SIZE(tp) & ~BITS) + sizeof(Head_t)) >= size )
844887Schin 			goto has_blk;
854887Schin 	}
864887Schin 
874887Schin 	for(;;) /* must extend region */
884887Schin 	{	if((tp = (*_Vmextend)(vm,ROUND(size,vd->incr),NIL(Vmsearch_f))) )
894887Schin 		{	s = (SIZE(tp) & ~BITS) + sizeof(Head_t);
904887Schin 			seg = SEG(tp);
914887Schin 			goto has_blk;
924887Schin 		}
934887Schin 		else if(vd->mode&VM_AGAIN)
944887Schin 			vd->mode &= ~VM_AGAIN;
954887Schin 		else	goto done;
964887Schin 	}
974887Schin 
984887Schin has_blk: /* if get here, (tp, s, seg) must be well-defined */
994887Schin 	next = (Block_t*)((Vmuchar_t*)tp+size);
1004887Schin 	if((s -= size) <= (size + sizeof(Head_t)) )
1014887Schin 	{	for(; s >= size; s -= size)
1024887Schin 		{	SIZE(next) = POOLFREE;
1034887Schin 			SEGLINK(next) = vd->free;
1044887Schin 			vd->free = next;
1054887Schin 			next = (Block_t*)((Vmuchar_t*)next + size);
1064887Schin 		}
1074887Schin 		seg->free = NIL(Block_t*);
1084887Schin 	}
1094887Schin 	else
1104887Schin 	{	SIZE(next) = s - sizeof(Head_t);
1114887Schin 		SEG(next) = seg;
1124887Schin 		seg->free = next;
1134887Schin 	}
1144887Schin 
1154887Schin done:
1164887Schin 	if(!local && (vd->mode&VM_TRACE) && _Vmtrace && tp)
1174887Schin 		(*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)tp,vd->pool,0);
1184887Schin 
1194887Schin 	CLRLOCK(vd, local);
1204887Schin 	ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)tp, vm->disc);
1218462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
1224887Schin 	return (Void_t*)tp;
1234887Schin }
1244887Schin 
1254887Schin #if __STD_C
pooladdr(Vmalloc_t * vm,reg Void_t * addr)1264887Schin static long pooladdr(Vmalloc_t* vm, reg Void_t* addr)
1274887Schin #else
1284887Schin static long pooladdr(vm, addr)
1294887Schin Vmalloc_t*	vm;
1304887Schin reg Void_t*	addr;
1314887Schin #endif
1324887Schin {
1334887Schin 	reg Block_t	*bp, *tp;
1344887Schin 	reg Vmuchar_t	*laddr, *baddr;
1354887Schin 	reg size_t	size;
1364887Schin 	reg Seg_t*	seg;
1374887Schin 	reg long	offset;
1384887Schin 	reg Vmdata_t*	vd = vm->data;
1398462SApril.Chin@Sun.COM 	reg int		local, inuse;
1404887Schin 
1418462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
1424887Schin 	if(!(local = vd->mode&VM_TRUST))
1434887Schin 	{	GETLOCAL(vd,local);
1444887Schin 		if(ISLOCK(vd,local))
1458462SApril.Chin@Sun.COM 		{	CLRINUSE(vd, inuse);
1464887Schin 			return -1L;
1478462SApril.Chin@Sun.COM 		}
1484887Schin 		SETLOCK(vd,local);
1494887Schin 	}
1504887Schin 
1514887Schin 	offset = -1L;
1524887Schin 	for(seg = vd->seg; seg; seg = seg->next)
1534887Schin 	{	laddr = (Vmuchar_t*)SEGBLOCK(seg);
1544887Schin 		baddr = seg->baddr-sizeof(Head_t);
1554887Schin 		if((Vmuchar_t*)addr < laddr || (Vmuchar_t*)addr >= baddr)
1564887Schin 			continue;
1574887Schin 
1584887Schin 		/* the block that has this address */
1594887Schin 		size = ROUND(vd->pool,ALIGN);
1604887Schin 		tp = (Block_t*)(laddr + (((Vmuchar_t*)addr-laddr)/size)*size );
1614887Schin 
1624887Schin 		/* see if this block has been freed */
1634887Schin 		if(SIZE(tp) == POOLFREE) /* may be a coincidence - make sure */
1644887Schin 			for(bp = vd->free; bp; bp = SEGLINK(bp))
1654887Schin 				if(bp == tp)
1664887Schin 					goto done;
1674887Schin 
1684887Schin 		offset = (Vmuchar_t*)addr - (Vmuchar_t*)tp;
1694887Schin 		goto done;
1704887Schin 	}
1714887Schin 
1724887Schin done :
1734887Schin 	CLRLOCK(vd,local);
1748462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
1754887Schin 	return offset;
1764887Schin }
1774887Schin 
1784887Schin #if __STD_C
poolfree(reg Vmalloc_t * vm,reg Void_t * data)1794887Schin static int poolfree(reg Vmalloc_t* vm, reg Void_t* data )
1804887Schin #else
1814887Schin static int poolfree(vm, data)
1824887Schin reg Vmalloc_t*	vm;
1834887Schin reg Void_t*	data;
1844887Schin #endif
1854887Schin {
1864887Schin 	reg Block_t*	bp;
1874887Schin 	reg Vmdata_t*	vd = vm->data;
1888462SApril.Chin@Sun.COM 	reg int		local, inuse;
1894887Schin 
1904887Schin 	if(!data)
1914887Schin 		return 0;
1924887Schin 
1938462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
1944887Schin 	if(!(local = vd->mode&VM_TRUST))
1954887Schin 	{	GETLOCAL(vd, local);
1964887Schin 
1974887Schin 		if(ISLOCK(vd, local) || vd->pool <= 0)
1988462SApril.Chin@Sun.COM 		{	CLRINUSE(vd, inuse);
1994887Schin 			return -1;
2008462SApril.Chin@Sun.COM 		}
2014887Schin 
2024887Schin 		if(KPVADDR(vm,data,pooladdr) != 0)
2034887Schin 		{	if(vm->disc->exceptf)
2044887Schin 				(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
2058462SApril.Chin@Sun.COM 			CLRINUSE(vd, inuse);
2064887Schin 			return -1;
2074887Schin 		}
2084887Schin 
2094887Schin 		SETLOCK(vd, local);
2104887Schin 	}
2114887Schin 
2124887Schin 	bp = (Block_t*)data;
2134887Schin 	SIZE(bp) = POOLFREE;
2144887Schin 	SEGLINK(bp) = vd->free;
2154887Schin 	vd->free = bp;
2164887Schin 
2174887Schin 	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
2184887Schin 		(*_Vmtrace)(vm, (Vmuchar_t*)data, NIL(Vmuchar_t*), vd->pool, 0);
2194887Schin 
2204887Schin 	CLRLOCK(vd,local);
2214887Schin 	ANNOUNCE(local, vm, VM_FREE, data, vm->disc);
2228462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
2234887Schin 	return 0;
2244887Schin }
2254887Schin 
2264887Schin #if __STD_C
poolresize(Vmalloc_t * vm,Void_t * data,size_t size,int type)2274887Schin static Void_t* poolresize(Vmalloc_t* vm, Void_t* data, size_t size, int type )
2284887Schin #else
2294887Schin static Void_t* poolresize(vm, data, size, type )
2304887Schin Vmalloc_t*	vm;
2314887Schin Void_t*		data;
2324887Schin size_t		size;
2334887Schin int		type;
2344887Schin #endif
2354887Schin {
2368462SApril.Chin@Sun.COM 	int		local, inuse;
2374887Schin 	reg Vmdata_t*	vd = vm->data;
2384887Schin 
2394887Schin 	NOTUSED(type);
2404887Schin 
2418462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
2424887Schin 	if(!data)
2434887Schin 	{	if((data = poolalloc(vm,size)) && (type&VM_RSZERO) )
2444887Schin 		{	reg int	*d = (int*)data, *ed = (int*)((char*)data+size);
2454887Schin 			do { *d++ = 0;} while(d < ed);
2464887Schin 		}
2478462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
2484887Schin 		return data;
2494887Schin 	}
2504887Schin 	if(size == 0)
2514887Schin 	{	(void)poolfree(vm,data);
2528462SApril.Chin@Sun.COM 		CLRINUSE(vd, inuse);
2534887Schin 		return NIL(Void_t*);
2544887Schin 	}
2554887Schin 
2564887Schin 	if(!(local = vd->mode&VM_TRUST) )
2574887Schin 	{	GETLOCAL(vd, local);
2584887Schin 
2594887Schin 		if(ISLOCK(vd, local) )
2608462SApril.Chin@Sun.COM 		{	CLRINUSE(vd, inuse);
2614887Schin 			return NIL(Void_t*);
2628462SApril.Chin@Sun.COM 		}
2634887Schin 
2644887Schin 		if(size != vd->pool || KPVADDR(vm,data,pooladdr) != 0)
2654887Schin 		{	if(vm->disc->exceptf)
2664887Schin 				(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
2678462SApril.Chin@Sun.COM 			CLRINUSE(vd, inuse);
2684887Schin 			return NIL(Void_t*);
2694887Schin 		}
2704887Schin 
2714887Schin 		if((vd->mode&VM_TRACE) && _Vmtrace)
2724887Schin 			(*_Vmtrace)(vm, (Vmuchar_t*)data, (Vmuchar_t*)data, size, 0);
2734887Schin 	}
2744887Schin 
2754887Schin 	ANNOUNCE(local, vm, VM_RESIZE, data, vm->disc);
2768462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
2774887Schin 	return data;
2784887Schin }
2794887Schin 
2804887Schin #if __STD_C
poolsize(Vmalloc_t * vm,Void_t * addr)2814887Schin static long poolsize(Vmalloc_t* vm, Void_t* addr)
2824887Schin #else
2834887Schin static long poolsize(vm, addr)
2844887Schin Vmalloc_t*	vm;
2854887Schin Void_t*		addr;
2864887Schin #endif
2874887Schin {
2884887Schin 	return pooladdr(vm,addr) == 0 ? (long)vm->data->pool : -1L;
2894887Schin }
2904887Schin 
2914887Schin #if __STD_C
poolcompact(Vmalloc_t * vm)2924887Schin static int poolcompact(Vmalloc_t* vm)
2934887Schin #else
2944887Schin static int poolcompact(vm)
2954887Schin Vmalloc_t*	vm;
2964887Schin #endif
2974887Schin {
2984887Schin 	reg Block_t*	fp;
2994887Schin 	reg Seg_t	*seg, *next;
3004887Schin 	reg size_t	s;
3014887Schin 	reg Vmdata_t*	vd = vm->data;
3028462SApril.Chin@Sun.COM 	reg int		inuse;
3034887Schin 
3048462SApril.Chin@Sun.COM 	SETINUSE(vd, inuse);
3054887Schin 	if(!(vd->mode&VM_TRUST))
3064887Schin 	{	if(ISLOCK(vd,0))
3078462SApril.Chin@Sun.COM 		{	CLRINUSE(vd, inuse);
3084887Schin 			return -1;
3098462SApril.Chin@Sun.COM 		}
3104887Schin 		SETLOCK(vd,0);
3114887Schin 	}
3124887Schin 
3134887Schin 	for(seg = vd->seg; seg; seg = next)
3144887Schin 	{	next = seg->next;
3154887Schin 
3164887Schin 		if(!(fp = seg->free))
3174887Schin 			continue;
3184887Schin 
3194887Schin 		seg->free = NIL(Block_t*);
3204887Schin 		if(seg->size == (s = SIZE(fp)&~BITS))
3214887Schin 			s = seg->extent;
3224887Schin 		else	s += sizeof(Head_t);
3234887Schin 
3244887Schin 		if((*_Vmtruncate)(vm,seg,s,1) == s)
3254887Schin 			seg->free = fp;
3264887Schin 	}
3274887Schin 
3284887Schin 	if((vd->mode&VM_TRACE) && _Vmtrace)
3294887Schin 		(*_Vmtrace)(vm, (Vmuchar_t*)0, (Vmuchar_t*)0, 0, 0);
3304887Schin 
3314887Schin 	CLRLOCK(vd,0);
3328462SApril.Chin@Sun.COM 	CLRINUSE(vd, inuse);
3334887Schin 	return 0;
3344887Schin }
3354887Schin 
3364887Schin #if __STD_C
poolalign(Vmalloc_t * vm,size_t size,size_t align)3374887Schin static Void_t* poolalign(Vmalloc_t* vm, size_t size, size_t align)
3384887Schin #else
3394887Schin static Void_t* poolalign(vm, size, align)
3404887Schin Vmalloc_t*	vm;
3414887Schin size_t		size;
3424887Schin size_t		align;
3434887Schin #endif
3444887Schin {
3454887Schin 	NOTUSED(vm);
3464887Schin 	NOTUSED(size);
3474887Schin 	NOTUSED(align);
3484887Schin 	return NIL(Void_t*);
3494887Schin }
3504887Schin 
3514887Schin /* Public interface */
3524887Schin static Vmethod_t _Vmpool =
3534887Schin {
3544887Schin 	poolalloc,
3554887Schin 	poolresize,
3564887Schin 	poolfree,
3574887Schin 	pooladdr,
3584887Schin 	poolsize,
3594887Schin 	poolcompact,
3604887Schin 	poolalign,
3614887Schin 	VM_MTPOOL
3624887Schin };
3634887Schin 
3644887Schin __DEFINE__(Vmethod_t*,Vmpool,&_Vmpool);
3654887Schin 
3664887Schin #ifdef NoF
3674887Schin NoF(vmpool)
3684887Schin #endif
3694887Schin 
3704887Schin #endif
371