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