xref: /titanic_50/usr/src/cmd/sendmail/libsm/rpool.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2004 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *	All rights reserved.
4*7c478bd9Sstevel@tonic-gate  *
5*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
6*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
7*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
8*7c478bd9Sstevel@tonic-gate  */
9*7c478bd9Sstevel@tonic-gate 
10*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
11*7c478bd9Sstevel@tonic-gate 
12*7c478bd9Sstevel@tonic-gate #include <sm/gen.h>
13*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: rpool.c,v 1.28 2004/08/03 20:44:04 ca Exp $")
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate /*
16*7c478bd9Sstevel@tonic-gate **  resource pools
17*7c478bd9Sstevel@tonic-gate **  For documentation, see rpool.html
18*7c478bd9Sstevel@tonic-gate */
19*7c478bd9Sstevel@tonic-gate 
20*7c478bd9Sstevel@tonic-gate #include <sm/exc.h>
21*7c478bd9Sstevel@tonic-gate #include <sm/heap.h>
22*7c478bd9Sstevel@tonic-gate #include <sm/rpool.h>
23*7c478bd9Sstevel@tonic-gate #include <sm/varargs.h>
24*7c478bd9Sstevel@tonic-gate #include <sm/conf.h>
25*7c478bd9Sstevel@tonic-gate #if _FFR_PERF_RPOOL
26*7c478bd9Sstevel@tonic-gate # include <syslog.h>
27*7c478bd9Sstevel@tonic-gate #endif /* _FFR_PERF_RPOOL */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate const char SmRpoolMagic[] = "sm_rpool";
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate typedef union
32*7c478bd9Sstevel@tonic-gate {
33*7c478bd9Sstevel@tonic-gate 	SM_POOLLINK_T	link;
34*7c478bd9Sstevel@tonic-gate 	char		align[SM_ALIGN_SIZE];
35*7c478bd9Sstevel@tonic-gate } SM_POOLHDR_T;
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate static char	*sm_rpool_allocblock_x __P((SM_RPOOL_T *, size_t));
38*7c478bd9Sstevel@tonic-gate static char	*sm_rpool_allocblock __P((SM_RPOOL_T *, size_t));
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate /*
41*7c478bd9Sstevel@tonic-gate **  Tune this later
42*7c478bd9Sstevel@tonic-gate */
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #define POOLSIZE		4096
45*7c478bd9Sstevel@tonic-gate #define BIG_OBJECT_RATIO	10
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_ALLOCBLOCK_X -- allocate a new block for an rpool.
49*7c478bd9Sstevel@tonic-gate **
50*7c478bd9Sstevel@tonic-gate **	Parameters:
51*7c478bd9Sstevel@tonic-gate **		rpool -- rpool to which the block should be added.
52*7c478bd9Sstevel@tonic-gate **		size -- size of block.
53*7c478bd9Sstevel@tonic-gate **
54*7c478bd9Sstevel@tonic-gate **	Returns:
55*7c478bd9Sstevel@tonic-gate **		Pointer to block.
56*7c478bd9Sstevel@tonic-gate **
57*7c478bd9Sstevel@tonic-gate **	Exceptions:
58*7c478bd9Sstevel@tonic-gate **		F:sm_heap -- out of memory
59*7c478bd9Sstevel@tonic-gate */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate static char *
sm_rpool_allocblock_x(rpool,size)62*7c478bd9Sstevel@tonic-gate sm_rpool_allocblock_x(rpool, size)
63*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
64*7c478bd9Sstevel@tonic-gate 	size_t size;
65*7c478bd9Sstevel@tonic-gate {
66*7c478bd9Sstevel@tonic-gate 	SM_POOLLINK_T *p;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	p = sm_malloc_x(sizeof(SM_POOLHDR_T) + size);
69*7c478bd9Sstevel@tonic-gate 	p->sm_pnext = rpool->sm_pools;
70*7c478bd9Sstevel@tonic-gate 	rpool->sm_pools = p;
71*7c478bd9Sstevel@tonic-gate 	return (char*) p + sizeof(SM_POOLHDR_T);
72*7c478bd9Sstevel@tonic-gate }
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate /*
75*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_ALLOCBLOCK -- allocate a new block for an rpool.
76*7c478bd9Sstevel@tonic-gate **
77*7c478bd9Sstevel@tonic-gate **	Parameters:
78*7c478bd9Sstevel@tonic-gate **		rpool -- rpool to which the block should be added.
79*7c478bd9Sstevel@tonic-gate **		size -- size of block.
80*7c478bd9Sstevel@tonic-gate **
81*7c478bd9Sstevel@tonic-gate **	Returns:
82*7c478bd9Sstevel@tonic-gate **		Pointer to block, NULL on failure.
83*7c478bd9Sstevel@tonic-gate */
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate static char *
sm_rpool_allocblock(rpool,size)86*7c478bd9Sstevel@tonic-gate sm_rpool_allocblock(rpool, size)
87*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
88*7c478bd9Sstevel@tonic-gate 	size_t size;
89*7c478bd9Sstevel@tonic-gate {
90*7c478bd9Sstevel@tonic-gate 	SM_POOLLINK_T *p;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate 	p = sm_malloc(sizeof(SM_POOLHDR_T) + size);
93*7c478bd9Sstevel@tonic-gate 	if (p == NULL)
94*7c478bd9Sstevel@tonic-gate 		return NULL;
95*7c478bd9Sstevel@tonic-gate 	p->sm_pnext = rpool->sm_pools;
96*7c478bd9Sstevel@tonic-gate 	rpool->sm_pools = p;
97*7c478bd9Sstevel@tonic-gate 	return (char*) p + sizeof(SM_POOLHDR_T);
98*7c478bd9Sstevel@tonic-gate }
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate /*
101*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_MALLOC_TAGGED_X -- allocate memory from rpool
102*7c478bd9Sstevel@tonic-gate **
103*7c478bd9Sstevel@tonic-gate **	Parameters:
104*7c478bd9Sstevel@tonic-gate **		rpool -- rpool from which memory should be allocated;
105*7c478bd9Sstevel@tonic-gate **			can be NULL, use sm_malloc() then.
106*7c478bd9Sstevel@tonic-gate **		size -- size of block.
107*7c478bd9Sstevel@tonic-gate **		file -- filename.
108*7c478bd9Sstevel@tonic-gate **		line -- line number in file.
109*7c478bd9Sstevel@tonic-gate **		group -- heap group for debugging.
110*7c478bd9Sstevel@tonic-gate **
111*7c478bd9Sstevel@tonic-gate **	Returns:
112*7c478bd9Sstevel@tonic-gate **		Pointer to block.
113*7c478bd9Sstevel@tonic-gate **
114*7c478bd9Sstevel@tonic-gate **	Exceptions:
115*7c478bd9Sstevel@tonic-gate **		F:sm_heap -- out of memory
116*7c478bd9Sstevel@tonic-gate **
117*7c478bd9Sstevel@tonic-gate **	Notice: XXX
118*7c478bd9Sstevel@tonic-gate **		if size == 0 and the rpool is new (no memory
119*7c478bd9Sstevel@tonic-gate **		allocated yet) NULL is returned!
120*7c478bd9Sstevel@tonic-gate **		We could solve this by
121*7c478bd9Sstevel@tonic-gate **		- wasting 1 byte (size < avail)
122*7c478bd9Sstevel@tonic-gate **		- checking for rpool->sm_poolptr != NULL
123*7c478bd9Sstevel@tonic-gate **		- not asking for 0 sized buffer
124*7c478bd9Sstevel@tonic-gate */
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate void *
127*7c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
sm_rpool_malloc_tagged_x(rpool,size,file,line,group)128*7c478bd9Sstevel@tonic-gate sm_rpool_malloc_tagged_x(rpool, size, file, line, group)
129*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
130*7c478bd9Sstevel@tonic-gate 	size_t size;
131*7c478bd9Sstevel@tonic-gate 	char *file;
132*7c478bd9Sstevel@tonic-gate 	int line;
133*7c478bd9Sstevel@tonic-gate 	int group;
134*7c478bd9Sstevel@tonic-gate #else /* SM_HEAP_CHECK */
135*7c478bd9Sstevel@tonic-gate sm_rpool_malloc_x(rpool, size)
136*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
137*7c478bd9Sstevel@tonic-gate 	size_t size;
138*7c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
139*7c478bd9Sstevel@tonic-gate {
140*7c478bd9Sstevel@tonic-gate 	char *ptr;
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	if (rpool == NULL)
143*7c478bd9Sstevel@tonic-gate 		return sm_malloc_tagged_x(size, file, line, group);
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	/* Ensure that size is properly aligned. */
146*7c478bd9Sstevel@tonic-gate 	if (size & SM_ALIGN_BITS)
147*7c478bd9Sstevel@tonic-gate 		size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	/* The common case.  This is optimized for speed. */
150*7c478bd9Sstevel@tonic-gate 	if (size <= rpool->sm_poolavail)
151*7c478bd9Sstevel@tonic-gate 	{
152*7c478bd9Sstevel@tonic-gate 		ptr = rpool->sm_poolptr;
153*7c478bd9Sstevel@tonic-gate 		rpool->sm_poolptr += size;
154*7c478bd9Sstevel@tonic-gate 		rpool->sm_poolavail -= size;
155*7c478bd9Sstevel@tonic-gate 		return ptr;
156*7c478bd9Sstevel@tonic-gate 	}
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	/*
159*7c478bd9Sstevel@tonic-gate 	**  The slow case: we need to call malloc.
160*7c478bd9Sstevel@tonic-gate 	**  The SM_REQUIRE assertion is deferred until now, for speed.
161*7c478bd9Sstevel@tonic-gate 	**  That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
162*7c478bd9Sstevel@tonic-gate 	**  so the common case code won't be triggered on a dangling pointer.
163*7c478bd9Sstevel@tonic-gate 	*/
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	/*
168*7c478bd9Sstevel@tonic-gate 	**  If size > sm_poolsize, then malloc a new block especially for
169*7c478bd9Sstevel@tonic-gate 	**  this request.  Future requests will be allocated from the
170*7c478bd9Sstevel@tonic-gate 	**  current pool.
171*7c478bd9Sstevel@tonic-gate 	**
172*7c478bd9Sstevel@tonic-gate 	**  What if the current pool is mostly unallocated, and the current
173*7c478bd9Sstevel@tonic-gate 	**  request is larger than the available space, but < sm_poolsize?
174*7c478bd9Sstevel@tonic-gate 	**  If we discard the current pool, and start allocating from a new
175*7c478bd9Sstevel@tonic-gate 	**  pool, then we will be wasting a lot of space.  For this reason,
176*7c478bd9Sstevel@tonic-gate 	**  we malloc a block just for the current request if size >
177*7c478bd9Sstevel@tonic-gate 	**  sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
178*7c478bd9Sstevel@tonic-gate 	**  Thus, the most space that we will waste at the end of a pool
179*7c478bd9Sstevel@tonic-gate 	**  is sm_bigobjectsize - 1.
180*7c478bd9Sstevel@tonic-gate 	*/
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	if (size > rpool->sm_bigobjectsize)
183*7c478bd9Sstevel@tonic-gate 	{
184*7c478bd9Sstevel@tonic-gate #if _FFR_PERF_RPOOL
185*7c478bd9Sstevel@tonic-gate 		++rpool->sm_nbigblocks;
186*7c478bd9Sstevel@tonic-gate #endif /* _FFR_PERF_RPOOL */
187*7c478bd9Sstevel@tonic-gate 		return sm_rpool_allocblock_x(rpool, size);
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 	SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
190*7c478bd9Sstevel@tonic-gate 	ptr = sm_rpool_allocblock_x(rpool, rpool->sm_poolsize);
191*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolptr = ptr + size;
192*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolavail = rpool->sm_poolsize - size;
193*7c478bd9Sstevel@tonic-gate #if _FFR_PERF_RPOOL
194*7c478bd9Sstevel@tonic-gate 	++rpool->sm_npools;
195*7c478bd9Sstevel@tonic-gate #endif /* _FFR_PERF_RPOOL */
196*7c478bd9Sstevel@tonic-gate 	return ptr;
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate /*
200*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_MALLOC_TAGGED -- allocate memory from rpool
201*7c478bd9Sstevel@tonic-gate **
202*7c478bd9Sstevel@tonic-gate **	Parameters:
203*7c478bd9Sstevel@tonic-gate **		rpool -- rpool from which memory should be allocated;
204*7c478bd9Sstevel@tonic-gate **			can be NULL, use sm_malloc() then.
205*7c478bd9Sstevel@tonic-gate **		size -- size of block.
206*7c478bd9Sstevel@tonic-gate **		file -- filename.
207*7c478bd9Sstevel@tonic-gate **		line -- line number in file.
208*7c478bd9Sstevel@tonic-gate **		group -- heap group for debugging.
209*7c478bd9Sstevel@tonic-gate **
210*7c478bd9Sstevel@tonic-gate **	Returns:
211*7c478bd9Sstevel@tonic-gate **		Pointer to block, NULL on failure.
212*7c478bd9Sstevel@tonic-gate **
213*7c478bd9Sstevel@tonic-gate **	Notice: XXX
214*7c478bd9Sstevel@tonic-gate **		if size == 0 and the rpool is new (no memory
215*7c478bd9Sstevel@tonic-gate **		allocated yet) NULL is returned!
216*7c478bd9Sstevel@tonic-gate **		We could solve this by
217*7c478bd9Sstevel@tonic-gate **		- wasting 1 byte (size < avail)
218*7c478bd9Sstevel@tonic-gate **		- checking for rpool->sm_poolptr != NULL
219*7c478bd9Sstevel@tonic-gate **		- not asking for 0 sized buffer
220*7c478bd9Sstevel@tonic-gate */
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate void *
223*7c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
sm_rpool_malloc_tagged(rpool,size,file,line,group)224*7c478bd9Sstevel@tonic-gate sm_rpool_malloc_tagged(rpool, size, file, line, group)
225*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
226*7c478bd9Sstevel@tonic-gate 	size_t size;
227*7c478bd9Sstevel@tonic-gate 	char *file;
228*7c478bd9Sstevel@tonic-gate 	int line;
229*7c478bd9Sstevel@tonic-gate 	int group;
230*7c478bd9Sstevel@tonic-gate #else /* SM_HEAP_CHECK */
231*7c478bd9Sstevel@tonic-gate sm_rpool_malloc(rpool, size)
232*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
233*7c478bd9Sstevel@tonic-gate 	size_t size;
234*7c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
235*7c478bd9Sstevel@tonic-gate {
236*7c478bd9Sstevel@tonic-gate 	char *ptr;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	if (rpool == NULL)
239*7c478bd9Sstevel@tonic-gate 		return sm_malloc_tagged(size, file, line, group);
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	/* Ensure that size is properly aligned. */
242*7c478bd9Sstevel@tonic-gate 	if (size & SM_ALIGN_BITS)
243*7c478bd9Sstevel@tonic-gate 		size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	/* The common case.  This is optimized for speed. */
246*7c478bd9Sstevel@tonic-gate 	if (size <= rpool->sm_poolavail)
247*7c478bd9Sstevel@tonic-gate 	{
248*7c478bd9Sstevel@tonic-gate 		ptr = rpool->sm_poolptr;
249*7c478bd9Sstevel@tonic-gate 		rpool->sm_poolptr += size;
250*7c478bd9Sstevel@tonic-gate 		rpool->sm_poolavail -= size;
251*7c478bd9Sstevel@tonic-gate 		return ptr;
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	/*
255*7c478bd9Sstevel@tonic-gate 	**  The slow case: we need to call malloc.
256*7c478bd9Sstevel@tonic-gate 	**  The SM_REQUIRE assertion is deferred until now, for speed.
257*7c478bd9Sstevel@tonic-gate 	**  That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
258*7c478bd9Sstevel@tonic-gate 	**  so the common case code won't be triggered on a dangling pointer.
259*7c478bd9Sstevel@tonic-gate 	*/
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	/*
264*7c478bd9Sstevel@tonic-gate 	**  If size > sm_poolsize, then malloc a new block especially for
265*7c478bd9Sstevel@tonic-gate 	**  this request.  Future requests will be allocated from the
266*7c478bd9Sstevel@tonic-gate 	**  current pool.
267*7c478bd9Sstevel@tonic-gate 	**
268*7c478bd9Sstevel@tonic-gate 	**  What if the current pool is mostly unallocated, and the current
269*7c478bd9Sstevel@tonic-gate 	**  request is larger than the available space, but < sm_poolsize?
270*7c478bd9Sstevel@tonic-gate 	**  If we discard the current pool, and start allocating from a new
271*7c478bd9Sstevel@tonic-gate 	**  pool, then we will be wasting a lot of space.  For this reason,
272*7c478bd9Sstevel@tonic-gate 	**  we malloc a block just for the current request if size >
273*7c478bd9Sstevel@tonic-gate 	**  sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
274*7c478bd9Sstevel@tonic-gate 	**  Thus, the most space that we will waste at the end of a pool
275*7c478bd9Sstevel@tonic-gate 	**  is sm_bigobjectsize - 1.
276*7c478bd9Sstevel@tonic-gate 	*/
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	if (size > rpool->sm_bigobjectsize)
279*7c478bd9Sstevel@tonic-gate 	{
280*7c478bd9Sstevel@tonic-gate #if _FFR_PERF_RPOOL
281*7c478bd9Sstevel@tonic-gate 		++rpool->sm_nbigblocks;
282*7c478bd9Sstevel@tonic-gate #endif /* _FFR_PERF_RPOOL */
283*7c478bd9Sstevel@tonic-gate 		return sm_rpool_allocblock(rpool, size);
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 	SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
286*7c478bd9Sstevel@tonic-gate 	ptr = sm_rpool_allocblock(rpool, rpool->sm_poolsize);
287*7c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
288*7c478bd9Sstevel@tonic-gate 		return NULL;
289*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolptr = ptr + size;
290*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolavail = rpool->sm_poolsize - size;
291*7c478bd9Sstevel@tonic-gate #if _FFR_PERF_RPOOL
292*7c478bd9Sstevel@tonic-gate 	++rpool->sm_npools;
293*7c478bd9Sstevel@tonic-gate #endif /* _FFR_PERF_RPOOL */
294*7c478bd9Sstevel@tonic-gate 	return ptr;
295*7c478bd9Sstevel@tonic-gate }
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate /*
298*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_NEW_X -- create a new rpool.
299*7c478bd9Sstevel@tonic-gate **
300*7c478bd9Sstevel@tonic-gate **	Parameters:
301*7c478bd9Sstevel@tonic-gate **		parent -- pointer to parent rpool, can be NULL.
302*7c478bd9Sstevel@tonic-gate **
303*7c478bd9Sstevel@tonic-gate **	Returns:
304*7c478bd9Sstevel@tonic-gate **		Pointer to new rpool.
305*7c478bd9Sstevel@tonic-gate */
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate SM_RPOOL_T *
sm_rpool_new_x(parent)308*7c478bd9Sstevel@tonic-gate sm_rpool_new_x(parent)
309*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *parent;
310*7c478bd9Sstevel@tonic-gate {
311*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	rpool = sm_malloc_x(sizeof(SM_RPOOL_T));
314*7c478bd9Sstevel@tonic-gate 	if (parent == NULL)
315*7c478bd9Sstevel@tonic-gate 		rpool->sm_parentlink = NULL;
316*7c478bd9Sstevel@tonic-gate 	else
317*7c478bd9Sstevel@tonic-gate 	{
318*7c478bd9Sstevel@tonic-gate 		SM_TRY
319*7c478bd9Sstevel@tonic-gate 			rpool->sm_parentlink = sm_rpool_attach_x(parent,
320*7c478bd9Sstevel@tonic-gate 					(SM_RPOOL_RFREE_T) sm_rpool_free,
321*7c478bd9Sstevel@tonic-gate 					(void *) rpool);
322*7c478bd9Sstevel@tonic-gate 		SM_EXCEPT(exc, "*")
323*7c478bd9Sstevel@tonic-gate 			sm_free(rpool);
324*7c478bd9Sstevel@tonic-gate 			sm_exc_raise_x(exc);
325*7c478bd9Sstevel@tonic-gate 		SM_END_TRY
326*7c478bd9Sstevel@tonic-gate 	}
327*7c478bd9Sstevel@tonic-gate 	rpool->sm_magic = SmRpoolMagic;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
330*7c478bd9Sstevel@tonic-gate 	rpool->sm_bigobjectsize = rpool->sm_poolsize / BIG_OBJECT_RATIO;
331*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolptr = NULL;
332*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolavail = 0;
333*7c478bd9Sstevel@tonic-gate 	rpool->sm_pools = NULL;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	rpool->sm_rptr = NULL;
336*7c478bd9Sstevel@tonic-gate 	rpool->sm_ravail = 0;
337*7c478bd9Sstevel@tonic-gate 	rpool->sm_rlists = NULL;
338*7c478bd9Sstevel@tonic-gate #if _FFR_PERF_RPOOL
339*7c478bd9Sstevel@tonic-gate 	rpool->sm_nbigblocks = 0;
340*7c478bd9Sstevel@tonic-gate 	rpool->sm_npools = 0;
341*7c478bd9Sstevel@tonic-gate #endif /* _FFR_PERF_RPOOL */
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	return rpool;
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate /*
347*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_SETSIZES -- set sizes for rpool.
348*7c478bd9Sstevel@tonic-gate **
349*7c478bd9Sstevel@tonic-gate **	Parameters:
350*7c478bd9Sstevel@tonic-gate **		poolsize -- size of a single rpool block.
351*7c478bd9Sstevel@tonic-gate **		bigobjectsize -- if this size is exceeded, an individual
352*7c478bd9Sstevel@tonic-gate **			block is allocated (must be less or equal poolsize).
353*7c478bd9Sstevel@tonic-gate **
354*7c478bd9Sstevel@tonic-gate **	Returns:
355*7c478bd9Sstevel@tonic-gate **		none.
356*7c478bd9Sstevel@tonic-gate */
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate void
sm_rpool_setsizes(rpool,poolsize,bigobjectsize)359*7c478bd9Sstevel@tonic-gate sm_rpool_setsizes(rpool, poolsize, bigobjectsize)
360*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
361*7c478bd9Sstevel@tonic-gate 	size_t poolsize;
362*7c478bd9Sstevel@tonic-gate 	size_t bigobjectsize;
363*7c478bd9Sstevel@tonic-gate {
364*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE(poolsize >= bigobjectsize);
365*7c478bd9Sstevel@tonic-gate 	if (poolsize == 0)
366*7c478bd9Sstevel@tonic-gate 		poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
367*7c478bd9Sstevel@tonic-gate 	if (bigobjectsize == 0)
368*7c478bd9Sstevel@tonic-gate 		bigobjectsize = poolsize / BIG_OBJECT_RATIO;
369*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolsize = poolsize;
370*7c478bd9Sstevel@tonic-gate 	rpool->sm_bigobjectsize = bigobjectsize;
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate /*
374*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_FREE -- free an rpool and release all of its resources.
375*7c478bd9Sstevel@tonic-gate **
376*7c478bd9Sstevel@tonic-gate **	Parameters:
377*7c478bd9Sstevel@tonic-gate **		rpool -- rpool to free.
378*7c478bd9Sstevel@tonic-gate **
379*7c478bd9Sstevel@tonic-gate **	Returns:
380*7c478bd9Sstevel@tonic-gate **		none.
381*7c478bd9Sstevel@tonic-gate */
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate void
sm_rpool_free(rpool)384*7c478bd9Sstevel@tonic-gate sm_rpool_free(rpool)
385*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
386*7c478bd9Sstevel@tonic-gate {
387*7c478bd9Sstevel@tonic-gate 	SM_RLIST_T *rl, *rnext;
388*7c478bd9Sstevel@tonic-gate 	SM_RESOURCE_T *r, *rmax;
389*7c478bd9Sstevel@tonic-gate 	SM_POOLLINK_T *pp, *pnext;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	if (rpool == NULL)
392*7c478bd9Sstevel@tonic-gate 		return;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	/*
395*7c478bd9Sstevel@tonic-gate 	**  It's important to free the resources before the memory pools,
396*7c478bd9Sstevel@tonic-gate 	**  because the resource free functions might modify the contents
397*7c478bd9Sstevel@tonic-gate 	**  of the memory pools.
398*7c478bd9Sstevel@tonic-gate 	*/
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	rl = rpool->sm_rlists;
401*7c478bd9Sstevel@tonic-gate 	if (rl != NULL)
402*7c478bd9Sstevel@tonic-gate 	{
403*7c478bd9Sstevel@tonic-gate 		rmax = rpool->sm_rptr;
404*7c478bd9Sstevel@tonic-gate 		for (;;)
405*7c478bd9Sstevel@tonic-gate 		{
406*7c478bd9Sstevel@tonic-gate 			for (r = rl->sm_rvec; r < rmax; ++r)
407*7c478bd9Sstevel@tonic-gate 			{
408*7c478bd9Sstevel@tonic-gate 				if (r->sm_rfree != NULL)
409*7c478bd9Sstevel@tonic-gate 					r->sm_rfree(r->sm_rcontext);
410*7c478bd9Sstevel@tonic-gate 			}
411*7c478bd9Sstevel@tonic-gate 			rnext = rl->sm_rnext;
412*7c478bd9Sstevel@tonic-gate 			sm_free(rl);
413*7c478bd9Sstevel@tonic-gate 			if (rnext == NULL)
414*7c478bd9Sstevel@tonic-gate 				break;
415*7c478bd9Sstevel@tonic-gate 			rl = rnext;
416*7c478bd9Sstevel@tonic-gate 			rmax = &rl->sm_rvec[SM_RLIST_MAX];
417*7c478bd9Sstevel@tonic-gate 		}
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	/*
421*7c478bd9Sstevel@tonic-gate 	**  Now free the memory pools.
422*7c478bd9Sstevel@tonic-gate 	*/
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	for (pp = rpool->sm_pools; pp != NULL; pp = pnext)
425*7c478bd9Sstevel@tonic-gate 	{
426*7c478bd9Sstevel@tonic-gate 		pnext = pp->sm_pnext;
427*7c478bd9Sstevel@tonic-gate 		sm_free(pp);
428*7c478bd9Sstevel@tonic-gate 	}
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	/*
431*7c478bd9Sstevel@tonic-gate 	**  Disconnect rpool from its parent.
432*7c478bd9Sstevel@tonic-gate 	*/
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	if (rpool->sm_parentlink != NULL)
435*7c478bd9Sstevel@tonic-gate 		*rpool->sm_parentlink = NULL;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	/*
438*7c478bd9Sstevel@tonic-gate 	**  Setting these fields to zero means that any future to attempt
439*7c478bd9Sstevel@tonic-gate 	**  to use the rpool after it is freed will cause an assertion failure.
440*7c478bd9Sstevel@tonic-gate 	*/
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	rpool->sm_magic = NULL;
443*7c478bd9Sstevel@tonic-gate 	rpool->sm_poolavail = 0;
444*7c478bd9Sstevel@tonic-gate 	rpool->sm_ravail = 0;
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate #if _FFR_PERF_RPOOL
447*7c478bd9Sstevel@tonic-gate 	if (rpool->sm_nbigblocks > 0 || rpool->sm_npools > 1)
448*7c478bd9Sstevel@tonic-gate 		syslog(LOG_NOTICE,
449*7c478bd9Sstevel@tonic-gate 			"perf: rpool=%lx, sm_nbigblocks=%d, sm_npools=%d",
450*7c478bd9Sstevel@tonic-gate 			(long) rpool, rpool->sm_nbigblocks, rpool->sm_npools);
451*7c478bd9Sstevel@tonic-gate 	rpool->sm_nbigblocks = 0;
452*7c478bd9Sstevel@tonic-gate 	rpool->sm_npools = 0;
453*7c478bd9Sstevel@tonic-gate #endif /* _FFR_PERF_RPOOL */
454*7c478bd9Sstevel@tonic-gate 	sm_free(rpool);
455*7c478bd9Sstevel@tonic-gate }
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate /*
458*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_ATTACH_X -- attach a resource to an rpool.
459*7c478bd9Sstevel@tonic-gate **
460*7c478bd9Sstevel@tonic-gate **	Parameters:
461*7c478bd9Sstevel@tonic-gate **		rpool -- rpool to which resource should be attached.
462*7c478bd9Sstevel@tonic-gate **		rfree -- function to call when rpool is freed.
463*7c478bd9Sstevel@tonic-gate **		rcontext -- argument for function to call when rpool is freed.
464*7c478bd9Sstevel@tonic-gate **
465*7c478bd9Sstevel@tonic-gate **	Returns:
466*7c478bd9Sstevel@tonic-gate **		Pointer to allocated function.
467*7c478bd9Sstevel@tonic-gate **
468*7c478bd9Sstevel@tonic-gate **	Exceptions:
469*7c478bd9Sstevel@tonic-gate **		F:sm_heap -- out of memory
470*7c478bd9Sstevel@tonic-gate */
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate SM_RPOOL_ATTACH_T
sm_rpool_attach_x(rpool,rfree,rcontext)473*7c478bd9Sstevel@tonic-gate sm_rpool_attach_x(rpool, rfree, rcontext)
474*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
475*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_RFREE_T rfree;
476*7c478bd9Sstevel@tonic-gate 	void *rcontext;
477*7c478bd9Sstevel@tonic-gate {
478*7c478bd9Sstevel@tonic-gate 	SM_RLIST_T *rl;
479*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_ATTACH_T a;
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(rpool, SmRpoolMagic);
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	if (rpool->sm_ravail == 0)
484*7c478bd9Sstevel@tonic-gate 	{
485*7c478bd9Sstevel@tonic-gate 		rl = sm_malloc_x(sizeof(SM_RLIST_T));
486*7c478bd9Sstevel@tonic-gate 		rl->sm_rnext = rpool->sm_rlists;
487*7c478bd9Sstevel@tonic-gate 		rpool->sm_rlists = rl;
488*7c478bd9Sstevel@tonic-gate 		rpool->sm_rptr = rl->sm_rvec;
489*7c478bd9Sstevel@tonic-gate 		rpool->sm_ravail = SM_RLIST_MAX;
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	a = &rpool->sm_rptr->sm_rfree;
493*7c478bd9Sstevel@tonic-gate 	rpool->sm_rptr->sm_rfree = rfree;
494*7c478bd9Sstevel@tonic-gate 	rpool->sm_rptr->sm_rcontext = rcontext;
495*7c478bd9Sstevel@tonic-gate 	++rpool->sm_rptr;
496*7c478bd9Sstevel@tonic-gate 	--rpool->sm_ravail;
497*7c478bd9Sstevel@tonic-gate 	return a;
498*7c478bd9Sstevel@tonic-gate }
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate #if DO_NOT_USE_STRCPY
501*7c478bd9Sstevel@tonic-gate /*
502*7c478bd9Sstevel@tonic-gate **  SM_RPOOL_STRDUP_X -- Create a copy of a C string
503*7c478bd9Sstevel@tonic-gate **
504*7c478bd9Sstevel@tonic-gate **	Parameters:
505*7c478bd9Sstevel@tonic-gate **		rpool -- rpool to use.
506*7c478bd9Sstevel@tonic-gate **		s -- the string to copy.
507*7c478bd9Sstevel@tonic-gate **
508*7c478bd9Sstevel@tonic-gate **	Returns:
509*7c478bd9Sstevel@tonic-gate **		pointer to newly allocated string.
510*7c478bd9Sstevel@tonic-gate */
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate char *
sm_rpool_strdup_x(rpool,s)513*7c478bd9Sstevel@tonic-gate sm_rpool_strdup_x(rpool, s)
514*7c478bd9Sstevel@tonic-gate 	SM_RPOOL_T *rpool;
515*7c478bd9Sstevel@tonic-gate 	const char *s;
516*7c478bd9Sstevel@tonic-gate {
517*7c478bd9Sstevel@tonic-gate 	size_t l;
518*7c478bd9Sstevel@tonic-gate 	char *n;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	l = strlen(s);
521*7c478bd9Sstevel@tonic-gate 	SM_ASSERT(l + 1 > l);
522*7c478bd9Sstevel@tonic-gate 	n = sm_rpool_malloc_x(rpool, l + 1);
523*7c478bd9Sstevel@tonic-gate 	sm_strlcpy(n, s, l + 1);
524*7c478bd9Sstevel@tonic-gate 	return n;
525*7c478bd9Sstevel@tonic-gate }
526*7c478bd9Sstevel@tonic-gate #endif /* DO_NOT_USE_STRCPY */
527