10Sstevel@tonic-gate /* 2*11038SRao.Shoaib@Sun.COM * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC") 30Sstevel@tonic-gate * Copyright (c) 1997,1999 by Internet Software Consortium. 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 60Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 70Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 80Sstevel@tonic-gate * 9*11038SRao.Shoaib@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10*11038SRao.Shoaib@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*11038SRao.Shoaib@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12*11038SRao.Shoaib@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*11038SRao.Shoaib@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*11038SRao.Shoaib@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15*11038SRao.Shoaib@Sun.COM * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 160Sstevel@tonic-gate */ 170Sstevel@tonic-gate 180Sstevel@tonic-gate 190Sstevel@tonic-gate /* When this symbol is defined allocations via memget are made slightly 200Sstevel@tonic-gate bigger and some debugging info stuck before and after the region given 210Sstevel@tonic-gate back to the caller. */ 220Sstevel@tonic-gate /* #define DEBUGGING_MEMCLUSTER */ 230Sstevel@tonic-gate #define MEMCLUSTER_ATEND 240Sstevel@tonic-gate 250Sstevel@tonic-gate 260Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER) 27*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: memcluster.c,v 1.11 2006/08/30 23:34:38 marka Exp $"; 280Sstevel@tonic-gate #endif /* not lint */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include "port_before.h" 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/uio.h> 340Sstevel@tonic-gate #include <sys/param.h> 350Sstevel@tonic-gate #include <sys/stat.h> 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <netinet/in.h> 380Sstevel@tonic-gate #include <arpa/inet.h> 390Sstevel@tonic-gate #include <arpa/nameser.h> 400Sstevel@tonic-gate 410Sstevel@tonic-gate #include <errno.h> 420Sstevel@tonic-gate #include <stdio.h> 430Sstevel@tonic-gate #include <stdlib.h> 440Sstevel@tonic-gate #include <string.h> 450Sstevel@tonic-gate #include <time.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include <isc/memcluster.h> 480Sstevel@tonic-gate #include <isc/assertions.h> 490Sstevel@tonic-gate 500Sstevel@tonic-gate #include "port_after.h" 510Sstevel@tonic-gate 520Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 530Sstevel@tonic-gate #ifndef DEBUGGING_MEMCLUSTER 540Sstevel@tonic-gate #define DEBUGGING_MEMCLUSTER 550Sstevel@tonic-gate #endif 560Sstevel@tonic-gate #endif 570Sstevel@tonic-gate 580Sstevel@tonic-gate #define DEF_MAX_SIZE 1100 590Sstevel@tonic-gate #define DEF_MEM_TARGET 4096 600Sstevel@tonic-gate 610Sstevel@tonic-gate typedef u_int32_t fence_t; 620Sstevel@tonic-gate 630Sstevel@tonic-gate typedef struct { 640Sstevel@tonic-gate void * next; 650Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 660Sstevel@tonic-gate #if defined(MEMCLUSTER_RECORD) 670Sstevel@tonic-gate const char * file; 680Sstevel@tonic-gate int line; 690Sstevel@tonic-gate #endif 700Sstevel@tonic-gate size_t size; 710Sstevel@tonic-gate fence_t fencepost; 720Sstevel@tonic-gate #endif 730Sstevel@tonic-gate } memcluster_element; 740Sstevel@tonic-gate 750Sstevel@tonic-gate #define SMALL_SIZE_LIMIT sizeof(memcluster_element) 760Sstevel@tonic-gate #define P_SIZE sizeof(void *) 770Sstevel@tonic-gate #define FRONT_FENCEPOST 0xfebafeba 780Sstevel@tonic-gate #define BACK_FENCEPOST 0xabefabef 790Sstevel@tonic-gate #define FENCEPOST_SIZE 4 800Sstevel@tonic-gate 810Sstevel@tonic-gate #ifndef MEMCLUSTER_LITTLE_MALLOC 820Sstevel@tonic-gate #define MEMCLUSTER_BIG_MALLOC 1 830Sstevel@tonic-gate #define NUM_BASIC_BLOCKS 64 840Sstevel@tonic-gate #endif 850Sstevel@tonic-gate 860Sstevel@tonic-gate struct stats { 870Sstevel@tonic-gate u_long gets; 880Sstevel@tonic-gate u_long totalgets; 890Sstevel@tonic-gate u_long blocks; 900Sstevel@tonic-gate u_long freefrags; 910Sstevel@tonic-gate }; 920Sstevel@tonic-gate 93*11038SRao.Shoaib@Sun.COM #ifdef DO_PTHREADS 94*11038SRao.Shoaib@Sun.COM #include <pthread.h> 95*11038SRao.Shoaib@Sun.COM static pthread_mutex_t memlock = PTHREAD_MUTEX_INITIALIZER; 96*11038SRao.Shoaib@Sun.COM #define MEMLOCK (void)pthread_mutex_lock(&memlock) 97*11038SRao.Shoaib@Sun.COM #define MEMUNLOCK (void)pthread_mutex_unlock(&memlock) 98*11038SRao.Shoaib@Sun.COM #else 99*11038SRao.Shoaib@Sun.COM /* 100*11038SRao.Shoaib@Sun.COM * Catch bad lock usage in non threaded build. 101*11038SRao.Shoaib@Sun.COM */ 102*11038SRao.Shoaib@Sun.COM static unsigned int memlock = 0; 103*11038SRao.Shoaib@Sun.COM #define MEMLOCK do { INSIST(memlock == 0); memlock = 1; } while (0) 104*11038SRao.Shoaib@Sun.COM #define MEMUNLOCK do { INSIST(memlock == 1); memlock = 0; } while (0) 105*11038SRao.Shoaib@Sun.COM #endif /* DO_PTHEADS */ 1060Sstevel@tonic-gate 107*11038SRao.Shoaib@Sun.COM /* Private data. */ 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate static size_t max_size; 1100Sstevel@tonic-gate static size_t mem_target; 111*11038SRao.Shoaib@Sun.COM #ifndef MEMCLUSTER_BIG_MALLOC 1120Sstevel@tonic-gate static size_t mem_target_half; 1130Sstevel@tonic-gate static size_t mem_target_fudge; 114*11038SRao.Shoaib@Sun.COM #endif 1150Sstevel@tonic-gate static memcluster_element ** freelists; 1160Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 1170Sstevel@tonic-gate static memcluster_element ** activelists; 1180Sstevel@tonic-gate #endif 1190Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 1200Sstevel@tonic-gate static memcluster_element * basic_blocks; 1210Sstevel@tonic-gate #endif 1220Sstevel@tonic-gate static struct stats * stats; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* Forward. */ 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate static size_t quantize(size_t); 1270Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 1280Sstevel@tonic-gate static void check(unsigned char *, int, size_t); 1290Sstevel@tonic-gate #endif 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* Public. */ 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate int 1340Sstevel@tonic-gate meminit(size_t init_max_size, size_t target_size) { 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 1370Sstevel@tonic-gate INSIST(sizeof(fence_t) == FENCEPOST_SIZE); 1380Sstevel@tonic-gate #endif 1390Sstevel@tonic-gate if (freelists != NULL) { 1400Sstevel@tonic-gate errno = EEXIST; 1410Sstevel@tonic-gate return (-1); 1420Sstevel@tonic-gate } 143*11038SRao.Shoaib@Sun.COM if (init_max_size == 0U) 1440Sstevel@tonic-gate max_size = DEF_MAX_SIZE; 1450Sstevel@tonic-gate else 1460Sstevel@tonic-gate max_size = init_max_size; 147*11038SRao.Shoaib@Sun.COM if (target_size == 0U) 1480Sstevel@tonic-gate mem_target = DEF_MEM_TARGET; 1490Sstevel@tonic-gate else 1500Sstevel@tonic-gate mem_target = target_size; 151*11038SRao.Shoaib@Sun.COM #ifndef MEMCLUSTER_BIG_MALLOC 1520Sstevel@tonic-gate mem_target_half = mem_target / 2; 1530Sstevel@tonic-gate mem_target_fudge = mem_target + mem_target / 4; 154*11038SRao.Shoaib@Sun.COM #endif 1550Sstevel@tonic-gate freelists = malloc(max_size * sizeof (memcluster_element *)); 1560Sstevel@tonic-gate stats = malloc((max_size+1) * sizeof (struct stats)); 1570Sstevel@tonic-gate if (freelists == NULL || stats == NULL) { 1580Sstevel@tonic-gate errno = ENOMEM; 1590Sstevel@tonic-gate return (-1); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate memset(freelists, 0, 1620Sstevel@tonic-gate max_size * sizeof (memcluster_element *)); 1630Sstevel@tonic-gate memset(stats, 0, (max_size + 1) * sizeof (struct stats)); 1640Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 1650Sstevel@tonic-gate activelists = malloc((max_size + 1) * sizeof (memcluster_element *)); 1660Sstevel@tonic-gate if (activelists == NULL) { 1670Sstevel@tonic-gate errno = ENOMEM; 1680Sstevel@tonic-gate return (-1); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate memset(activelists, 0, 1710Sstevel@tonic-gate (max_size + 1) * sizeof (memcluster_element *)); 1720Sstevel@tonic-gate #endif 1730Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 1740Sstevel@tonic-gate basic_blocks = NULL; 1750Sstevel@tonic-gate #endif 1760Sstevel@tonic-gate return (0); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate void * 1800Sstevel@tonic-gate __memget(size_t size) { 1810Sstevel@tonic-gate return (__memget_record(size, NULL, 0)); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate void * 1850Sstevel@tonic-gate __memget_record(size_t size, const char *file, int line) { 1860Sstevel@tonic-gate size_t new_size = quantize(size); 1870Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 1880Sstevel@tonic-gate memcluster_element *e; 1890Sstevel@tonic-gate char *p; 1900Sstevel@tonic-gate fence_t fp = BACK_FENCEPOST; 1910Sstevel@tonic-gate #endif 1920Sstevel@tonic-gate void *ret; 1930Sstevel@tonic-gate 194*11038SRao.Shoaib@Sun.COM MEMLOCK; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate #if !defined(MEMCLUSTER_RECORD) 1970Sstevel@tonic-gate UNUSED(file); 1980Sstevel@tonic-gate UNUSED(line); 1990Sstevel@tonic-gate #endif 200*11038SRao.Shoaib@Sun.COM if (freelists == NULL) { 201*11038SRao.Shoaib@Sun.COM if (meminit(0, 0) == -1) { 202*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 2030Sstevel@tonic-gate return (NULL); 204*11038SRao.Shoaib@Sun.COM } 205*11038SRao.Shoaib@Sun.COM } 206*11038SRao.Shoaib@Sun.COM if (size == 0U) { 207*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 2080Sstevel@tonic-gate errno = EINVAL; 2090Sstevel@tonic-gate return (NULL); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate if (size >= max_size || new_size >= max_size) { 2120Sstevel@tonic-gate /* memget() was called on something beyond our upper limit. */ 2130Sstevel@tonic-gate stats[max_size].gets++; 2140Sstevel@tonic-gate stats[max_size].totalgets++; 2150Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 2160Sstevel@tonic-gate e = malloc(new_size); 2170Sstevel@tonic-gate if (e == NULL) { 218*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 2190Sstevel@tonic-gate errno = ENOMEM; 2200Sstevel@tonic-gate return (NULL); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate e->next = NULL; 2230Sstevel@tonic-gate e->size = size; 2240Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 2250Sstevel@tonic-gate e->file = file; 2260Sstevel@tonic-gate e->line = line; 2270Sstevel@tonic-gate e->next = activelists[max_size]; 2280Sstevel@tonic-gate activelists[max_size] = e; 2290Sstevel@tonic-gate #endif 230*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 2310Sstevel@tonic-gate e->fencepost = FRONT_FENCEPOST; 2320Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 2330Sstevel@tonic-gate memcpy(p, &fp, sizeof fp); 2340Sstevel@tonic-gate return ((char *)e + sizeof *e); 2350Sstevel@tonic-gate #else 236*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 2370Sstevel@tonic-gate return (malloc(size)); 2380Sstevel@tonic-gate #endif 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * If there are no blocks in the free list for this size, get a chunk 2430Sstevel@tonic-gate * of memory and then break it up into "new_size"-sized blocks, adding 2440Sstevel@tonic-gate * them to the free list. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate if (freelists[new_size] == NULL) { 2470Sstevel@tonic-gate int i, frags; 2480Sstevel@tonic-gate size_t total_size; 2490Sstevel@tonic-gate void *new; 2500Sstevel@tonic-gate char *curr, *next; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 2530Sstevel@tonic-gate if (basic_blocks == NULL) { 2540Sstevel@tonic-gate new = malloc(NUM_BASIC_BLOCKS * mem_target); 2550Sstevel@tonic-gate if (new == NULL) { 256*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 2570Sstevel@tonic-gate errno = ENOMEM; 2580Sstevel@tonic-gate return (NULL); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate curr = new; 2610Sstevel@tonic-gate next = curr + mem_target; 2620Sstevel@tonic-gate for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 2630Sstevel@tonic-gate ((memcluster_element *)curr)->next = next; 2640Sstevel@tonic-gate curr = next; 2650Sstevel@tonic-gate next += mem_target; 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate /* 2680Sstevel@tonic-gate * curr is now pointing at the last block in the 2690Sstevel@tonic-gate * array. 2700Sstevel@tonic-gate */ 2710Sstevel@tonic-gate ((memcluster_element *)curr)->next = NULL; 2720Sstevel@tonic-gate basic_blocks = new; 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate total_size = mem_target; 2750Sstevel@tonic-gate new = basic_blocks; 2760Sstevel@tonic-gate basic_blocks = basic_blocks->next; 2770Sstevel@tonic-gate #else 2780Sstevel@tonic-gate if (new_size > mem_target_half) 2790Sstevel@tonic-gate total_size = mem_target_fudge; 2800Sstevel@tonic-gate else 2810Sstevel@tonic-gate total_size = mem_target; 2820Sstevel@tonic-gate new = malloc(total_size); 2830Sstevel@tonic-gate if (new == NULL) { 284*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 2850Sstevel@tonic-gate errno = ENOMEM; 2860Sstevel@tonic-gate return (NULL); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate #endif 2890Sstevel@tonic-gate frags = total_size / new_size; 2900Sstevel@tonic-gate stats[new_size].blocks++; 2910Sstevel@tonic-gate stats[new_size].freefrags += frags; 2920Sstevel@tonic-gate /* Set up a linked-list of blocks of size "new_size". */ 2930Sstevel@tonic-gate curr = new; 2940Sstevel@tonic-gate next = curr + new_size; 2950Sstevel@tonic-gate for (i = 0; i < (frags - 1); i++) { 2960Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 2970Sstevel@tonic-gate memset(curr, 0xa5, new_size); 2980Sstevel@tonic-gate #endif 2990Sstevel@tonic-gate ((memcluster_element *)curr)->next = next; 3000Sstevel@tonic-gate curr = next; 3010Sstevel@tonic-gate next += new_size; 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate /* curr is now pointing at the last block in the array. */ 3040Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3050Sstevel@tonic-gate memset(curr, 0xa5, new_size); 3060Sstevel@tonic-gate #endif 3070Sstevel@tonic-gate ((memcluster_element *)curr)->next = freelists[new_size]; 3080Sstevel@tonic-gate freelists[new_size] = new; 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* The free list uses the "rounded-up" size "new_size". */ 3120Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3130Sstevel@tonic-gate e = freelists[new_size]; 3140Sstevel@tonic-gate ret = (char *)e + sizeof *e; 3150Sstevel@tonic-gate /* 3160Sstevel@tonic-gate * Check to see if this buffer has been written to while on free list. 3170Sstevel@tonic-gate */ 3180Sstevel@tonic-gate check(ret, 0xa5, new_size - sizeof *e); 3190Sstevel@tonic-gate /* 3200Sstevel@tonic-gate * Mark memory we are returning. 3210Sstevel@tonic-gate */ 3220Sstevel@tonic-gate memset(ret, 0xe5, size); 3230Sstevel@tonic-gate #else 3240Sstevel@tonic-gate ret = freelists[new_size]; 3250Sstevel@tonic-gate #endif 3260Sstevel@tonic-gate freelists[new_size] = freelists[new_size]->next; 3270Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 3280Sstevel@tonic-gate e->next = NULL; 3290Sstevel@tonic-gate e->size = size; 3300Sstevel@tonic-gate e->fencepost = FRONT_FENCEPOST; 3310Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 3320Sstevel@tonic-gate e->file = file; 3330Sstevel@tonic-gate e->line = line; 3340Sstevel@tonic-gate e->next = activelists[size]; 3350Sstevel@tonic-gate activelists[size] = e; 3360Sstevel@tonic-gate #endif 3370Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 3380Sstevel@tonic-gate memcpy(p, &fp, sizeof fp); 3390Sstevel@tonic-gate #endif 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * The stats[] uses the _actual_ "size" requested by the 3430Sstevel@tonic-gate * caller, with the caveat (in the code above) that "size" >= the 3440Sstevel@tonic-gate * max. size (max_size) ends up getting recorded as a call to 3450Sstevel@tonic-gate * max_size. 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate stats[size].gets++; 3480Sstevel@tonic-gate stats[size].totalgets++; 3490Sstevel@tonic-gate stats[new_size].freefrags--; 350*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 3510Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 3520Sstevel@tonic-gate return ((char *)e + sizeof *e); 3530Sstevel@tonic-gate #else 3540Sstevel@tonic-gate return (ret); 3550Sstevel@tonic-gate #endif 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 358*11038SRao.Shoaib@Sun.COM /*% 3590Sstevel@tonic-gate * This is a call from an external caller, 3600Sstevel@tonic-gate * so we want to count this as a user "put". 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate void 3630Sstevel@tonic-gate __memput(void *mem, size_t size) { 3640Sstevel@tonic-gate __memput_record(mem, size, NULL, 0); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate void 3680Sstevel@tonic-gate __memput_record(void *mem, size_t size, const char *file, int line) { 3690Sstevel@tonic-gate size_t new_size = quantize(size); 3700Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3710Sstevel@tonic-gate memcluster_element *e; 3720Sstevel@tonic-gate memcluster_element *el; 3730Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 3740Sstevel@tonic-gate memcluster_element *prev; 3750Sstevel@tonic-gate #endif 3760Sstevel@tonic-gate fence_t fp; 3770Sstevel@tonic-gate char *p; 3780Sstevel@tonic-gate #endif 3790Sstevel@tonic-gate 380*11038SRao.Shoaib@Sun.COM MEMLOCK; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate #if !defined (MEMCLUSTER_RECORD) 3830Sstevel@tonic-gate UNUSED(file); 3840Sstevel@tonic-gate UNUSED(line); 3850Sstevel@tonic-gate #endif 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate REQUIRE(freelists != NULL); 3880Sstevel@tonic-gate 389*11038SRao.Shoaib@Sun.COM if (size == 0U) { 390*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 3910Sstevel@tonic-gate errno = EINVAL; 3920Sstevel@tonic-gate return; 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3960Sstevel@tonic-gate e = (memcluster_element *) ((char *)mem - sizeof *e); 3970Sstevel@tonic-gate INSIST(e->fencepost == FRONT_FENCEPOST); 3980Sstevel@tonic-gate INSIST(e->size == size); 3990Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 4000Sstevel@tonic-gate memcpy(&fp, p, sizeof fp); 4010Sstevel@tonic-gate INSIST(fp == BACK_FENCEPOST); 402*11038SRao.Shoaib@Sun.COM INSIST(((u_long)mem % 4) == 0); 4030Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 4040Sstevel@tonic-gate prev = NULL; 4050Sstevel@tonic-gate if (size == max_size || new_size >= max_size) 4060Sstevel@tonic-gate el = activelists[max_size]; 4070Sstevel@tonic-gate else 4080Sstevel@tonic-gate el = activelists[size]; 4090Sstevel@tonic-gate while (el != NULL && el != e) { 4100Sstevel@tonic-gate prev = el; 4110Sstevel@tonic-gate el = el->next; 4120Sstevel@tonic-gate } 413*11038SRao.Shoaib@Sun.COM INSIST(el != NULL); /*%< double free */ 4140Sstevel@tonic-gate if (prev == NULL) { 4150Sstevel@tonic-gate if (size == max_size || new_size >= max_size) 4160Sstevel@tonic-gate activelists[max_size] = el->next; 4170Sstevel@tonic-gate else 4180Sstevel@tonic-gate activelists[size] = el->next; 4190Sstevel@tonic-gate } else 4200Sstevel@tonic-gate prev->next = el->next; 4210Sstevel@tonic-gate #endif 4220Sstevel@tonic-gate #endif 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (size == max_size || new_size >= max_size) { 4250Sstevel@tonic-gate /* memput() called on something beyond our upper limit */ 4260Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 4270Sstevel@tonic-gate free(e); 4280Sstevel@tonic-gate #else 4290Sstevel@tonic-gate free(mem); 4300Sstevel@tonic-gate #endif 4310Sstevel@tonic-gate 432*11038SRao.Shoaib@Sun.COM INSIST(stats[max_size].gets != 0U); 4330Sstevel@tonic-gate stats[max_size].gets--; 434*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 4350Sstevel@tonic-gate return; 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /* The free list uses the "rounded-up" size "new_size": */ 4390Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 440*11038SRao.Shoaib@Sun.COM memset(mem, 0xa5, new_size - sizeof *e); /*%< catch write after free */ 441*11038SRao.Shoaib@Sun.COM e->size = 0; /*%< catch double memput() */ 4420Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 4430Sstevel@tonic-gate e->file = file; 4440Sstevel@tonic-gate e->line = line; 4450Sstevel@tonic-gate #endif 4460Sstevel@tonic-gate #ifdef MEMCLUSTER_ATEND 4470Sstevel@tonic-gate e->next = NULL; 4480Sstevel@tonic-gate el = freelists[new_size]; 4490Sstevel@tonic-gate while (el != NULL && el->next != NULL) 4500Sstevel@tonic-gate el = el->next; 4510Sstevel@tonic-gate if (el) 4520Sstevel@tonic-gate el->next = e; 4530Sstevel@tonic-gate else 4540Sstevel@tonic-gate freelists[new_size] = e; 4550Sstevel@tonic-gate #else 4560Sstevel@tonic-gate e->next = freelists[new_size]; 4570Sstevel@tonic-gate freelists[new_size] = (void *)e; 4580Sstevel@tonic-gate #endif 4590Sstevel@tonic-gate #else 4600Sstevel@tonic-gate ((memcluster_element *)mem)->next = freelists[new_size]; 4610Sstevel@tonic-gate freelists[new_size] = (memcluster_element *)mem; 4620Sstevel@tonic-gate #endif 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate /* 4650Sstevel@tonic-gate * The stats[] uses the _actual_ "size" requested by the 4660Sstevel@tonic-gate * caller, with the caveat (in the code above) that "size" >= the 4670Sstevel@tonic-gate * max. size (max_size) ends up getting recorded as a call to 4680Sstevel@tonic-gate * max_size. 4690Sstevel@tonic-gate */ 470*11038SRao.Shoaib@Sun.COM INSIST(stats[size].gets != 0U); 4710Sstevel@tonic-gate stats[size].gets--; 4720Sstevel@tonic-gate stats[new_size].freefrags++; 473*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate void * 4770Sstevel@tonic-gate __memget_debug(size_t size, const char *file, int line) { 4780Sstevel@tonic-gate void *ptr; 4790Sstevel@tonic-gate ptr = __memget_record(size, file, line); 4800Sstevel@tonic-gate fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line, 4810Sstevel@tonic-gate (u_long)size, ptr); 4820Sstevel@tonic-gate return (ptr); 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate void 4860Sstevel@tonic-gate __memput_debug(void *ptr, size_t size, const char *file, int line) { 4870Sstevel@tonic-gate fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr, 4880Sstevel@tonic-gate (u_long)size); 4890Sstevel@tonic-gate __memput_record(ptr, size, file, line); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 492*11038SRao.Shoaib@Sun.COM /*% 4930Sstevel@tonic-gate * Print the stats[] on the stream "out" with suitable formatting. 4940Sstevel@tonic-gate */ 4950Sstevel@tonic-gate void 4960Sstevel@tonic-gate memstats(FILE *out) { 4970Sstevel@tonic-gate size_t i; 4980Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 4990Sstevel@tonic-gate memcluster_element *e; 5000Sstevel@tonic-gate #endif 5010Sstevel@tonic-gate 502*11038SRao.Shoaib@Sun.COM MEMLOCK; 503*11038SRao.Shoaib@Sun.COM 504*11038SRao.Shoaib@Sun.COM if (freelists == NULL) { 505*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 5060Sstevel@tonic-gate return; 507*11038SRao.Shoaib@Sun.COM } 5080Sstevel@tonic-gate for (i = 1; i <= max_size; i++) { 5090Sstevel@tonic-gate const struct stats *s = &stats[i]; 5100Sstevel@tonic-gate 511*11038SRao.Shoaib@Sun.COM if (s->totalgets == 0U && s->gets == 0U) 5120Sstevel@tonic-gate continue; 513*11038SRao.Shoaib@Sun.COM fprintf(out, "%s%5lu: %11lu gets, %11lu rem", 5140Sstevel@tonic-gate (i == max_size) ? ">=" : " ", 515*11038SRao.Shoaib@Sun.COM (unsigned long)i, s->totalgets, s->gets); 516*11038SRao.Shoaib@Sun.COM if (s->blocks != 0U) 5170Sstevel@tonic-gate fprintf(out, " (%lu bl, %lu ff)", 5180Sstevel@tonic-gate s->blocks, s->freefrags); 5190Sstevel@tonic-gate fputc('\n', out); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 5220Sstevel@tonic-gate fprintf(out, "Active Memory:\n"); 5230Sstevel@tonic-gate for (i = 1; i <= max_size; i++) { 5240Sstevel@tonic-gate if ((e = activelists[i]) != NULL) 5250Sstevel@tonic-gate while (e != NULL) { 526*11038SRao.Shoaib@Sun.COM fprintf(out, "%s:%d %p:%lu\n", 5270Sstevel@tonic-gate e->file != NULL ? e->file : 5280Sstevel@tonic-gate "<UNKNOWN>", e->line, 529*11038SRao.Shoaib@Sun.COM (char *)e + sizeof *e, 530*11038SRao.Shoaib@Sun.COM (u_long)e->size); 5310Sstevel@tonic-gate e = e->next; 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate #endif 535*11038SRao.Shoaib@Sun.COM MEMUNLOCK; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate int 5390Sstevel@tonic-gate memactive(void) { 5400Sstevel@tonic-gate size_t i; 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate if (stats == NULL) 5430Sstevel@tonic-gate return (0); 5440Sstevel@tonic-gate for (i = 1; i <= max_size; i++) 545*11038SRao.Shoaib@Sun.COM if (stats[i].gets != 0U) 5460Sstevel@tonic-gate return (1); 5470Sstevel@tonic-gate return (0); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /* Private. */ 5510Sstevel@tonic-gate 552*11038SRao.Shoaib@Sun.COM /*% 5530Sstevel@tonic-gate * Round up size to a multiple of sizeof(void *). This guarantees that a 5540Sstevel@tonic-gate * block is at least sizeof void *, and that we won't violate alignment 5550Sstevel@tonic-gate * restrictions, both of which are needed to make lists of blocks. 5560Sstevel@tonic-gate */ 5570Sstevel@tonic-gate static size_t 5580Sstevel@tonic-gate quantize(size_t size) { 5590Sstevel@tonic-gate int remainder; 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * If there is no remainder for the integer division of 5620Sstevel@tonic-gate * 5630Sstevel@tonic-gate * (rightsize/P_SIZE) 5640Sstevel@tonic-gate * 5650Sstevel@tonic-gate * then we already have a good size; if not, then we need 5660Sstevel@tonic-gate * to round up the result in order to get a size big 5670Sstevel@tonic-gate * enough to satisfy the request _and_ aligned on P_SIZE boundaries. 5680Sstevel@tonic-gate */ 5690Sstevel@tonic-gate remainder = size % P_SIZE; 5700Sstevel@tonic-gate if (remainder != 0) 5710Sstevel@tonic-gate size += P_SIZE - remainder; 5720Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 5730Sstevel@tonic-gate return (size + SMALL_SIZE_LIMIT + sizeof (int)); 5740Sstevel@tonic-gate #else 5750Sstevel@tonic-gate return (size); 5760Sstevel@tonic-gate #endif 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 5800Sstevel@tonic-gate static void 5810Sstevel@tonic-gate check(unsigned char *a, int value, size_t len) { 5820Sstevel@tonic-gate size_t i; 5830Sstevel@tonic-gate for (i = 0; i < len; i++) 5840Sstevel@tonic-gate INSIST(a[i] == value); 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate #endif 587*11038SRao.Shoaib@Sun.COM 588*11038SRao.Shoaib@Sun.COM /*! \file */ 589