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_vmprofile(){}
25
26#else
27
28#include	"vmhdr.h"
29
30/*	Method to profile space usage.
31**
32**	Written by Kiem-Phong Vo, kpv@research.att.com, 03/23/94.
33*/
34
35#define PFHASH(pf)	((pf)->data.data.hash)
36#define PFVM(pf)	((pf)->data.data.vm)
37#define PFFILE(pf)	((pf)->data.data.fm.file)
38#define PFLINE(pf)	((pf)->line)
39#define PFNAME(pf)	((pf)->data.f)
40#define PFNALLOC(pf)	((pf)->data.data.nalloc)
41#define PFALLOC(pf)	((pf)->data.data.alloc)
42#define PFNFREE(pf)	((pf)->data.data.nfree)
43#define PFFREE(pf)	((pf)->data.data.free)
44#define PFREGION(pf)	((pf)->data.data.region)
45#define PFMAX(pf)	((pf)->data.data.fm.max)
46
47typedef struct _pfdata_s	Pfdata_t;
48struct _pfdata_s
49{	Vmulong_t	hash;	/* hash value			*/
50	union
51	{ char*		file;	/* file name			*/
52	  Vmulong_t	max;	/* max busy space for region	*/
53	} fm;
54	Vmalloc_t*	vm;	/* region alloc from 		*/
55	Pfobj_t*	region;	/* pointer to region record	*/
56	Vmulong_t	nalloc;	/* number of alloc calls	*/
57	Vmulong_t	alloc;	/* amount allocated		*/
58	Vmulong_t	nfree;	/* number of free calls		*/
59	Vmulong_t	free;	/* amount freed			*/
60};
61struct _pfobj_s
62{	Pfobj_t*	next;	/* next in linked list	*/
63	int		line;	/* line #, 0 for name holder	*/
64	union
65	{
66	Pfdata_t	data;
67	char		f[1];	/* actual file name		*/
68	} data;
69};
70
71static Pfobj_t**	Pftable;	/* hash table		*/
72#define PFTABLE		1019		/* table size		*/
73static Vmalloc_t*	Vmpf;		/* heap for our own use	*/
74
75#if __STD_C
76static Pfobj_t* pfsearch(Vmalloc_t* vm, const char* file, int line)
77#else
78static Pfobj_t* pfsearch(vm, file, line)
79Vmalloc_t*	vm;	/* region allocating from			*/
80const char*	file;	/* the file issuing the allocation request	*/
81int		line;	/* line number					*/
82#endif
83{
84	reg Pfobj_t		*pf, *last;
85	reg Vmulong_t		h;
86	reg int			n;
87	reg const char*		cp;
88
89	if(!Vmpf && !(Vmpf = vmopen(Vmdcheap,Vmpool,0)) )
90		return NIL(Pfobj_t*);
91
92	/* make hash table; PFTABLE'th slot hold regions' records */
93	if(!Pftable)
94	{	if(!(Pftable = (Pfobj_t**)vmalloc(Vmheap,(PFTABLE+1)*sizeof(Pfobj_t*))) )
95			return NIL(Pfobj_t*);
96		for(n = PFTABLE; n >= 0; --n)
97			Pftable[n] = NIL(Pfobj_t*);
98	}
99
100	/* see if it's there with a combined hash value of vm,file,line */
101	h = line + (((Vmulong_t)vm)>>4);
102	for(cp = file; *cp; ++cp)
103		h += (h<<7) + ((*cp)&0377) + 987654321L;
104	n = (int)(h%PFTABLE);
105	for(last = NIL(Pfobj_t*), pf = Pftable[n]; pf; last = pf, pf = pf->next)
106		if(PFLINE(pf) == line && PFVM(pf) == vm && strcmp(PFFILE(pf),file) == 0)
107			break;
108
109	/* insert if not there yet */
110	if(!pf)
111	{	reg Pfobj_t*	fn;
112		reg Pfobj_t*	pfvm;
113		reg Vmulong_t	hn;
114
115		/* first get/construct the file name slot */
116		hn = 0;
117		for(cp = file; *cp; ++cp)
118			hn += (hn<<7) + ((*cp)&0377) + 987654321L;
119		n = (int)(hn%PFTABLE);
120		for(fn = Pftable[n]; fn; fn = fn->next)
121			if(PFLINE(fn) < 0 && strcmp(PFNAME(fn),file) == 0)
122				break;
123		if(!fn)
124		{	reg size_t	s;
125			s = sizeof(Pfobj_t) - sizeof(Pfdata_t) + strlen(file) + 1;
126			if(!(fn = (Pfobj_t*)vmalloc(Vmheap,s)) )
127				return NIL(Pfobj_t*);
128			fn->next = Pftable[n];
129			Pftable[n] = fn;
130			PFLINE(fn) = -1;
131			strcpy(PFNAME(fn),file);
132		}
133
134		/* get region record; note that these are ordered by vm */
135		last = NIL(Pfobj_t*);
136		for(pfvm = Pftable[PFTABLE]; pfvm; last = pfvm, pfvm = pfvm->next)
137			if(vm >= PFVM(pfvm))
138				break;
139		if(!pfvm || PFVM(pfvm) > vm)
140		{	if(!(pfvm = (Pfobj_t*)vmalloc(Vmpf,sizeof(Pfobj_t))) )
141				return NIL(Pfobj_t*);
142			if(last)
143			{	pfvm->next = last->next;
144				last->next = pfvm;
145			}
146			else
147			{	pfvm->next = Pftable[PFTABLE];
148				Pftable[PFTABLE] = pfvm;
149			}
150			PFNALLOC(pfvm) = PFALLOC(pfvm) = 0;
151			PFNFREE(pfvm) = PFFREE(pfvm) = 0;
152			PFMAX(pfvm) = 0;
153			PFVM(pfvm) = vm;
154			PFLINE(pfvm) = 0;
155		}
156
157		if(!(pf = (Pfobj_t*)vmalloc(Vmpf,sizeof(Pfobj_t))) )
158			return NIL(Pfobj_t*);
159		n = (int)(h%PFTABLE);
160		pf->next = Pftable[n];
161		Pftable[n] = pf;
162		PFLINE(pf) = line;
163		PFFILE(pf) = PFNAME(fn);
164		PFREGION(pf) = pfvm;
165		PFVM(pf) = vm;
166		PFNALLOC(pf) = 0;
167		PFALLOC(pf) = 0;
168		PFNFREE(pf) = 0;
169		PFFREE(pf) = 0;
170		PFHASH(pf) = h;
171	}
172	else if(last)	/* do a move-to-front */
173	{	last->next = pf->next;
174		pf->next = Pftable[n];
175		Pftable[n] = pf;
176	}
177
178	return pf;
179}
180
181#if __STD_C
182static void pfclose(Vmalloc_t* vm)
183#else
184static void pfclose(vm)
185Vmalloc_t*	vm;
186#endif
187{
188	reg int		n;
189	reg Pfobj_t	*pf, *next, *last;
190
191	/* free all records related to region vm */
192	for(n = PFTABLE; n >= 0; --n)
193	{	for(last = NIL(Pfobj_t*), pf = Pftable[n]; pf; )
194		{	next = pf->next;
195
196			if(PFLINE(pf) >= 0 && PFVM(pf) == vm)
197			{	if(last)
198					last->next = next;
199				else	Pftable[n] = next;
200				vmfree(Vmpf,pf);
201			}
202			else	last = pf;
203
204			pf = next;
205		}
206	}
207}
208
209#if __STD_C
210static void pfsetinfo(Vmalloc_t* vm, Vmuchar_t* data, size_t size, const char* file, int line)
211#else
212static void pfsetinfo(vm, data, size, file, line)
213Vmalloc_t*	vm;
214Vmuchar_t*	data;
215size_t		size;
216const char*	file;
217int		line;
218#endif
219{
220	reg Pfobj_t*	pf;
221	reg Vmulong_t	s;
222
223	/* let vmclose knows that there are records for region vm */
224	_Vmpfclose = pfclose;
225
226	if(!file || line <= 0)
227	{	file = "";
228		line = 0;
229	}
230
231	if((pf = pfsearch(vm,file,line)) )
232	{	PFALLOC(pf) += size;
233		PFNALLOC(pf) += 1;
234	}
235	PFOBJ(data) = pf;
236	PFSIZE(data) = size;
237
238	if(pf)
239	{	/* update region statistics */
240		pf = PFREGION(pf);
241		PFALLOC(pf) += size;
242		PFNALLOC(pf) += 1;
243		if((s = PFALLOC(pf) - PFFREE(pf)) > PFMAX(pf) )
244			PFMAX(pf) = s;
245	}
246}
247
248/* sort by file names and line numbers */
249#if __STD_C
250static Pfobj_t* pfsort(Pfobj_t* pf)
251#else
252static Pfobj_t* pfsort(pf)
253Pfobj_t*	pf;
254#endif
255{
256	reg Pfobj_t	*one, *two, *next;
257	reg int		cmp;
258
259	if(!pf->next)
260		return pf;
261
262	/* partition to two equal size lists */
263	one = two = NIL(Pfobj_t*);
264	while(pf)
265	{	next = pf->next;
266		pf->next = one;
267		one = pf;
268
269		if((pf = next) )
270		{	next = pf->next;
271			pf->next = two;
272			two = pf;
273			pf = next;
274		}
275	}
276
277	/* sort and merge the lists */
278	one = pfsort(one);
279	two = pfsort(two);
280	for(pf = next = NIL(Pfobj_t*);; )
281	{	/* make sure that the "<>" file comes first */
282		if(PFLINE(one) == 0 && PFLINE(two) == 0)
283			cmp = PFVM(one) > PFVM(two) ? 1 : -1;
284		else if(PFLINE(one) == 0)
285			cmp = -1;
286		else if(PFLINE(two) == 0)
287			cmp = 1;
288		else if((cmp = strcmp(PFFILE(one),PFFILE(two))) == 0)
289		{	cmp = PFLINE(one) - PFLINE(two);
290			if(cmp == 0)
291				cmp = PFVM(one) > PFVM(two) ? 1 : -1;
292		}
293
294		if(cmp < 0)
295		{	if(!pf)
296				pf = one;
297			else	next->next = one;
298			next = one;
299			if(!(one = one->next) )
300			{	if(two)
301					next->next = two;
302				return pf;
303			}
304		}
305		else
306		{	if(!pf)
307				pf = two;
308			else	next->next = two;
309			next = two;
310			if(!(two = two->next) )
311			{	if(one)
312					next->next = one;
313				return pf;
314			}
315		}
316	}
317}
318
319#if __STD_C
320static char* pfsummary(char* buf, Vmulong_t na, Vmulong_t sa,
321			Vmulong_t nf, Vmulong_t sf, Vmulong_t max, Vmulong_t size)
322#else
323static char* pfsummary(buf, na, sa, nf, sf, max, size)
324char*		buf;
325Vmulong_t	na;
326Vmulong_t	sa;
327Vmulong_t	nf;
328Vmulong_t	sf;
329Vmulong_t	max;
330Vmulong_t	size;
331#endif
332{
333	buf = (*_Vmstrcpy)(buf,"n_alloc", '=');
334	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(na,-1), ':');
335	buf = (*_Vmstrcpy)(buf,"n_free", '=');
336	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(nf,-1), ':');
337	buf = (*_Vmstrcpy)(buf,"s_alloc", '=');
338	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(sa,-1), ':');
339	buf = (*_Vmstrcpy)(buf,"s_free", '=');
340	buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(sf,-1), ':');
341	if(max > 0)
342	{	buf = (*_Vmstrcpy)(buf,"max_busy", '=');
343		buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(max,-1), ':');
344		buf = (*_Vmstrcpy)(buf,"extent", '=');
345		buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(size,-1), ':');
346	}
347	*buf++ = '\n';
348
349	return buf;
350}
351
352/* print profile data */
353#if __STD_C
354int vmprofile(Vmalloc_t* vm, int fd)
355#else
356int vmprofile(vm, fd)
357Vmalloc_t*	vm;
358int		fd;
359#endif
360{
361	reg Pfobj_t	*pf, *list, *next, *last;
362	reg int		n;
363	reg Vmulong_t	nalloc, alloc, nfree, free;
364	reg Seg_t*	seg;
365	char		buf[1024], *bufp, *endbuf;
366#define INITBUF()	(bufp = buf, endbuf = buf+sizeof(buf)-128)
367#define CHKBUF()	(bufp >= endbuf ? (write(fd,buf,bufp-buf), bufp=buf) : bufp)
368#define FLSBUF()	(bufp > buf ? write(fd,buf,bufp-buf) : 0)
369
370	if(fd < 0)
371		return -1;
372
373	/* initialize functions from vmtrace.c that we use below */
374	if((n = vmtrace(-1)) >= 0)
375		vmtrace(n);
376
377	alloc = free = nalloc = nfree = 0;
378	list = NIL(Pfobj_t*);
379	for(n = PFTABLE-1; n >= 0; --n)
380	{	for(pf = Pftable[n], last = NIL(Pfobj_t*); pf; )
381		{	next = pf->next;
382
383			if(PFLINE(pf) < 0  || (vm && vm != PFVM(pf)) )
384			{	last = pf;
385				goto next_pf;
386			}
387
388			/* remove from hash table */
389			if(last)
390				last->next = next;
391			else	Pftable[n] = next;
392
393			/* put on output list */
394			pf->next = list;
395			list = pf;
396			nalloc += PFNALLOC(pf);
397			alloc += PFALLOC(pf);
398			nfree += PFNFREE(pf);
399			free += PFFREE(pf);
400
401		next_pf:
402			pf = next;
403		}
404	}
405
406	INITBUF();
407	bufp = (*_Vmstrcpy)(bufp,"ALLOCATION USAGE SUMMARY", ':');
408	bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0);
409
410	/* print regions' summary data */
411	for(pf = Pftable[PFTABLE]; pf; pf = pf->next)
412	{	if(vm && PFVM(pf) != vm)
413			continue;
414		alloc = 0;
415		for(seg = PFVM(pf)->data->seg; seg; seg = seg->next)
416			alloc += seg->extent;
417		bufp = (*_Vmstrcpy)(bufp,"region", '=');
418		bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(PFVM(pf)),0), ':');
419		bufp = pfsummary(bufp,PFNALLOC(pf),PFALLOC(pf),
420				 PFNFREE(pf),PFFREE(pf),PFMAX(pf),alloc);
421	}
422
423	/* sort then output detailed profile */
424	list = pfsort(list);
425	for(pf = list; pf; )
426	{	/* compute summary for file */
427		alloc = free = nalloc = nfree = 0;
428		for(last = pf; last; last = last->next)
429		{	if(strcmp(PFFILE(last),PFFILE(pf)) != 0)
430				break;
431			nalloc += PFNALLOC(pf);
432			alloc += PFALLOC(last);
433			nfree += PFNFREE(last);
434			free += PFFREE(last);
435		}
436		CHKBUF();
437		bufp = (*_Vmstrcpy)(bufp,"file",'=');
438		bufp = (*_Vmstrcpy)(bufp,PFFILE(pf)[0] ? PFFILE(pf) : "<>" ,':');
439		bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0);
440
441		while(pf != last)	/* detailed data */
442		{	CHKBUF();
443			bufp = (*_Vmstrcpy)(bufp,"\tline",'=');
444			bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(PFLINE(pf),-1), ':');
445			bufp = (*_Vmstrcpy)(bufp, "region", '=');
446			bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(PFVM(pf)),0), ':');
447			bufp = pfsummary(bufp,PFNALLOC(pf),PFALLOC(pf),
448					 PFNFREE(pf),PFFREE(pf),0,0);
449
450			/* reinsert into hash table */
451			next = pf->next;
452			n = (int)(PFHASH(pf)%PFTABLE);
453			pf->next = Pftable[n];
454			Pftable[n] = pf;
455			pf = next;
456		}
457	}
458
459	FLSBUF();
460	return 0;
461}
462
463#if __STD_C
464static Void_t* pfalloc(Vmalloc_t* vm, size_t size)
465#else
466static Void_t* pfalloc(vm, size)
467Vmalloc_t*	vm;
468size_t		size;
469#endif
470{
471	reg size_t		s;
472	reg Void_t*		data;
473	reg char*		file;
474	reg int			line, local, inuse;
475	reg Void_t*		func;
476	reg Vmdata_t*		vd = vm->data;
477
478	VMFLF(vm,file,line,func);
479	SETINUSE(vd, inuse);
480	if(!(local = vd->mode&VM_TRUST) )
481	{	GETLOCAL(vd, local);
482		if(ISLOCK(vd, local))
483		{	CLRINUSE(vd, inuse);
484			return NIL(Void_t*);
485		}
486		SETLOCK(vd, local);
487	}
488
489	s = ROUND(size,ALIGN) + PF_EXTRA;
490	if(!(data = KPVALLOC(vm,s,(*(Vmbest->allocf))) ) )
491		goto done;
492
493	pfsetinfo(vm,(Vmuchar_t*)data,size,file,line);
494
495	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
496	{	vm->file = file; vm->line = line; vm->func = func;
497		(*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)data,size,0);
498	}
499done:
500	CLRLOCK(vd, local);
501	ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)data, vm->disc);
502	CLRINUSE(vd, inuse);
503	return data;
504}
505
506#if __STD_C
507static int pffree(Vmalloc_t* vm, Void_t* data)
508#else
509static int pffree(vm, data)
510Vmalloc_t*	vm;
511Void_t*		data;
512#endif
513{
514	reg Pfobj_t*		pf;
515	reg size_t		s;
516	reg char*		file;
517	reg int			line, rv, local, inuse;
518	reg Void_t*		func;
519	reg Vmdata_t*		vd = vm->data;
520
521	VMFLF(vm,file,line,func);
522
523	if(!data)
524		return 0;
525
526	SETINUSE(vd, inuse);
527	if(!(local = vd->mode&VM_TRUST) )
528	{	GETLOCAL(vd,local);
529		if(ISLOCK(vd,local))
530		{	CLRINUSE(vd, inuse);
531			return -1;
532		}
533		SETLOCK(vd,local);
534	}
535
536	if(KPVADDR(vm,data,Vmbest->addrf) != 0 )
537	{	if(vm->disc->exceptf)
538			(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
539		CLRLOCK(vd,0);
540		CLRINUSE(vd, inuse);
541		return -1;
542	}
543
544	pf = PFOBJ(data);
545	s = PFSIZE(data);
546	if(pf)
547	{	PFNFREE(pf) += 1;
548		PFFREE(pf) += s;
549		pf = PFREGION(pf);
550		PFNFREE(pf) += 1;
551		PFFREE(pf) += s;
552	}
553
554	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
555	{	vm->file = file; vm->line = line; vm->func = func;
556		(*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*),s,0);
557	}
558
559	rv = KPVFREE((vm), (Void_t*)data, (*Vmbest->freef));
560        CLRLOCK(vd,local);
561        ANNOUNCE(local, vm, VM_FREE, data, vm->disc);
562	CLRINUSE(vd, inuse);
563	return rv;
564}
565
566#if __STD_C
567static Void_t* pfresize(Vmalloc_t* vm, Void_t* data, size_t size, int type)
568#else
569static Void_t* pfresize(vm, data, size, type)
570Vmalloc_t*	vm;
571Void_t*		data;
572size_t		size;
573int		type;
574#endif
575{
576	reg Pfobj_t*		pf;
577	reg size_t		s;
578	reg size_t		news;
579	reg Void_t*		addr;
580	reg char*		file;
581	reg int			line, local, inuse;
582	reg Void_t*		func;
583	reg size_t		oldsize;
584	reg Vmdata_t*		vd = vm->data;
585
586	SETINUSE(vd, inuse);
587	if(!data)
588	{	oldsize = 0;
589		addr = pfalloc(vm,size);
590		goto done;
591	}
592	if(size == 0)
593	{	(void)pffree(vm,data);
594		CLRINUSE(vd, inuse);
595		return NIL(Void_t*);
596	}
597
598	VMFLF(vm,file,line,func);
599	if(!(local = vd->mode&VM_TRUST))
600	{	GETLOCAL(vd, local);
601		if(ISLOCK(vd, local))
602		{	CLRINUSE(vd, inuse);
603			return NIL(Void_t*);
604		}
605		SETLOCK(vd, local);
606	}
607
608	if(KPVADDR(vm,data,Vmbest->addrf) != 0 )
609	{	if(vm->disc->exceptf)
610			(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
611		CLRLOCK(vd, local);
612		CLRINUSE(vd, inuse);
613		return NIL(Void_t*);
614	}
615
616	pf = PFOBJ(data);
617	s = oldsize = PFSIZE(data);
618
619	news = ROUND(size,ALIGN) + PF_EXTRA;
620	if((addr = KPVRESIZE(vm,data,news,(type&~VM_RSZERO),Vmbest->resizef)) )
621	{	if(pf)
622		{	PFFREE(pf) += s;
623			PFNFREE(pf) += 1;
624			pf = PFREGION(pf);
625			PFFREE(pf) += s;
626			PFNFREE(pf) += 1;
627			pfsetinfo(vm,(Vmuchar_t*)addr,size,file,line);
628		}
629
630		if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
631		{	vm->file = file; vm->line = line; vm->func = func;
632			(*_Vmtrace)(vm,(Vmuchar_t*)data,(Vmuchar_t*)addr,size,0);
633		}
634	}
635	else if(pf)	/* reset old info */
636	{	PFALLOC(pf) -= s;
637		PFNALLOC(pf) -= 1;
638		pf = PFREGION(pf);
639		PFALLOC(pf) -= s;
640		PFNALLOC(pf) -= 1;
641		file = PFFILE(pf);
642		line = PFLINE(pf);
643		pfsetinfo(vm,(Vmuchar_t*)data,s,file,line);
644	}
645
646	CLRLOCK(vd, local);
647	ANNOUNCE(local, vm, VM_RESIZE, (Void_t*)addr, vm->disc);
648
649done:	if(addr && (type&VM_RSZERO) && oldsize < size)
650	{	reg Vmuchar_t *d = (Vmuchar_t*)addr+oldsize, *ed = (Vmuchar_t*)addr+size;
651		do { *d++ = 0; } while(d < ed);
652	}
653
654	CLRINUSE(vd, inuse);
655	return addr;
656}
657
658#if __STD_C
659static long pfsize(Vmalloc_t* vm, Void_t* addr)
660#else
661static long pfsize(vm, addr)
662Vmalloc_t*	vm;
663Void_t*		addr;
664#endif
665{
666	return (*Vmbest->addrf)(vm,addr) != 0 ? -1L : (long)PFSIZE(addr);
667}
668
669#if __STD_C
670static long pfaddr(Vmalloc_t* vm, Void_t* addr)
671#else
672static long pfaddr(vm, addr)
673Vmalloc_t*	vm;
674Void_t*		addr;
675#endif
676{
677	return (*Vmbest->addrf)(vm,addr);
678}
679
680#if __STD_C
681static int pfcompact(Vmalloc_t* vm)
682#else
683static int pfcompact(vm)
684Vmalloc_t*	vm;
685#endif
686{
687	return (*Vmbest->compactf)(vm);
688}
689
690#if __STD_C
691static Void_t* pfalign(Vmalloc_t* vm, size_t size, size_t align)
692#else
693static Void_t* pfalign(vm, size, align)
694Vmalloc_t*	vm;
695size_t		size;
696size_t		align;
697#endif
698{
699	reg size_t		s;
700	reg Void_t*		data;
701	reg char*		file;
702	reg int			line, local, inuse;
703	reg Void_t*		func;
704	reg Vmdata_t*		vd = vm->data;
705
706	VMFLF(vm,file,line,func);
707
708	SETINUSE(vd, inuse);
709	if(!(local = vd->mode&VM_TRUST) )
710	{	GETLOCAL(vd,local);
711		if(ISLOCK(vd, local))
712		{	CLRINUSE(vd, inuse);
713			return NIL(Void_t*);
714		}
715		SETLOCK(vd, local);
716	}
717
718	s = (size <= TINYSIZE ? TINYSIZE : ROUND(size,ALIGN)) + PF_EXTRA;
719	if(!(data = KPVALIGN(vm,s,align,Vmbest->alignf)) )
720		goto done;
721
722	pfsetinfo(vm,(Vmuchar_t*)data,size,file,line);
723
724	if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
725	{	vm->file = file; vm->line = line; vm->func = func;
726		(*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)data,size,align);
727	}
728done:
729	CLRLOCK(vd, local);
730	ANNOUNCE(local, vm, VM_ALLOC, data, vm->disc);
731	CLRINUSE(vd, inuse);
732	return data;
733}
734
735static Vmethod_t _Vmprofile =
736{
737	pfalloc,
738	pfresize,
739	pffree,
740	pfaddr,
741	pfsize,
742	pfcompact,
743	pfalign,
744	VM_MTPROFILE
745};
746
747__DEFINE__(Vmethod_t*,Vmprofile,&_Vmprofile);
748
749#ifdef NoF
750NoF(vmprofile)
751#endif
752
753#endif
754