1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 1998-2002 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* 7*0Sstevel@tonic-gate * Copyright (c) 1997,1999 by Internet Software Consortium. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 10*0Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 11*0Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14*0Sstevel@tonic-gate * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16*0Sstevel@tonic-gate * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17*0Sstevel@tonic-gate * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18*0Sstevel@tonic-gate * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19*0Sstevel@tonic-gate * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20*0Sstevel@tonic-gate * SOFTWARE. 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate 23*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate /* When this symbol is defined allocations via memget are made slightly 26*0Sstevel@tonic-gate bigger and some debugging info stuck before and after the region given 27*0Sstevel@tonic-gate back to the caller. */ 28*0Sstevel@tonic-gate /* #define DEBUGGING_MEMCLUSTER */ 29*0Sstevel@tonic-gate #define MEMCLUSTER_ATEND 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER) 33*0Sstevel@tonic-gate static const char rcsid[] = "$Id: memcluster.c,v 8.23 2001/06/18 14:44:05 marka Exp $"; 34*0Sstevel@tonic-gate #endif /* not lint */ 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #include "port_before.h" 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #include <sys/types.h> 39*0Sstevel@tonic-gate #include <sys/uio.h> 40*0Sstevel@tonic-gate #include <sys/param.h> 41*0Sstevel@tonic-gate #include <sys/stat.h> 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include <netinet/in.h> 44*0Sstevel@tonic-gate #include <arpa/inet.h> 45*0Sstevel@tonic-gate #include <arpa/nameser.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #include <errno.h> 48*0Sstevel@tonic-gate #include <stdio.h> 49*0Sstevel@tonic-gate #include <stdlib.h> 50*0Sstevel@tonic-gate #include <string.h> 51*0Sstevel@tonic-gate #include <time.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #include <isc/memcluster.h> 54*0Sstevel@tonic-gate #include <isc/assertions.h> 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate #include "port_after.h" 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 59*0Sstevel@tonic-gate #ifndef DEBUGGING_MEMCLUSTER 60*0Sstevel@tonic-gate #define DEBUGGING_MEMCLUSTER 61*0Sstevel@tonic-gate #endif 62*0Sstevel@tonic-gate #endif 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate #define DEF_MAX_SIZE 1100 65*0Sstevel@tonic-gate #define DEF_MEM_TARGET 4096 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate typedef u_int32_t fence_t; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate typedef struct { 70*0Sstevel@tonic-gate void * next; 71*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 72*0Sstevel@tonic-gate #if defined(MEMCLUSTER_RECORD) 73*0Sstevel@tonic-gate const char * file; 74*0Sstevel@tonic-gate int line; 75*0Sstevel@tonic-gate #endif 76*0Sstevel@tonic-gate size_t size; 77*0Sstevel@tonic-gate fence_t fencepost; 78*0Sstevel@tonic-gate #endif 79*0Sstevel@tonic-gate } memcluster_element; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate #define SMALL_SIZE_LIMIT sizeof(memcluster_element) 82*0Sstevel@tonic-gate #define P_SIZE sizeof(void *) 83*0Sstevel@tonic-gate #define FRONT_FENCEPOST 0xfebafeba 84*0Sstevel@tonic-gate #define BACK_FENCEPOST 0xabefabef 85*0Sstevel@tonic-gate #define FENCEPOST_SIZE 4 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate #ifndef MEMCLUSTER_LITTLE_MALLOC 88*0Sstevel@tonic-gate #define MEMCLUSTER_BIG_MALLOC 1 89*0Sstevel@tonic-gate #define NUM_BASIC_BLOCKS 64 90*0Sstevel@tonic-gate #endif 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate struct stats { 93*0Sstevel@tonic-gate u_long gets; 94*0Sstevel@tonic-gate u_long totalgets; 95*0Sstevel@tonic-gate u_long blocks; 96*0Sstevel@tonic-gate u_long freefrags; 97*0Sstevel@tonic-gate }; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate /* Private data. */ 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate #ifdef SUNW_MT_RESOLVER 102*0Sstevel@tonic-gate #include <thread.h> 103*0Sstevel@tonic-gate #include <synch.h> 104*0Sstevel@tonic-gate static mutex_t memlock = DEFAULTMUTEX; 105*0Sstevel@tonic-gate #define SUNW_MEMLOCK (void)mutex_lock(&memlock) 106*0Sstevel@tonic-gate #define SUNW_MEMUNLOCK (void)mutex_unlock(&memlock) 107*0Sstevel@tonic-gate #define SUNW_MEMLOCKBLOCK_BEGIN { 108*0Sstevel@tonic-gate #define SUNW_MEMLOCKBLOCK_END } 109*0Sstevel@tonic-gate #else 110*0Sstevel@tonic-gate #define SUNW_MEMLOCK 111*0Sstevel@tonic-gate #define SUNW_MEMUNLOCK 112*0Sstevel@tonic-gate #define SUNW_MEMLOCKBLOCK_BEGIN 113*0Sstevel@tonic-gate #define SUNW_MEMLOCKBLOCK_END 114*0Sstevel@tonic-gate #endif /* SUNW_MT_RESOLVER */ 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate static size_t max_size; 117*0Sstevel@tonic-gate static size_t mem_target; 118*0Sstevel@tonic-gate static size_t mem_target_half; 119*0Sstevel@tonic-gate static size_t mem_target_fudge; 120*0Sstevel@tonic-gate static memcluster_element ** freelists; 121*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 122*0Sstevel@tonic-gate static memcluster_element ** activelists; 123*0Sstevel@tonic-gate #endif 124*0Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 125*0Sstevel@tonic-gate static memcluster_element * basic_blocks; 126*0Sstevel@tonic-gate #endif 127*0Sstevel@tonic-gate static struct stats * stats; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate /* Forward. */ 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate static size_t quantize(size_t); 132*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 133*0Sstevel@tonic-gate static void check(unsigned char *, int, size_t); 134*0Sstevel@tonic-gate #endif 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* Public. */ 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate int 139*0Sstevel@tonic-gate meminit(size_t init_max_size, size_t target_size) { 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 142*0Sstevel@tonic-gate INSIST(sizeof(fence_t) == FENCEPOST_SIZE); 143*0Sstevel@tonic-gate #endif 144*0Sstevel@tonic-gate if (freelists != NULL) { 145*0Sstevel@tonic-gate errno = EEXIST; 146*0Sstevel@tonic-gate return (-1); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate if (init_max_size == 0) 149*0Sstevel@tonic-gate max_size = DEF_MAX_SIZE; 150*0Sstevel@tonic-gate else 151*0Sstevel@tonic-gate max_size = init_max_size; 152*0Sstevel@tonic-gate if (target_size == 0) 153*0Sstevel@tonic-gate mem_target = DEF_MEM_TARGET; 154*0Sstevel@tonic-gate else 155*0Sstevel@tonic-gate mem_target = target_size; 156*0Sstevel@tonic-gate mem_target_half = mem_target / 2; 157*0Sstevel@tonic-gate mem_target_fudge = mem_target + mem_target / 4; 158*0Sstevel@tonic-gate freelists = malloc(max_size * sizeof (memcluster_element *)); 159*0Sstevel@tonic-gate stats = malloc((max_size+1) * sizeof (struct stats)); 160*0Sstevel@tonic-gate if (freelists == NULL || stats == NULL) { 161*0Sstevel@tonic-gate errno = ENOMEM; 162*0Sstevel@tonic-gate return (-1); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate memset(freelists, 0, 165*0Sstevel@tonic-gate max_size * sizeof (memcluster_element *)); 166*0Sstevel@tonic-gate memset(stats, 0, (max_size + 1) * sizeof (struct stats)); 167*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 168*0Sstevel@tonic-gate activelists = malloc((max_size + 1) * sizeof (memcluster_element *)); 169*0Sstevel@tonic-gate if (activelists == NULL) { 170*0Sstevel@tonic-gate errno = ENOMEM; 171*0Sstevel@tonic-gate return (-1); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate memset(activelists, 0, 174*0Sstevel@tonic-gate (max_size + 1) * sizeof (memcluster_element *)); 175*0Sstevel@tonic-gate #endif 176*0Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 177*0Sstevel@tonic-gate basic_blocks = NULL; 178*0Sstevel@tonic-gate #endif 179*0Sstevel@tonic-gate return (0); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate void * 183*0Sstevel@tonic-gate __memget(size_t size) { 184*0Sstevel@tonic-gate return (__memget_record(size, NULL, 0)); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate void * 188*0Sstevel@tonic-gate __memget_record(size_t size, const char *file, int line) { 189*0Sstevel@tonic-gate size_t new_size = quantize(size); 190*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 191*0Sstevel@tonic-gate memcluster_element *e; 192*0Sstevel@tonic-gate char *p; 193*0Sstevel@tonic-gate fence_t fp = BACK_FENCEPOST; 194*0Sstevel@tonic-gate #endif 195*0Sstevel@tonic-gate void *ret; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate SUNW_MEMLOCK; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate #if !defined(MEMCLUSTER_RECORD) 200*0Sstevel@tonic-gate UNUSED(file); 201*0Sstevel@tonic-gate UNUSED(line); 202*0Sstevel@tonic-gate #endif 203*0Sstevel@tonic-gate if (freelists == NULL) 204*0Sstevel@tonic-gate if (meminit(0, 0) == -1) 205*0Sstevel@tonic-gate SUNW_MEMLOCKBLOCK_BEGIN 206*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 207*0Sstevel@tonic-gate return (NULL); 208*0Sstevel@tonic-gate SUNW_MEMLOCKBLOCK_END 209*0Sstevel@tonic-gate if (size == 0) { 210*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 211*0Sstevel@tonic-gate errno = EINVAL; 212*0Sstevel@tonic-gate return (NULL); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate if (size >= max_size || new_size >= max_size) { 215*0Sstevel@tonic-gate /* memget() was called on something beyond our upper limit. */ 216*0Sstevel@tonic-gate stats[max_size].gets++; 217*0Sstevel@tonic-gate stats[max_size].totalgets++; 218*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 219*0Sstevel@tonic-gate e = malloc(new_size); 220*0Sstevel@tonic-gate if (e == NULL) { 221*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 222*0Sstevel@tonic-gate errno = ENOMEM; 223*0Sstevel@tonic-gate return (NULL); 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate e->next = NULL; 226*0Sstevel@tonic-gate e->size = size; 227*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 228*0Sstevel@tonic-gate e->file = file; 229*0Sstevel@tonic-gate e->line = line; 230*0Sstevel@tonic-gate e->next = activelists[max_size]; 231*0Sstevel@tonic-gate activelists[max_size] = e; 232*0Sstevel@tonic-gate #endif 233*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 234*0Sstevel@tonic-gate e->fencepost = FRONT_FENCEPOST; 235*0Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 236*0Sstevel@tonic-gate memcpy(p, &fp, sizeof fp); 237*0Sstevel@tonic-gate return ((char *)e + sizeof *e); 238*0Sstevel@tonic-gate #else 239*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 240*0Sstevel@tonic-gate return (malloc(size)); 241*0Sstevel@tonic-gate #endif 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate /* 245*0Sstevel@tonic-gate * If there are no blocks in the free list for this size, get a chunk 246*0Sstevel@tonic-gate * of memory and then break it up into "new_size"-sized blocks, adding 247*0Sstevel@tonic-gate * them to the free list. 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate if (freelists[new_size] == NULL) { 250*0Sstevel@tonic-gate int i, frags; 251*0Sstevel@tonic-gate size_t total_size; 252*0Sstevel@tonic-gate void *new; 253*0Sstevel@tonic-gate char *curr, *next; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 256*0Sstevel@tonic-gate if (basic_blocks == NULL) { 257*0Sstevel@tonic-gate new = malloc(NUM_BASIC_BLOCKS * mem_target); 258*0Sstevel@tonic-gate if (new == NULL) { 259*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 260*0Sstevel@tonic-gate errno = ENOMEM; 261*0Sstevel@tonic-gate return (NULL); 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate curr = new; 264*0Sstevel@tonic-gate next = curr + mem_target; 265*0Sstevel@tonic-gate for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 266*0Sstevel@tonic-gate ((memcluster_element *)curr)->next = next; 267*0Sstevel@tonic-gate curr = next; 268*0Sstevel@tonic-gate next += mem_target; 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * curr is now pointing at the last block in the 272*0Sstevel@tonic-gate * array. 273*0Sstevel@tonic-gate */ 274*0Sstevel@tonic-gate ((memcluster_element *)curr)->next = NULL; 275*0Sstevel@tonic-gate basic_blocks = new; 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate total_size = mem_target; 278*0Sstevel@tonic-gate new = basic_blocks; 279*0Sstevel@tonic-gate basic_blocks = basic_blocks->next; 280*0Sstevel@tonic-gate #else 281*0Sstevel@tonic-gate if (new_size > mem_target_half) 282*0Sstevel@tonic-gate total_size = mem_target_fudge; 283*0Sstevel@tonic-gate else 284*0Sstevel@tonic-gate total_size = mem_target; 285*0Sstevel@tonic-gate new = malloc(total_size); 286*0Sstevel@tonic-gate if (new == NULL) { 287*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 288*0Sstevel@tonic-gate errno = ENOMEM; 289*0Sstevel@tonic-gate return (NULL); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate #endif 292*0Sstevel@tonic-gate frags = total_size / new_size; 293*0Sstevel@tonic-gate stats[new_size].blocks++; 294*0Sstevel@tonic-gate stats[new_size].freefrags += frags; 295*0Sstevel@tonic-gate /* Set up a linked-list of blocks of size "new_size". */ 296*0Sstevel@tonic-gate curr = new; 297*0Sstevel@tonic-gate next = curr + new_size; 298*0Sstevel@tonic-gate for (i = 0; i < (frags - 1); i++) { 299*0Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 300*0Sstevel@tonic-gate memset(curr, 0xa5, new_size); 301*0Sstevel@tonic-gate #endif 302*0Sstevel@tonic-gate ((memcluster_element *)curr)->next = next; 303*0Sstevel@tonic-gate curr = next; 304*0Sstevel@tonic-gate next += new_size; 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate /* curr is now pointing at the last block in the array. */ 307*0Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 308*0Sstevel@tonic-gate memset(curr, 0xa5, new_size); 309*0Sstevel@tonic-gate #endif 310*0Sstevel@tonic-gate ((memcluster_element *)curr)->next = freelists[new_size]; 311*0Sstevel@tonic-gate freelists[new_size] = new; 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate /* The free list uses the "rounded-up" size "new_size". */ 315*0Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 316*0Sstevel@tonic-gate e = freelists[new_size]; 317*0Sstevel@tonic-gate ret = (char *)e + sizeof *e; 318*0Sstevel@tonic-gate /* 319*0Sstevel@tonic-gate * Check to see if this buffer has been written to while on free list. 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate check(ret, 0xa5, new_size - sizeof *e); 322*0Sstevel@tonic-gate /* 323*0Sstevel@tonic-gate * Mark memory we are returning. 324*0Sstevel@tonic-gate */ 325*0Sstevel@tonic-gate memset(ret, 0xe5, size); 326*0Sstevel@tonic-gate #else 327*0Sstevel@tonic-gate ret = freelists[new_size]; 328*0Sstevel@tonic-gate #endif 329*0Sstevel@tonic-gate freelists[new_size] = freelists[new_size]->next; 330*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 331*0Sstevel@tonic-gate e->next = NULL; 332*0Sstevel@tonic-gate e->size = size; 333*0Sstevel@tonic-gate e->fencepost = FRONT_FENCEPOST; 334*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 335*0Sstevel@tonic-gate e->file = file; 336*0Sstevel@tonic-gate e->line = line; 337*0Sstevel@tonic-gate e->next = activelists[size]; 338*0Sstevel@tonic-gate activelists[size] = e; 339*0Sstevel@tonic-gate #endif 340*0Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 341*0Sstevel@tonic-gate memcpy(p, &fp, sizeof fp); 342*0Sstevel@tonic-gate #endif 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate * The stats[] uses the _actual_ "size" requested by the 346*0Sstevel@tonic-gate * caller, with the caveat (in the code above) that "size" >= the 347*0Sstevel@tonic-gate * max. size (max_size) ends up getting recorded as a call to 348*0Sstevel@tonic-gate * max_size. 349*0Sstevel@tonic-gate */ 350*0Sstevel@tonic-gate stats[size].gets++; 351*0Sstevel@tonic-gate stats[size].totalgets++; 352*0Sstevel@tonic-gate stats[new_size].freefrags--; 353*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 354*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 355*0Sstevel@tonic-gate return ((char *)e + sizeof *e); 356*0Sstevel@tonic-gate #else 357*0Sstevel@tonic-gate return (ret); 358*0Sstevel@tonic-gate #endif 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * This is a call from an external caller, 363*0Sstevel@tonic-gate * so we want to count this as a user "put". 364*0Sstevel@tonic-gate */ 365*0Sstevel@tonic-gate void 366*0Sstevel@tonic-gate __memput(void *mem, size_t size) { 367*0Sstevel@tonic-gate __memput_record(mem, size, NULL, 0); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate void 371*0Sstevel@tonic-gate __memput_record(void *mem, size_t size, const char *file, int line) { 372*0Sstevel@tonic-gate size_t new_size = quantize(size); 373*0Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 374*0Sstevel@tonic-gate memcluster_element *e; 375*0Sstevel@tonic-gate memcluster_element *el; 376*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 377*0Sstevel@tonic-gate memcluster_element *prev; 378*0Sstevel@tonic-gate #endif 379*0Sstevel@tonic-gate fence_t fp; 380*0Sstevel@tonic-gate char *p; 381*0Sstevel@tonic-gate #endif 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate SUNW_MEMLOCK; 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate #if !defined (MEMCLUSTER_RECORD) 386*0Sstevel@tonic-gate UNUSED(file); 387*0Sstevel@tonic-gate UNUSED(line); 388*0Sstevel@tonic-gate #endif 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate REQUIRE(freelists != NULL); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if (size == 0) { 393*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 394*0Sstevel@tonic-gate errno = EINVAL; 395*0Sstevel@tonic-gate return; 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 399*0Sstevel@tonic-gate e = (memcluster_element *) ((char *)mem - sizeof *e); 400*0Sstevel@tonic-gate INSIST(e->fencepost == FRONT_FENCEPOST); 401*0Sstevel@tonic-gate INSIST(e->size == size); 402*0Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 403*0Sstevel@tonic-gate memcpy(&fp, p, sizeof fp); 404*0Sstevel@tonic-gate INSIST(fp == BACK_FENCEPOST); 405*0Sstevel@tonic-gate INSIST(((int)mem % 4) == 0); 406*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 407*0Sstevel@tonic-gate prev = NULL; 408*0Sstevel@tonic-gate if (size == max_size || new_size >= max_size) 409*0Sstevel@tonic-gate el = activelists[max_size]; 410*0Sstevel@tonic-gate else 411*0Sstevel@tonic-gate el = activelists[size]; 412*0Sstevel@tonic-gate while (el != NULL && el != e) { 413*0Sstevel@tonic-gate prev = el; 414*0Sstevel@tonic-gate el = el->next; 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate INSIST(el != NULL); /* double free */ 417*0Sstevel@tonic-gate if (prev == NULL) { 418*0Sstevel@tonic-gate if (size == max_size || new_size >= max_size) 419*0Sstevel@tonic-gate activelists[max_size] = el->next; 420*0Sstevel@tonic-gate else 421*0Sstevel@tonic-gate activelists[size] = el->next; 422*0Sstevel@tonic-gate } else 423*0Sstevel@tonic-gate prev->next = el->next; 424*0Sstevel@tonic-gate #endif 425*0Sstevel@tonic-gate #endif 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate if (size == max_size || new_size >= max_size) { 428*0Sstevel@tonic-gate /* memput() called on something beyond our upper limit */ 429*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 430*0Sstevel@tonic-gate free(e); 431*0Sstevel@tonic-gate #else 432*0Sstevel@tonic-gate free(mem); 433*0Sstevel@tonic-gate #endif 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate INSIST(stats[max_size].gets != 0); 436*0Sstevel@tonic-gate stats[max_size].gets--; 437*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 438*0Sstevel@tonic-gate return; 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate /* The free list uses the "rounded-up" size "new_size": */ 442*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 443*0Sstevel@tonic-gate memset(mem, 0xa5, new_size - sizeof *e); /* catch write after free */ 444*0Sstevel@tonic-gate e->size = 0; /* catch double memput() */ 445*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 446*0Sstevel@tonic-gate e->file = file; 447*0Sstevel@tonic-gate e->line = line; 448*0Sstevel@tonic-gate #endif 449*0Sstevel@tonic-gate #ifdef MEMCLUSTER_ATEND 450*0Sstevel@tonic-gate e->next = NULL; 451*0Sstevel@tonic-gate el = freelists[new_size]; 452*0Sstevel@tonic-gate while (el != NULL && el->next != NULL) 453*0Sstevel@tonic-gate el = el->next; 454*0Sstevel@tonic-gate if (el) 455*0Sstevel@tonic-gate el->next = e; 456*0Sstevel@tonic-gate else 457*0Sstevel@tonic-gate freelists[new_size] = e; 458*0Sstevel@tonic-gate #else 459*0Sstevel@tonic-gate e->next = freelists[new_size]; 460*0Sstevel@tonic-gate freelists[new_size] = (void *)e; 461*0Sstevel@tonic-gate #endif 462*0Sstevel@tonic-gate #else 463*0Sstevel@tonic-gate ((memcluster_element *)mem)->next = freelists[new_size]; 464*0Sstevel@tonic-gate freelists[new_size] = (memcluster_element *)mem; 465*0Sstevel@tonic-gate #endif 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * The stats[] uses the _actual_ "size" requested by the 469*0Sstevel@tonic-gate * caller, with the caveat (in the code above) that "size" >= the 470*0Sstevel@tonic-gate * max. size (max_size) ends up getting recorded as a call to 471*0Sstevel@tonic-gate * max_size. 472*0Sstevel@tonic-gate */ 473*0Sstevel@tonic-gate INSIST(stats[size].gets != 0); 474*0Sstevel@tonic-gate stats[size].gets--; 475*0Sstevel@tonic-gate stats[new_size].freefrags++; 476*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate void * 480*0Sstevel@tonic-gate __memget_debug(size_t size, const char *file, int line) { 481*0Sstevel@tonic-gate void *ptr; 482*0Sstevel@tonic-gate ptr = __memget_record(size, file, line); 483*0Sstevel@tonic-gate fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line, 484*0Sstevel@tonic-gate (u_long)size, ptr); 485*0Sstevel@tonic-gate return (ptr); 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate void 489*0Sstevel@tonic-gate __memput_debug(void *ptr, size_t size, const char *file, int line) { 490*0Sstevel@tonic-gate fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr, 491*0Sstevel@tonic-gate (u_long)size); 492*0Sstevel@tonic-gate __memput_record(ptr, size, file, line); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* 496*0Sstevel@tonic-gate * Print the stats[] on the stream "out" with suitable formatting. 497*0Sstevel@tonic-gate */ 498*0Sstevel@tonic-gate void 499*0Sstevel@tonic-gate memstats(FILE *out) { 500*0Sstevel@tonic-gate size_t i; 501*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 502*0Sstevel@tonic-gate memcluster_element *e; 503*0Sstevel@tonic-gate #endif 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate SUNW_MEMLOCK; 506*0Sstevel@tonic-gate if (freelists == NULL) 507*0Sstevel@tonic-gate SUNW_MEMLOCKBLOCK_BEGIN 508*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 509*0Sstevel@tonic-gate return; 510*0Sstevel@tonic-gate SUNW_MEMLOCKBLOCK_END 511*0Sstevel@tonic-gate for (i = 1; i <= max_size; i++) { 512*0Sstevel@tonic-gate const struct stats *s = &stats[i]; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate if (s->totalgets == 0 && s->gets == 0) 515*0Sstevel@tonic-gate continue; 516*0Sstevel@tonic-gate fprintf(out, "%s%5d: %11lu gets, %11lu rem", 517*0Sstevel@tonic-gate (i == max_size) ? ">=" : " ", 518*0Sstevel@tonic-gate i, s->totalgets, s->gets); 519*0Sstevel@tonic-gate if (s->blocks != 0) 520*0Sstevel@tonic-gate fprintf(out, " (%lu bl, %lu ff)", 521*0Sstevel@tonic-gate s->blocks, s->freefrags); 522*0Sstevel@tonic-gate fputc('\n', out); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 525*0Sstevel@tonic-gate fprintf(out, "Active Memory:\n"); 526*0Sstevel@tonic-gate for (i = 1; i <= max_size; i++) { 527*0Sstevel@tonic-gate if ((e = activelists[i]) != NULL) 528*0Sstevel@tonic-gate while (e != NULL) { 529*0Sstevel@tonic-gate fprintf(out, "%s:%d %p:%d\n", 530*0Sstevel@tonic-gate e->file != NULL ? e->file : 531*0Sstevel@tonic-gate "<UNKNOWN>", e->line, 532*0Sstevel@tonic-gate (char *)e + sizeof *e, e->size); 533*0Sstevel@tonic-gate e = e->next; 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate #endif 537*0Sstevel@tonic-gate SUNW_MEMUNLOCK; 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate int 541*0Sstevel@tonic-gate memactive(void) { 542*0Sstevel@tonic-gate size_t i; 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate if (stats == NULL) 545*0Sstevel@tonic-gate return (0); 546*0Sstevel@tonic-gate for (i = 1; i <= max_size; i++) 547*0Sstevel@tonic-gate if (stats[i].gets != 0) 548*0Sstevel@tonic-gate return (1); 549*0Sstevel@tonic-gate return (0); 550*0Sstevel@tonic-gate } 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate /* Private. */ 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * Round up size to a multiple of sizeof(void *). This guarantees that a 556*0Sstevel@tonic-gate * block is at least sizeof void *, and that we won't violate alignment 557*0Sstevel@tonic-gate * restrictions, both of which are needed to make lists of blocks. 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate static size_t 560*0Sstevel@tonic-gate quantize(size_t size) { 561*0Sstevel@tonic-gate int remainder; 562*0Sstevel@tonic-gate /* 563*0Sstevel@tonic-gate * If there is no remainder for the integer division of 564*0Sstevel@tonic-gate * 565*0Sstevel@tonic-gate * (rightsize/P_SIZE) 566*0Sstevel@tonic-gate * 567*0Sstevel@tonic-gate * then we already have a good size; if not, then we need 568*0Sstevel@tonic-gate * to round up the result in order to get a size big 569*0Sstevel@tonic-gate * enough to satisfy the request _and_ aligned on P_SIZE boundaries. 570*0Sstevel@tonic-gate */ 571*0Sstevel@tonic-gate remainder = size % P_SIZE; 572*0Sstevel@tonic-gate if (remainder != 0) 573*0Sstevel@tonic-gate size += P_SIZE - remainder; 574*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 575*0Sstevel@tonic-gate return (size + SMALL_SIZE_LIMIT + sizeof (int)); 576*0Sstevel@tonic-gate #else 577*0Sstevel@tonic-gate return (size); 578*0Sstevel@tonic-gate #endif 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 582*0Sstevel@tonic-gate static void 583*0Sstevel@tonic-gate check(unsigned char *a, int value, size_t len) { 584*0Sstevel@tonic-gate size_t i; 585*0Sstevel@tonic-gate for (i = 0; i < len; i++) 586*0Sstevel@tonic-gate INSIST(a[i] == value); 587*0Sstevel@tonic-gate } 588*0Sstevel@tonic-gate #endif 589