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 * 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 * 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 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 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 * 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 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 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 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 * 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