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