1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #if defined(_UWIN) && defined(_BLD_ast)
_STUB_malloc()24da2e3ebdSchin void _STUB_malloc(){}
26da2e3ebdSchin #else
28da2e3ebdSchin #if _UWIN
30da2e3ebdSchin #define calloc		______calloc
31da2e3ebdSchin #define _ast_free	______free
32da2e3ebdSchin #define malloc		______malloc
33da2e3ebdSchin #define mallinfo	______mallinfo
34da2e3ebdSchin #define mallopt		______mallopt
35da2e3ebdSchin #define mstats		______mstats
36da2e3ebdSchin #define realloc		______realloc
38da2e3ebdSchin #define _STDLIB_H_	1
40da2e3ebdSchin extern int		atexit(void(*)(void));
41da2e3ebdSchin extern char*		getenv(const char*);
43da2e3ebdSchin #endif
45da2e3ebdSchin #include	"vmhdr.h"
4634f9b3eeSRoland Mainz #include	<errno.h>
48da2e3ebdSchin #if _UWIN
50da2e3ebdSchin #include	<malloc.h>
52da2e3ebdSchin #define _map_malloc	1
53da2e3ebdSchin #define _mal_alloca	1
55da2e3ebdSchin #undef	calloc
56da2e3ebdSchin #define calloc		_ast_calloc
57da2e3ebdSchin #undef	_ast_free
58da2e3ebdSchin #define free		_ast_free
59da2e3ebdSchin #undef	malloc
60da2e3ebdSchin #define malloc		_ast_malloc
61da2e3ebdSchin #undef	mallinfo
62da2e3ebdSchin typedef struct ______mallinfo Mallinfo_t;
63da2e3ebdSchin #undef	mallopt
64da2e3ebdSchin #undef	mstats
65da2e3ebdSchin typedef struct ______mstats Mstats_t;
66da2e3ebdSchin #undef	realloc
67da2e3ebdSchin #define realloc		_ast_realloc
69da2e3ebdSchin #endif
71da2e3ebdSchin #if __STD_C
72da2e3ebdSchin #define F0(f,t0)		f(t0)
73da2e3ebdSchin #define F1(f,t1,a1)		f(t1 a1)
74da2e3ebdSchin #define F2(f,t1,a1,t2,a2)	f(t1 a1, t2 a2)
75da2e3ebdSchin #else
76da2e3ebdSchin #define F0(f,t0)		f()
77da2e3ebdSchin #define F1(f,t1,a1)		f(a1) t1 a1;
78da2e3ebdSchin #define F2(f,t1,a1,t2,a2)	f(a1, a2) t1 a1; t2 a2;
79da2e3ebdSchin #endif
81da2e3ebdSchin /*
82da2e3ebdSchin  * define _AST_std_malloc=1 to force the standard malloc
83da2e3ebdSchin  * if _map_malloc is also defined then _ast_malloc etc.
84da2e3ebdSchin  * will simply call malloc etc.
85da2e3ebdSchin  */
87da2e3ebdSchin #if !defined(_AST_std_malloc) && __CYGWIN__
88da2e3ebdSchin #define _AST_std_malloc	1
89da2e3ebdSchin #endif
913e14f97fSRoger A. Faulkner /*	malloc compatibility functions
923e14f97fSRoger A. Faulkner **
933e14f97fSRoger A. Faulkner **	These are aware of debugging/profiling and are driven by the
94*b30d1939SAndy Fiddaman **	VMALLOC_OPTIONS environment variable which is a comma or space
95*b30d1939SAndy Fiddaman **	separated list of [no]name[=value] options:
96da2e3ebdSchin **
973e14f97fSRoger A. Faulkner **	    abort	if Vmregion==Vmdebug then VM_DBABORT is set,
98*b30d1939SAndy Fiddaman **			otherwise _BLD_DEBUG enabled assertions abort()
993e14f97fSRoger A. Faulkner **			on failure
100*b30d1939SAndy Fiddaman **	    break	try sbrk() block allocator first
1013e14f97fSRoger A. Faulkner **	    check	if Vmregion==Vmbest then the region is checked every op
102*b30d1939SAndy Fiddaman **	    free	disable addfreelist()
103*b30d1939SAndy Fiddaman **	    keep	disable free -- if code works with this enabled then it
104*b30d1939SAndy Fiddaman **	    		probably accesses free'd data
1053e14f97fSRoger A. Faulkner **	    method=m	sets Vmregion=m if not defined, m (Vm prefix optional)
1063e14f97fSRoger A. Faulkner **			may be one of { best debug last profile }
107*b30d1939SAndy Fiddaman **	    mmap	try mmap() block allocator first
1083e14f97fSRoger A. Faulkner **	    period=n	sets Vmregion=Vmdebug if not defined, if
1093e14f97fSRoger A. Faulkner **			Vmregion==Vmdebug the region is checked every n ops
1103e14f97fSRoger A. Faulkner **	    profile=f	sets Vmregion=Vmprofile if not set, if
1113e14f97fSRoger A. Faulkner **			Vmregion==Vmprofile then profile info printed to file f
1123e14f97fSRoger A. Faulkner **	    start=n	sets Vmregion=Vmdebug if not defined, if
1133e14f97fSRoger A. Faulkner **			Vmregion==Vmdebug region checking starts after n ops
1143e14f97fSRoger A. Faulkner **	    trace=f	enables tracing to file f
1153e14f97fSRoger A. Faulkner **	    warn=f	sets Vmregion=Vmdebug if not defined, if
1163e14f97fSRoger A. Faulkner **			Vmregion==Vmdebug then warnings printed to file f
1173e14f97fSRoger A. Faulkner **	    watch=a	sets Vmregion=Vmdebug if not defined, if
1183e14f97fSRoger A. Faulkner **			Vmregion==Vmdebug then address a is watched
119da2e3ebdSchin **
1203e14f97fSRoger A. Faulkner **	Output files are created if they don't exist. &n and /dev/fd/n name
1213e14f97fSRoger A. Faulkner **	the file descriptor n which must be open for writing. The pattern %p
1223e14f97fSRoger A. Faulkner **	in a file name is replaced by the process ID.
1233e14f97fSRoger A. Faulkner **
1243e14f97fSRoger A. Faulkner **	VMALLOC_OPTIONS combines the features of these previously used env vars:
126da2e3ebdSchin **
127da2e3ebdSchin **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
128da2e3ebdSchin */
130da2e3ebdSchin #if _sys_stat
131da2e3ebdSchin #include	<sys/stat.h>
132da2e3ebdSchin #endif
133da2e3ebdSchin #include	<fcntl.h>
135da2e3ebdSchin #ifdef S_IRUSR
136da2e3ebdSchin #define CREAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
137da2e3ebdSchin #else
138da2e3ebdSchin #define CREAT_MODE	0644
139da2e3ebdSchin #endif
1413e14f97fSRoger A. Faulkner static Vmulong_t	_Vmdbstart = 0;
1423e14f97fSRoger A. Faulkner static Vmulong_t	_Vmdbcheck = 0;
1433e14f97fSRoger A. Faulkner static Vmulong_t	_Vmdbtime = 0;
1443e14f97fSRoger A. Faulkner static int		_Vmpffd = -1;
1453e14f97fSRoger A. Faulkner 
1463e14f97fSRoger A. Faulkner #if ( !_std_malloc || !_BLD_ast ) && !_AST_std_malloc
1473e14f97fSRoger A. Faulkner 
148da2e3ebdSchin #if !_map_malloc
149da2e3ebdSchin #undef calloc
150da2e3ebdSchin #undef cfree
151da2e3ebdSchin #undef free
152da2e3ebdSchin #undef mallinfo
153da2e3ebdSchin #undef malloc
154da2e3ebdSchin #undef mallopt
155da2e3ebdSchin #undef memalign
156da2e3ebdSchin #undef mstats
157da2e3ebdSchin #undef realloc
158da2e3ebdSchin #undef valloc
159*b30d1939SAndy Fiddaman 
160*b30d1939SAndy Fiddaman #if _malloc_hook
161*b30d1939SAndy Fiddaman 
162*b30d1939SAndy Fiddaman #include <malloc.h>
163*b30d1939SAndy Fiddaman 
164*b30d1939SAndy Fiddaman #undef	calloc
165*b30d1939SAndy Fiddaman #undef	cfree
166*b30d1939SAndy Fiddaman #undef	free
167*b30d1939SAndy Fiddaman #undef	malloc
168*b30d1939SAndy Fiddaman #undef	memalign
169*b30d1939SAndy Fiddaman #undef	realloc
170*b30d1939SAndy Fiddaman 
171*b30d1939SAndy Fiddaman #define calloc		_ast_calloc
172*b30d1939SAndy Fiddaman #define cfree		_ast_cfree
173*b30d1939SAndy Fiddaman #define free		_ast_free
174*b30d1939SAndy Fiddaman #define malloc		_ast_malloc
175*b30d1939SAndy Fiddaman #define memalign	_ast_memalign
176*b30d1939SAndy Fiddaman #define realloc		_ast_realloc
177*b30d1939SAndy Fiddaman 
178*b30d1939SAndy Fiddaman #endif
179*b30d1939SAndy Fiddaman 
180da2e3ebdSchin #endif
182da2e3ebdSchin #if _WINIX
184da2e3ebdSchin #include <ast_windows.h>
186da2e3ebdSchin #if _UWIN
188da2e3ebdSchin #define VMRECORD(p)	_vmrecord(p)
189da2e3ebdSchin #define VMBLOCK		{ int _vmblock = _sigblock();
190da2e3ebdSchin #define VMUNBLOCK	_sigunblock(_vmblock); }
192da2e3ebdSchin extern int		_sigblock(void);
193da2e3ebdSchin extern void		_sigunblock(int);
194da2e3ebdSchin extern unsigned long	_record[2048];
_vmrecord(Void_t * p)196da2e3ebdSchin __inline Void_t* _vmrecord(Void_t* p)
197da2e3ebdSchin {
198da2e3ebdSchin 	register unsigned long	v = ((unsigned long)p)>>16;
200da2e3ebdSchin 	_record[v>>5] |= 1<<((v&0x1f));
201da2e3ebdSchin 	return p;
202da2e3ebdSchin }
204da2e3ebdSchin #else
206da2e3ebdSchin #define getenv(s)	lcl_getenv(s)
208da2e3ebdSchin static char*
lcl_getenv(const char * s)209da2e3ebdSchin lcl_getenv(const char* s)
210da2e3ebdSchin {
211da2e3ebdSchin 	int		n;
212da2e3ebdSchin 	static char	buf[512];
214da2e3ebdSchin 	if (!(n = GetEnvironmentVariable(s, buf, sizeof(buf))) || n > sizeof(buf))
215da2e3ebdSchin 		return 0;
216da2e3ebdSchin 	return buf;
217da2e3ebdSchin }
219da2e3ebdSchin #endif /* _UWIN */
221da2e3ebdSchin #endif /* _WINIX */
223da2e3ebdSchin #ifndef VMRECORD
224da2e3ebdSchin #define VMRECORD(p)	(p)
225da2e3ebdSchin #define VMBLOCK
226da2e3ebdSchin #define VMUNBLOCK
227da2e3ebdSchin #endif
229da2e3ebdSchin #if defined(__EXPORT__)
230da2e3ebdSchin #define extern		extern __EXPORT__
231da2e3ebdSchin #endif
233da2e3ebdSchin static int		_Vmflinit = 0;
234da2e3ebdSchin #define VMFLINIT() \
235da2e3ebdSchin 	{ if(!_Vmflinit)	vmflinit(); \
236da2e3ebdSchin 	  if(_Vmdbcheck) \
237da2e3ebdSchin 	  { if(_Vmdbtime < _Vmdbstart) _Vmdbtime += 1; \
238da2e3ebdSchin 	    else if((_Vmdbtime += 1) < _Vmdbstart) _Vmdbtime = _Vmdbstart; \
239da2e3ebdSchin 	    if(_Vmdbtime >= _Vmdbstart && (_Vmdbtime % _Vmdbcheck) == 0 && \
240da2e3ebdSchin 	       Vmregion->meth.meth == VM_MTDEBUG) \
241da2e3ebdSchin 		vmdbcheck(Vmregion); \
242da2e3ebdSchin 	  } \
243da2e3ebdSchin 	}
245da2e3ebdSchin #if __STD_C
vmflinit(void)246da2e3ebdSchin static int vmflinit(void)
247da2e3ebdSchin #else
248da2e3ebdSchin static int vmflinit()
249da2e3ebdSchin #endif
250da2e3ebdSchin {
251da2e3ebdSchin 	char*		file;
252da2e3ebdSchin 	int		line;
253da2e3ebdSchin 	Void_t*		func;
255da2e3ebdSchin 	/* this must be done now to avoid any inadvertent recursion (more below) */
256da2e3ebdSchin 	_Vmflinit = 1;
257da2e3ebdSchin 	VMFLF(Vmregion,file,line,func);
2593e14f97fSRoger A. Faulkner 	/* if getenv() calls malloc(), the options may not affect the eventual region */
2603e14f97fSRoger A. Faulkner 	VMOPTIONS();
262da2e3ebdSchin 	/* reset file and line number to correct values for the call */
263da2e3ebdSchin 	Vmregion->file = file;
264da2e3ebdSchin 	Vmregion->line = line;
265da2e3ebdSchin 	Vmregion->func = func;
267da2e3ebdSchin 	return 0;
268da2e3ebdSchin }
270*b30d1939SAndy Fiddaman /* use multiple regions to reduce blocking by concurrent threads  */
271*b30d1939SAndy Fiddaman #if _mem_mmap_anon || _mem_mmap_zero
272*b30d1939SAndy Fiddaman static Vmalloc_t	*Region[64];	/* list of concurrent regions	*/
273*b30d1939SAndy Fiddaman static unsigned int	Regmax = 64;	/* max number of regions	*/
274*b30d1939SAndy Fiddaman #else
275*b30d1939SAndy Fiddaman static Vmalloc_t*	Region[1];	/* list of concurrent regions	*/
276*b30d1939SAndy Fiddaman static unsigned int	Regmax = 0;
277*b30d1939SAndy Fiddaman #endif
278*b30d1939SAndy Fiddaman static unsigned int	Regnum = 0; 	/* current #concurrent regions	*/
279*b30d1939SAndy Fiddaman 
280*b30d1939SAndy Fiddaman /* statistics */
281*b30d1939SAndy Fiddaman static unsigned int	Regopen = 0; 	/* #allocation calls opened	*/
282*b30d1939SAndy Fiddaman static unsigned int	Reglock = 0; 	/* #allocation calls locked	*/
283*b30d1939SAndy Fiddaman static unsigned int	Regprobe = 0; 	/* #probes to find a region	*/
284*b30d1939SAndy Fiddaman 
setregmax(int regmax)285*b30d1939SAndy Fiddaman int setregmax(int regmax)
286*b30d1939SAndy Fiddaman {
287*b30d1939SAndy Fiddaman 	int	oldmax = Regmax;
288*b30d1939SAndy Fiddaman 
289*b30d1939SAndy Fiddaman 	if(regmax >= Regnum && regmax <= sizeof(Region)/sizeof(Region[0]))
290*b30d1939SAndy Fiddaman 		Regmax = regmax;
291*b30d1939SAndy Fiddaman 
292*b30d1939SAndy Fiddaman 	return oldmax;
293*b30d1939SAndy Fiddaman }
294*b30d1939SAndy Fiddaman 
295*b30d1939SAndy Fiddaman /* return statistics */
_mallocstat(Vmstat_t * st)296*b30d1939SAndy Fiddaman int _mallocstat(Vmstat_t* st)
297*b30d1939SAndy Fiddaman {
298*b30d1939SAndy Fiddaman 	Vmstat_t	vmst;
299*b30d1939SAndy Fiddaman 	int		k;
300*b30d1939SAndy Fiddaman 
301*b30d1939SAndy Fiddaman 	if(vmstat(Vmregion, st) < 0) /* add up all stats */
302*b30d1939SAndy Fiddaman 		return -1;
303*b30d1939SAndy Fiddaman 	for(k = 0; k < Regnum; ++k)
304*b30d1939SAndy Fiddaman 	{	if(!Region[k])
305*b30d1939SAndy Fiddaman 			continue;
306*b30d1939SAndy Fiddaman 		if(vmstat(Region[k], &vmst) < 0 )
307*b30d1939SAndy Fiddaman 			return -1;
308*b30d1939SAndy Fiddaman 		st->n_busy += vmst.n_busy;
309*b30d1939SAndy Fiddaman 		st->n_free += vmst.n_free;
310*b30d1939SAndy Fiddaman 		st->s_busy += vmst.s_busy;
311*b30d1939SAndy Fiddaman 		st->s_free += vmst.s_free;
312*b30d1939SAndy Fiddaman 		st->m_busy += vmst.m_busy;
313*b30d1939SAndy Fiddaman 		st->m_free += vmst.m_free;
314*b30d1939SAndy Fiddaman 		st->n_seg  += vmst.n_seg;
315*b30d1939SAndy Fiddaman 		st->extent += vmst.extent;
316*b30d1939SAndy Fiddaman 	}
317*b30d1939SAndy Fiddaman 
318*b30d1939SAndy Fiddaman 	st->n_region = Regnum+1;
319*b30d1939SAndy Fiddaman 	st->n_open = Regopen;
320*b30d1939SAndy Fiddaman 	st->n_lock = Reglock;
321*b30d1939SAndy Fiddaman 	st->n_probe = Regprobe;
322*b30d1939SAndy Fiddaman 
323*b30d1939SAndy Fiddaman 	return 0;
324*b30d1939SAndy Fiddaman }
325*b30d1939SAndy Fiddaman 
326*b30d1939SAndy Fiddaman /* find the region that a block was allocated from */
regionof(Void_t * addr)327*b30d1939SAndy Fiddaman static Vmalloc_t* regionof(Void_t* addr)
328*b30d1939SAndy Fiddaman {
329*b30d1939SAndy Fiddaman 	int	k;
330*b30d1939SAndy Fiddaman 
331*b30d1939SAndy Fiddaman #if USE_NATIVE
332*b30d1939SAndy Fiddaman #define CAUTIOUS	1
333*b30d1939SAndy Fiddaman #else
334*b30d1939SAndy Fiddaman #define CAUTIOUS	0
335*b30d1939SAndy Fiddaman #endif
336*b30d1939SAndy Fiddaman 	if(CAUTIOUS || Vmregion->meth.meth != VM_MTBEST )
337*b30d1939SAndy Fiddaman 	{	/* addr will not be dereferenced here */
338*b30d1939SAndy Fiddaman 		if(vmaddr(Vmregion,addr) == 0 )
339*b30d1939SAndy Fiddaman 			return Vmregion;
340*b30d1939SAndy Fiddaman 		for(k = 0; k < Regnum; ++k)
341*b30d1939SAndy Fiddaman 			if(Region[k] && vmaddr(Region[k], addr) == 0 )
342*b30d1939SAndy Fiddaman 				return Region[k];
343*b30d1939SAndy Fiddaman 		return NIL(Vmalloc_t*);
344*b30d1939SAndy Fiddaman 	}
345*b30d1939SAndy Fiddaman 	else
346*b30d1939SAndy Fiddaman 	{	/* fast, but susceptible to bad data */
347*b30d1939SAndy Fiddaman 		Vmdata_t *vd = SEG(BLOCK(addr))->vmdt;
348*b30d1939SAndy Fiddaman 		if(Vmregion->data == vd )
349*b30d1939SAndy Fiddaman 			return Vmregion;
350*b30d1939SAndy Fiddaman 		for(k = 0; k < Regnum; ++k)
351*b30d1939SAndy Fiddaman 			if(Region[k] && Region[k]->data == vd)
352*b30d1939SAndy Fiddaman 				return Region[k];
353*b30d1939SAndy Fiddaman 		return NIL(Vmalloc_t*);
354*b30d1939SAndy Fiddaman 	}
355*b30d1939SAndy Fiddaman }
356*b30d1939SAndy Fiddaman 
357*b30d1939SAndy Fiddaman /* manage a cache of free objects */
358*b30d1939SAndy Fiddaman typedef struct _regfree_s
359*b30d1939SAndy Fiddaman {	struct _regfree_s*	next;
360*b30d1939SAndy Fiddaman } Regfree_t;
361*b30d1939SAndy Fiddaman static Regfree_t	*Regfree;
362*b30d1939SAndy Fiddaman 
addfreelist(Regfree_t * data)363*b30d1939SAndy Fiddaman static void addfreelist(Regfree_t* data)
364*b30d1939SAndy Fiddaman {
365*b30d1939SAndy Fiddaman 	unsigned int	k;
366*b30d1939SAndy Fiddaman 	Regfree_t	*head;
367*b30d1939SAndy Fiddaman 
368*b30d1939SAndy Fiddaman 	for(k = 0;; ASOLOOP(k) )
369*b30d1939SAndy Fiddaman 	{	data->next = head = Regfree;
370*b30d1939SAndy Fiddaman 		if(asocasptr(&Regfree, head, data) == (Void_t*)head )
371*b30d1939SAndy Fiddaman 			return;
372*b30d1939SAndy Fiddaman 	}
373*b30d1939SAndy Fiddaman }
374*b30d1939SAndy Fiddaman 
clrfreelist()375*b30d1939SAndy Fiddaman static void clrfreelist()
376*b30d1939SAndy Fiddaman {
377*b30d1939SAndy Fiddaman 	Regfree_t	*list, *next;
378*b30d1939SAndy Fiddaman 	Vmalloc_t	*vm;
379*b30d1939SAndy Fiddaman 
380*b30d1939SAndy Fiddaman 	if(!(list = Regfree) )
381*b30d1939SAndy Fiddaman 		return; /* nothing to do */
382*b30d1939SAndy Fiddaman 
383*b30d1939SAndy Fiddaman 	if(asocasptr(&Regfree, list, NIL(Regfree_t*)) != list )
384*b30d1939SAndy Fiddaman 		return; /* somebody else is doing it */
385*b30d1939SAndy Fiddaman 
386*b30d1939SAndy Fiddaman 	for(; list; list = next)
387*b30d1939SAndy Fiddaman 	{	next = list->next;
388*b30d1939SAndy Fiddaman 		if(vm = regionof((Void_t*)list))
389*b30d1939SAndy Fiddaman 		{	if(asocasint(&vm->data->lock, 0, 1) == 0) /* can free this now */
390*b30d1939SAndy Fiddaman 			{	(void)(*vm->meth.freef)(vm, (Void_t*)list, 1);
391*b30d1939SAndy Fiddaman 				vm->data->lock = 0;
392*b30d1939SAndy Fiddaman 			}
393*b30d1939SAndy Fiddaman 			else	addfreelist(list); /* ah well, back in the queue */
394*b30d1939SAndy Fiddaman 		}
395*b30d1939SAndy Fiddaman 	}
396*b30d1939SAndy Fiddaman }
397*b30d1939SAndy Fiddaman 
398*b30d1939SAndy Fiddaman /* get a suitable region to allocate from */
399*b30d1939SAndy Fiddaman typedef struct _regdisc_s
400*b30d1939SAndy Fiddaman {	Vmdisc_t	disc;
401*b30d1939SAndy Fiddaman 	char		slop[64]; /* to absorb any extra data in Vmdcsystem */
402*b30d1939SAndy Fiddaman } Regdisc_t;
403*b30d1939SAndy Fiddaman 
regexcept(Vmalloc_t * vm,int type,Void_t * data,Vmdisc_t * disc)404*b30d1939SAndy Fiddaman static int regexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc)
405*b30d1939SAndy Fiddaman {
406*b30d1939SAndy Fiddaman 	if(type == VM_OPEN)
407*b30d1939SAndy Fiddaman 	{	if(data) /* make vmopen allocate all memory using discipline */
408*b30d1939SAndy Fiddaman 			*(Void_t**)data = data; /* just make it non-NULL */
409*b30d1939SAndy Fiddaman 		return 0;
410*b30d1939SAndy Fiddaman 	}
411*b30d1939SAndy Fiddaman 	return 0;
412*b30d1939SAndy Fiddaman }
413*b30d1939SAndy Fiddaman 
getregion(int * local)414*b30d1939SAndy Fiddaman static Vmalloc_t* getregion(int* local)
415*b30d1939SAndy Fiddaman {
416*b30d1939SAndy Fiddaman 	Vmalloc_t		*vm;
417*b30d1939SAndy Fiddaman 	int			p, pos;
418*b30d1939SAndy Fiddaman 
419*b30d1939SAndy Fiddaman 	static unsigned int	Rand = 0xdeadbeef; /* a cheap prng */
420*b30d1939SAndy Fiddaman #define RAND()			(Rand = Rand*16777617 + 3)
421*b30d1939SAndy Fiddaman 
422*b30d1939SAndy Fiddaman 	clrfreelist();
423*b30d1939SAndy Fiddaman 
424*b30d1939SAndy Fiddaman 	if(Regmax <= 0 )
425*b30d1939SAndy Fiddaman 	{	/* uni-process/thread */
426*b30d1939SAndy Fiddaman 		*local = 1;
427*b30d1939SAndy Fiddaman 		Vmregion->data->lock = 1;
428*b30d1939SAndy Fiddaman 		return Vmregion;
429*b30d1939SAndy Fiddaman 	}
430*b30d1939SAndy Fiddaman 	else if(asocasint(&Vmregion->data->lock, 0, 1) == 0 )
431*b30d1939SAndy Fiddaman 	{	/* Vmregion is open, so use it */
432*b30d1939SAndy Fiddaman 		*local = 1;
433*b30d1939SAndy Fiddaman 		asoincint(&Regopen);
434*b30d1939SAndy Fiddaman 		return Vmregion;
435*b30d1939SAndy Fiddaman 	}
436*b30d1939SAndy Fiddaman 
437*b30d1939SAndy Fiddaman 	asoincint(&Regprobe); /* probe Region[] to find an open region */
438*b30d1939SAndy Fiddaman 	if(Regnum == 0)
439*b30d1939SAndy Fiddaman 		pos = 0;
440*b30d1939SAndy Fiddaman 	else for(pos = p = RAND()%Regnum;; )
441*b30d1939SAndy Fiddaman 	{	if(Region[p] && asocasint(&Region[p]->data->lock, 0, 1) == 0 )
442*b30d1939SAndy Fiddaman 		{	*local = 1;
443*b30d1939SAndy Fiddaman 			asoincint(&Regopen);
444*b30d1939SAndy Fiddaman 			return Region[p];
445*b30d1939SAndy Fiddaman 		}
446*b30d1939SAndy Fiddaman 		if((p = (p+1)%Regnum) == pos )
447*b30d1939SAndy Fiddaman 			break;
448*b30d1939SAndy Fiddaman 	}
449*b30d1939SAndy Fiddaman 
450*b30d1939SAndy Fiddaman 	/* grab the next open slot for a new region */
451*b30d1939SAndy Fiddaman 	while((p = Regnum) < Regmax)
452*b30d1939SAndy Fiddaman 		if(asocasint(&Regnum, p, p+1) == p )
453*b30d1939SAndy Fiddaman 			break;
454*b30d1939SAndy Fiddaman 	if(p < Regmax) /* this slot is now ours */
455*b30d1939SAndy Fiddaman 	{	static Regdisc_t	Regdisc;
456*b30d1939SAndy Fiddaman 		if(!Regdisc.disc.exceptf) /* one time initialization */
457*b30d1939SAndy Fiddaman 		{	GETPAGESIZE(_Vmpagesize);
458*b30d1939SAndy Fiddaman 			memcpy(&Regdisc, Vmdcsystem, Vmdcsystem->size);
459*b30d1939SAndy Fiddaman 			Regdisc.disc.round = ROUND(_Vmpagesize, 64*1024);
460*b30d1939SAndy Fiddaman 			Regdisc.disc.exceptf = regexcept;
461*b30d1939SAndy Fiddaman 		}
462*b30d1939SAndy Fiddaman 
463*b30d1939SAndy Fiddaman 		/**/ASSERT(Region[p] == NIL(Vmalloc_t*));
464*b30d1939SAndy Fiddaman 		if((vm = vmopen(&Regdisc.disc, Vmbest, VM_SHARE)) != NIL(Vmalloc_t*) )
465*b30d1939SAndy Fiddaman 		{	vm->data->lock = 1; /* lock new region now */
466*b30d1939SAndy Fiddaman 			*local = 1;
467*b30d1939SAndy Fiddaman 			asoincint(&Regopen);
468*b30d1939SAndy Fiddaman 			return (Region[p] = vm);
469*b30d1939SAndy Fiddaman 		}
470*b30d1939SAndy Fiddaman 		else	Region[p] = Vmregion; /* better than nothing */
471*b30d1939SAndy Fiddaman 	}
472*b30d1939SAndy Fiddaman 
473*b30d1939SAndy Fiddaman 	/* must return something */
474*b30d1939SAndy Fiddaman 	vm = Region[pos] ? Region[pos] : Vmregion;
475*b30d1939SAndy Fiddaman 	if(asocasint(&vm->data->lock, 0, 1) == 0)
476*b30d1939SAndy Fiddaman 	{	*local = 1;
477*b30d1939SAndy Fiddaman 		asoincint(&Regopen);
478*b30d1939SAndy Fiddaman 	}
479*b30d1939SAndy Fiddaman 	else
480*b30d1939SAndy Fiddaman 	{	*local = 0;
481*b30d1939SAndy Fiddaman 		asoincint(&Reglock);
482*b30d1939SAndy Fiddaman 	}
483*b30d1939SAndy Fiddaman 	return vm;
484*b30d1939SAndy Fiddaman }
485*b30d1939SAndy Fiddaman 
486da2e3ebdSchin #if __STD_C
calloc(reg size_t n_obj,reg size_t s_obj)487da2e3ebdSchin extern Void_t* calloc(reg size_t n_obj, reg size_t s_obj)
488da2e3ebdSchin #else
489da2e3ebdSchin extern Void_t* calloc(n_obj, s_obj)
490da2e3ebdSchin reg size_t	n_obj;
491da2e3ebdSchin reg size_t	s_obj;
492da2e3ebdSchin #endif
493da2e3ebdSchin {
494*b30d1939SAndy Fiddaman 	Void_t		*addr;
495*b30d1939SAndy Fiddaman 	Vmalloc_t	*vm;
496*b30d1939SAndy Fiddaman 	int		local = 0;
497da2e3ebdSchin 	VMFLINIT();
498*b30d1939SAndy Fiddaman 
499*b30d1939SAndy Fiddaman 	vm = getregion(&local);
500*b30d1939SAndy Fiddaman 	addr = (*vm->meth.resizef)(vm, NIL(Void_t*), n_obj*s_obj, VM_RSZERO, local);
501*b30d1939SAndy Fiddaman 	if(local)
502*b30d1939SAndy Fiddaman 	{	/**/ASSERT(vm->data->lock == 1);
503*b30d1939SAndy Fiddaman 		vm->data->lock = 0;
504*b30d1939SAndy Fiddaman 	}
505*b30d1939SAndy Fiddaman 	return VMRECORD(addr);
506da2e3ebdSchin }
508da2e3ebdSchin #if __STD_C
malloc(reg size_t size)509da2e3ebdSchin extern Void_t* malloc(reg size_t size)
510da2e3ebdSchin #else
511da2e3ebdSchin extern Void_t* malloc(size)
512da2e3ebdSchin reg size_t	size;
513da2e3ebdSchin #endif
514da2e3ebdSchin {
515*b30d1939SAndy Fiddaman 	Void_t		*addr;
516*b30d1939SAndy Fiddaman 	Vmalloc_t	*vm;
517*b30d1939SAndy Fiddaman 	int		local = 0;
518da2e3ebdSchin 	VMFLINIT();
519*b30d1939SAndy Fiddaman 
520*b30d1939SAndy Fiddaman 	vm = getregion(&local);
521*b30d1939SAndy Fiddaman 	addr = (*vm->meth.allocf)(vm, size, local);
522*b30d1939SAndy Fiddaman 	if(local)
523*b30d1939SAndy Fiddaman 	{	/**/ASSERT(vm->data->lock == 1);
524*b30d1939SAndy Fiddaman 		vm->data->lock = 0;
525*b30d1939SAndy Fiddaman 	}
526*b30d1939SAndy Fiddaman 	return VMRECORD(addr);
527da2e3ebdSchin }
529da2e3ebdSchin #if __STD_C
realloc(reg Void_t * data,reg size_t size)530da2e3ebdSchin extern Void_t* realloc(reg Void_t* data, reg size_t size)
531da2e3ebdSchin #else
532da2e3ebdSchin extern Void_t* realloc(data,size)
533da2e3ebdSchin reg Void_t*	data;	/* block to be reallocated	*/
534da2e3ebdSchin reg size_t	size;	/* new size			*/
535da2e3ebdSchin #endif
536da2e3ebdSchin {
537*b30d1939SAndy Fiddaman 	ssize_t		copy;
538*b30d1939SAndy Fiddaman 	Void_t		*addr;
539*b30d1939SAndy Fiddaman 	Vmalloc_t	*vm;
540da2e3ebdSchin 	VMFLINIT();
542*b30d1939SAndy Fiddaman 	if(!data)
543*b30d1939SAndy Fiddaman 		return malloc(size);
544*b30d1939SAndy Fiddaman 	else if((vm = regionof(data)) )
545*b30d1939SAndy Fiddaman 	{	if(vm == Vmregion && vm != Vmheap) /* no multiple region usage here */
546*b30d1939SAndy Fiddaman 		{	addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 0);
547*b30d1939SAndy Fiddaman 			return VMRECORD(addr);
548*b30d1939SAndy Fiddaman 		}
549*b30d1939SAndy Fiddaman 		if(asocasint(&vm->data->lock, 0, 1) == 0 ) /* region is open */
550*b30d1939SAndy Fiddaman 		{	addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 1);
551*b30d1939SAndy Fiddaman 			vm->data->lock = 0;
552*b30d1939SAndy Fiddaman 			return VMRECORD(addr);
553*b30d1939SAndy Fiddaman 		}
554*b30d1939SAndy Fiddaman 		else if(Regmax > 0 && Vmregion == Vmheap && (addr = malloc(size)) )
555*b30d1939SAndy Fiddaman 		{	if((copy = SIZE(BLOCK(data))&~BITS) > size )
556*b30d1939SAndy Fiddaman 				copy = size;
557*b30d1939SAndy Fiddaman 			memcpy(addr, data, copy);
558*b30d1939SAndy Fiddaman 			addfreelist((Regfree_t*)data);
559*b30d1939SAndy Fiddaman 			return VMRECORD(addr);
560*b30d1939SAndy Fiddaman 		}
561*b30d1939SAndy Fiddaman 		else /* this may block but it is the best that we can do now */
562*b30d1939SAndy Fiddaman 		{	addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 0);
563*b30d1939SAndy Fiddaman 			return VMRECORD(addr);
564*b30d1939SAndy Fiddaman 		}
565*b30d1939SAndy Fiddaman 	}
566*b30d1939SAndy Fiddaman 	else /* not our data */
567*b30d1939SAndy Fiddaman 	{
568da2e3ebdSchin #if USE_NATIVE
569*b30d1939SAndy Fiddaman #undef	realloc /* let the native realloc() take care of it */
570*b30d1939SAndy Fiddaman #if __STD_C
571*b30d1939SAndy Fiddaman 		extern Void_t*	realloc(Void_t*, size_t);
572da2e3ebdSchin #else
573*b30d1939SAndy Fiddaman 		extern Void_t*	realloc();
574da2e3ebdSchin #endif
575*b30d1939SAndy Fiddaman 		return realloc(data, size);
576*b30d1939SAndy Fiddaman #else
577*b30d1939SAndy Fiddaman 		return NIL(Void_t*);
578da2e3ebdSchin #endif
579da2e3ebdSchin 	}
580da2e3ebdSchin }
582da2e3ebdSchin #if __STD_C
free(reg Void_t * data)583da2e3ebdSchin extern void free(reg Void_t* data)
584da2e3ebdSchin #else
585da2e3ebdSchin extern void free(data)
586da2e3ebdSchin reg Void_t*	data;
587da2e3ebdSchin #endif
588da2e3ebdSchin {
589*b30d1939SAndy Fiddaman 	Vmalloc_t	*vm;
590da2e3ebdSchin 	VMFLINIT();
592*b30d1939SAndy Fiddaman 	if(!data || (_Vmassert & VM_keep))
593*b30d1939SAndy Fiddaman 		return;
594*b30d1939SAndy Fiddaman 	else if((vm = regionof(data)) )
595*b30d1939SAndy Fiddaman 	{
596*b30d1939SAndy Fiddaman 		if(vm == Vmregion && Vmregion != Vmheap || (_Vmassert & VM_free))
597*b30d1939SAndy Fiddaman 			(void)(*vm->meth.freef)(vm, data, 0);
598*b30d1939SAndy Fiddaman