xref: /onnv-gate/usr/src/lib/libast/common/vmalloc/vmprivate.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_vmprivate()244887Schin void _STUB_vmprivate(){}
254887Schin 
264887Schin #else
274887Schin 
284887Schin #include	"vmhdr.h"
294887Schin 
30*12068SRoger.Faulkner@Oracle.COM static char*	Version = "\n@(#)$Id: Vmalloc (AT&T Research) 2010-01-01 $\0\n";
314887Schin 
324887Schin /*	Private code used in the vmalloc library
334887Schin **
344887Schin **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
354887Schin */
364887Schin 
374887Schin /* Get more memory for a region */
384887Schin #if __STD_C
vmextend(reg Vmalloc_t * vm,size_t size,Vmsearch_f searchf)394887Schin static Block_t* vmextend(reg Vmalloc_t* vm, size_t size, Vmsearch_f searchf )
404887Schin #else
414887Schin static Block_t* vmextend(vm, size, searchf )
424887Schin reg Vmalloc_t*	vm;		/* region to increase in size	*/
434887Schin size_t		size;		/* desired amount of space	*/
444887Schin Vmsearch_f	searchf;	/* tree search function		*/
454887Schin #endif
464887Schin {
474887Schin 	reg size_t	s;
484887Schin 	reg Seg_t*	seg;
494887Schin 	reg Block_t	*bp, *t;
504887Schin 	reg Vmuchar_t*	addr = (Vmuchar_t*)Version; /* shut compiler warning */
514887Schin 	reg Vmdata_t*	vd = vm->data;
524887Schin 	reg Vmemory_f	memoryf = vm->disc->memoryf;
534887Schin 	reg Vmexcept_f	exceptf = vm->disc->exceptf;
544887Schin 
554887Schin 	GETPAGESIZE(_Vmpagesize);
564887Schin 
574887Schin #if DEBUG /* trace all allocation calls through the heap */
584887Schin 	if(!_Vmtrace && vm == Vmheap && (vd->mode&VM_TRUST) )
59*12068SRoger.Faulkner@Oracle.COM 		VMOPTIONS();
604887Schin #endif
614887Schin 
624887Schin 	if(vd->incr <= 0) /* this is just _Vmheap on the first call */
6310898Sroland.mainz@nrubsig.org 		vd->incr = VMHEAPINCR;
644887Schin 
654887Schin 	/* Get slightly more for administrative data */
664887Schin 	s = size + sizeof(Seg_t) + sizeof(Block_t) + sizeof(Head_t) + 2*ALIGN;
674887Schin 	if(s <= size)	/* size was too large and we have wrapped around */
684887Schin 		return NIL(Block_t*);
694887Schin 	if((size = ROUND(s,vd->incr)) < s)
704887Schin 		return NIL(Block_t*);
714887Schin 
724887Schin 	/* increase the rounding factor to reduce # of future extensions */
734887Schin 	if(size > 2*vd->incr && vm->disc->round < vd->incr)
744887Schin 		vd->incr *= 2;
754887Schin 
764887Schin 	/* see if we can extend the current segment */
774887Schin 	if(!(seg = vd->seg) )
784887Schin 		addr = NIL(Vmuchar_t*);
794887Schin 	else
804887Schin 	{	if(!vd->wild || SEG(vd->wild) != seg)
814887Schin 			s = 0;
824887Schin 		else
834887Schin 		{	s = SIZE(vd->wild) + sizeof(Head_t);
844887Schin 			if((s = (s/vd->incr)*vd->incr) == size)
854887Schin 				size += vd->incr;
864887Schin 		}
874887Schin 		addr = (Vmuchar_t*)(*memoryf)(vm,seg->addr,seg->extent,
884887Schin 					  seg->extent+size-s,vm->disc);
894887Schin 		if(!addr)
904887Schin 			seg = NIL(Seg_t*);
914887Schin 		else
924887Schin 		{	/**/ASSERT(addr == (Vmuchar_t*)seg->addr);
934887Schin 			addr += seg->extent;
944887Schin 			size -= s;
954887Schin 		}
964887Schin 	}
974887Schin 
984887Schin 	while(!addr)	/* try to get space */
994887Schin 	{	if((addr = (Vmuchar_t*)(*memoryf)(vm,NIL(Void_t*),0,size,vm->disc)) )
1004887Schin 			break;
1014887Schin 
1024887Schin 		/* check with exception handler to see if we should continue */
1034887Schin 		if(!exceptf)
1044887Schin 			return NIL(Block_t*);
1054887Schin 		else
1064887Schin 		{	int	rv, lock;
1074887Schin 			lock = vd->mode&VM_LOCK;
1084887Schin 			vd->mode &= ~VM_LOCK;
1094887Schin 			rv = (*exceptf)(vm,VM_NOMEM,(Void_t*)size,vm->disc);
1104887Schin 			vd->mode |= lock;
1114887Schin 			if(rv <= 0)
1124887Schin 			{	if(rv == 0)
1134887Schin 					vd->mode |= VM_AGAIN;
1144887Schin 				return NIL(Block_t*);
1154887Schin 			}
1164887Schin 		}
1174887Schin 	}
1184887Schin 
1194887Schin 	if(seg)
1204887Schin 	{	/* extending current segment */
121*12068SRoger.Faulkner@Oracle.COM 		bp = BLOCK(seg->baddr);
1224887Schin 
1234887Schin 		if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE) )
124*12068SRoger.Faulkner@Oracle.COM 		{	/**/ ASSERT((SIZE(bp)&~BITS) == 0);
125*12068SRoger.Faulkner@Oracle.COM 			/**/ ASSERT(SEG(bp) == seg);
126*12068SRoger.Faulkner@Oracle.COM 			if(!ISPFREE(SIZE(bp)) )
1274887Schin 				SIZE(bp) = size - sizeof(Head_t);
1284887Schin 			else
1294887Schin 			{	/**/ ASSERT(searchf);
1304887Schin 				bp = LAST(bp);
1314887Schin 				if(bp == vd->wild)
1324887Schin 					vd->wild = NIL(Block_t*);
1334887Schin 				else	REMOVE(vd,bp,INDEX(SIZE(bp)),t,(*searchf));
1344887Schin 				SIZE(bp) += size;
1354887Schin 			}
1364887Schin 		}
1374887Schin 		else
1384887Schin 		{	if(seg->free)
1394887Schin 			{	bp = seg->free;
1404887Schin 				seg->free = NIL(Block_t*);
1414887Schin 				SIZE(bp) += size;
1424887Schin 			}
143*12068SRoger.Faulkner@Oracle.COM 			else
144*12068SRoger.Faulkner@Oracle.COM 			{	SEG(bp) = seg;
145*12068SRoger.Faulkner@Oracle.COM 				SIZE(bp) = size - sizeof(Head_t);
146*12068SRoger.Faulkner@Oracle.COM 			}
1474887Schin 		}
1484887Schin 
1494887Schin 		seg->size += size;
1504887Schin 		seg->extent += size;
1514887Schin 		seg->baddr += size;
1524887Schin 	}
1534887Schin 	else
1544887Schin 	{	/* creating a new segment */
1554887Schin 		reg Seg_t	*sp, *lastsp;
1564887Schin 
1574887Schin 		if((s = (size_t)(VLONG(addr)%ALIGN)) != 0)
1584887Schin 			addr += ALIGN-s;
1594887Schin 
1604887Schin 		seg = (Seg_t*)addr;
161*12068SRoger.Faulkner@Oracle.COM 		seg->vmdt = vd;
1624887Schin 		seg->addr = (Void_t*)(addr - (s ? ALIGN-s : 0));
1634887Schin 		seg->extent = size;
1644887Schin 		seg->baddr = addr + size - (s ? 2*ALIGN : 0);
1654887Schin 		seg->free = NIL(Block_t*);
1664887Schin 		bp = SEGBLOCK(seg);
1674887Schin 		SEG(bp) = seg;
1684887Schin 		SIZE(bp) = seg->baddr - (Vmuchar_t*)bp - 2*sizeof(Head_t);
1694887Schin 
1704887Schin 		/* NOTE: for Vmbest, Vmdebug and Vmprofile the region's segment list
1714887Schin 		   is reversely ordered by addresses. This is so that we can easily
1724887Schin 		   check for the wild block.
1734887Schin 		*/
1744887Schin 		lastsp = NIL(Seg_t*);
1754887Schin 		sp = vd->seg;
1764887Schin 		if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE))
1774887Schin 			for(; sp; lastsp = sp, sp = sp->next)
1784887Schin 				if(seg->addr > sp->addr)
1794887Schin 					break;
1804887Schin 		seg->next = sp;
1814887Schin 		if(lastsp)
1824887Schin 			lastsp->next = seg;
1834887Schin 		else	vd->seg = seg;
1844887Schin 
1854887Schin 		seg->size = SIZE(bp);
1864887Schin 	}
1874887Schin 
1884887Schin 	/* make a fake header for possible segmented memory */
1894887Schin 	t = NEXT(bp);
1904887Schin 	SEG(t) = seg;
1914887Schin 	SIZE(t) = BUSY;
1924887Schin 
1934887Schin 	/* see if the wild block is still wild */
1944887Schin 	if((t = vd->wild) && (seg = SEG(t)) != vd->seg)
1954887Schin 	{	CLRPFREE(SIZE(NEXT(t)));
1964887Schin 		if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE) )
1974887Schin 		{	SIZE(t) |= BUSY|JUNK;
1984887Schin 			LINK(t) = CACHE(vd)[C_INDEX(SIZE(t))];
1994887Schin 			CACHE(vd)[C_INDEX(SIZE(t))] = t;
2004887Schin 		}
2014887Schin 		else	seg->free = t;
2024887Schin 
2034887Schin 		vd->wild = NIL(Block_t*);
2044887Schin 	}
2054887Schin 
2064887Schin 	return bp;
2074887Schin }
2084887Schin 
2094887Schin /* Truncate a segment if possible */
2104887Schin #if __STD_C
vmtruncate(Vmalloc_t * vm,Seg_t * seg,size_t size,int exact)2114887Schin static ssize_t vmtruncate(Vmalloc_t* vm, Seg_t* seg, size_t size, int exact)
2124887Schin #else
2134887Schin static ssize_t vmtruncate(vm, seg, size, exact)
2144887Schin Vmalloc_t*	vm;	/* containing region		*/
2154887Schin Seg_t*		seg;	/* the one to be truncated	*/
2164887Schin size_t		size;	/* amount of free space		*/
2174887Schin int		exact;
2184887Schin #endif
2194887Schin {
2204887Schin 	reg Void_t*	caddr;
2214887Schin 	reg Seg_t*	last;
2224887Schin 	reg Vmdata_t*	vd = vm->data;
2234887Schin 	reg Vmemory_f	memoryf = vm->disc->memoryf;
2244887Schin 
2254887Schin 	caddr = seg->addr;
2264887Schin 
2274887Schin 	if(size < seg->size)
2284887Schin 	{	reg ssize_t	less;
2294887Schin 
2304887Schin 		if(exact)
2314887Schin 			less = size;
2324887Schin 		else /* keep truncated amount to discipline requirements */
2334887Schin 		{	if((less = vm->disc->round) <= 0)
2344887Schin 				less = _Vmpagesize;
2354887Schin 			less = (size/less)*less;
2364887Schin 			less = (less/vd->incr)*vd->incr;
237*12068SRoger.Faulkner@Oracle.COM 			if(less > 0 && size > (size_t)less && (size-(size_t)less) < sizeof(Block_t) )
238*12068SRoger.Faulkner@Oracle.COM 				less = (size_t)less <= vd->incr ? 0 : (size_t)less - vd->incr;
2394887Schin 		}
2404887Schin 
2414887Schin 		if(less <= 0 ||
2424887Schin 		   (*memoryf)(vm,caddr,seg->extent,seg->extent-less,vm->disc) != caddr)
2434887Schin 			return 0;
2444887Schin 
2454887Schin 		seg->extent -= less;
2464887Schin 		seg->size -= less;
2474887Schin 		seg->baddr -= less;
2484887Schin 		SEG(BLOCK(seg->baddr)) = seg;
2494887Schin 		SIZE(BLOCK(seg->baddr)) = BUSY;
2504887Schin 
2514887Schin 		return less;
2524887Schin 	}
2534887Schin 	else
2544887Schin 	{	/* unlink segment from region */
2554887Schin 		if(seg == vd->seg)
2564887Schin 		{	vd->seg = seg->next;
2574887Schin 			last = NIL(Seg_t*);
2584887Schin 		}
2594887Schin 		else
2604887Schin 		{	for(last = vd->seg; last->next != seg; last = last->next)
2614887Schin 				;
2624887Schin 			last->next = seg->next;
2634887Schin 		}
2644887Schin 
2654887Schin 		/* now delete it */
2664887Schin 		if((*memoryf)(vm,caddr,seg->extent,0,vm->disc) == caddr)
2674887Schin 			return size;
2684887Schin 
2694887Schin 		/* space reduction failed, reinsert segment */
2704887Schin 		if(last)
2714887Schin 		{	seg->next = last->next;
2724887Schin 			last->next = seg;
2734887Schin 		}
2744887Schin 		else
2754887Schin 		{	seg->next = vd->seg;
2764887Schin 			vd->seg = seg;
2774887Schin 		}
2784887Schin 		return 0;
2794887Schin 	}
2804887Schin }
2814887Schin 
2824887Schin /* Externally visible names but local to library */
2834887Schin Vmextern_t	_Vmextern =
2844887Schin {	vmextend,						/* _Vmextend	*/
2854887Schin 	vmtruncate,						/* _Vmtruncate	*/
2864887Schin 	0,							/* _Vmpagesize	*/
2874887Schin 	NIL(char*(*)_ARG_((char*,const char*,int))),		/* _Vmstrcpy	*/
2884887Schin 	NIL(char*(*)_ARG_((Vmulong_t,int))),			/* _Vmitoa	*/
2894887Schin 	NIL(void(*)_ARG_((Vmalloc_t*,
2904887Schin 			  Vmuchar_t*,Vmuchar_t*,size_t,size_t))), /* _Vmtrace	*/
2914887Schin 	NIL(void(*)_ARG_((Vmalloc_t*)))				/* _Vmpfclose	*/
2924887Schin };
2934887Schin 
2944887Schin #endif
295