17c478bd9Sstevel@tonic-gate /* 2*9525b14bSRao Shoaib * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC") 37c478bd9Sstevel@tonic-gate * Copyright (c) 1997,1999 by Internet Software Consortium. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 67c478bd9Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 77c478bd9Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 87c478bd9Sstevel@tonic-gate * 9*9525b14bSRao Shoaib * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10*9525b14bSRao Shoaib * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*9525b14bSRao Shoaib * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12*9525b14bSRao Shoaib * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*9525b14bSRao Shoaib * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*9525b14bSRao Shoaib * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15*9525b14bSRao Shoaib * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 167c478bd9Sstevel@tonic-gate */ 177c478bd9Sstevel@tonic-gate 187c478bd9Sstevel@tonic-gate 197c478bd9Sstevel@tonic-gate /* When this symbol is defined allocations via memget are made slightly 207c478bd9Sstevel@tonic-gate bigger and some debugging info stuck before and after the region given 217c478bd9Sstevel@tonic-gate back to the caller. */ 227c478bd9Sstevel@tonic-gate /* #define DEBUGGING_MEMCLUSTER */ 237c478bd9Sstevel@tonic-gate #define MEMCLUSTER_ATEND 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER) 27*9525b14bSRao Shoaib static const char rcsid[] = "$Id: memcluster.c,v 1.11 2006/08/30 23:34:38 marka Exp $"; 287c478bd9Sstevel@tonic-gate #endif /* not lint */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include "port_before.h" 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/uio.h> 347c478bd9Sstevel@tonic-gate #include <sys/param.h> 357c478bd9Sstevel@tonic-gate #include <sys/stat.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <netinet/in.h> 387c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 397c478bd9Sstevel@tonic-gate #include <arpa/nameser.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <errno.h> 427c478bd9Sstevel@tonic-gate #include <stdio.h> 437c478bd9Sstevel@tonic-gate #include <stdlib.h> 447c478bd9Sstevel@tonic-gate #include <string.h> 457c478bd9Sstevel@tonic-gate #include <time.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <isc/memcluster.h> 487c478bd9Sstevel@tonic-gate #include <isc/assertions.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include "port_after.h" 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 537c478bd9Sstevel@tonic-gate #ifndef DEBUGGING_MEMCLUSTER 547c478bd9Sstevel@tonic-gate #define DEBUGGING_MEMCLUSTER 557c478bd9Sstevel@tonic-gate #endif 567c478bd9Sstevel@tonic-gate #endif 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #define DEF_MAX_SIZE 1100 597c478bd9Sstevel@tonic-gate #define DEF_MEM_TARGET 4096 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate typedef u_int32_t fence_t; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate typedef struct { 647c478bd9Sstevel@tonic-gate void * next; 657c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 667c478bd9Sstevel@tonic-gate #if defined(MEMCLUSTER_RECORD) 677c478bd9Sstevel@tonic-gate const char * file; 687c478bd9Sstevel@tonic-gate int line; 697c478bd9Sstevel@tonic-gate #endif 707c478bd9Sstevel@tonic-gate size_t size; 717c478bd9Sstevel@tonic-gate fence_t fencepost; 727c478bd9Sstevel@tonic-gate #endif 737c478bd9Sstevel@tonic-gate } memcluster_element; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #define SMALL_SIZE_LIMIT sizeof(memcluster_element) 767c478bd9Sstevel@tonic-gate #define P_SIZE sizeof(void *) 777c478bd9Sstevel@tonic-gate #define FRONT_FENCEPOST 0xfebafeba 787c478bd9Sstevel@tonic-gate #define BACK_FENCEPOST 0xabefabef 797c478bd9Sstevel@tonic-gate #define FENCEPOST_SIZE 4 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #ifndef MEMCLUSTER_LITTLE_MALLOC 827c478bd9Sstevel@tonic-gate #define MEMCLUSTER_BIG_MALLOC 1 837c478bd9Sstevel@tonic-gate #define NUM_BASIC_BLOCKS 64 847c478bd9Sstevel@tonic-gate #endif 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate struct stats { 877c478bd9Sstevel@tonic-gate u_long gets; 887c478bd9Sstevel@tonic-gate u_long totalgets; 897c478bd9Sstevel@tonic-gate u_long blocks; 907c478bd9Sstevel@tonic-gate u_long freefrags; 917c478bd9Sstevel@tonic-gate }; 927c478bd9Sstevel@tonic-gate 93*9525b14bSRao Shoaib #ifdef DO_PTHREADS 94*9525b14bSRao Shoaib #include <pthread.h> 95*9525b14bSRao Shoaib static pthread_mutex_t memlock = PTHREAD_MUTEX_INITIALIZER; 96*9525b14bSRao Shoaib #define MEMLOCK (void)pthread_mutex_lock(&memlock) 97*9525b14bSRao Shoaib #define MEMUNLOCK (void)pthread_mutex_unlock(&memlock) 987c478bd9Sstevel@tonic-gate #else 99*9525b14bSRao Shoaib /* 100*9525b14bSRao Shoaib * Catch bad lock usage in non threaded build. 101*9525b14bSRao Shoaib */ 102*9525b14bSRao Shoaib static unsigned int memlock = 0; 103*9525b14bSRao Shoaib #define MEMLOCK do { INSIST(memlock == 0); memlock = 1; } while (0) 104*9525b14bSRao Shoaib #define MEMUNLOCK do { INSIST(memlock == 1); memlock = 0; } while (0) 105*9525b14bSRao Shoaib #endif /* DO_PTHEADS */ 106*9525b14bSRao Shoaib 107*9525b14bSRao Shoaib /* Private data. */ 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate static size_t max_size; 1107c478bd9Sstevel@tonic-gate static size_t mem_target; 111*9525b14bSRao Shoaib #ifndef MEMCLUSTER_BIG_MALLOC 1127c478bd9Sstevel@tonic-gate static size_t mem_target_half; 1137c478bd9Sstevel@tonic-gate static size_t mem_target_fudge; 114*9525b14bSRao Shoaib #endif 1157c478bd9Sstevel@tonic-gate static memcluster_element ** freelists; 1167c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 1177c478bd9Sstevel@tonic-gate static memcluster_element ** activelists; 1187c478bd9Sstevel@tonic-gate #endif 1197c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 1207c478bd9Sstevel@tonic-gate static memcluster_element * basic_blocks; 1217c478bd9Sstevel@tonic-gate #endif 1227c478bd9Sstevel@tonic-gate static struct stats * stats; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* Forward. */ 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate static size_t quantize(size_t); 1277c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 1287c478bd9Sstevel@tonic-gate static void check(unsigned char *, int, size_t); 1297c478bd9Sstevel@tonic-gate #endif 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* Public. */ 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate int 1347c478bd9Sstevel@tonic-gate meminit(size_t init_max_size, size_t target_size) { 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 1377c478bd9Sstevel@tonic-gate INSIST(sizeof(fence_t) == FENCEPOST_SIZE); 1387c478bd9Sstevel@tonic-gate #endif 1397c478bd9Sstevel@tonic-gate if (freelists != NULL) { 1407c478bd9Sstevel@tonic-gate errno = EEXIST; 1417c478bd9Sstevel@tonic-gate return (-1); 1427c478bd9Sstevel@tonic-gate } 143*9525b14bSRao Shoaib if (init_max_size == 0U) 1447c478bd9Sstevel@tonic-gate max_size = DEF_MAX_SIZE; 1457c478bd9Sstevel@tonic-gate else 1467c478bd9Sstevel@tonic-gate max_size = init_max_size; 147*9525b14bSRao Shoaib if (target_size == 0U) 1487c478bd9Sstevel@tonic-gate mem_target = DEF_MEM_TARGET; 1497c478bd9Sstevel@tonic-gate else 1507c478bd9Sstevel@tonic-gate mem_target = target_size; 151*9525b14bSRao Shoaib #ifndef MEMCLUSTER_BIG_MALLOC 1527c478bd9Sstevel@tonic-gate mem_target_half = mem_target / 2; 1537c478bd9Sstevel@tonic-gate mem_target_fudge = mem_target + mem_target / 4; 154*9525b14bSRao Shoaib #endif 1557c478bd9Sstevel@tonic-gate freelists = malloc(max_size * sizeof (memcluster_element *)); 1567c478bd9Sstevel@tonic-gate stats = malloc((max_size+1) * sizeof (struct stats)); 1577c478bd9Sstevel@tonic-gate if (freelists == NULL || stats == NULL) { 1587c478bd9Sstevel@tonic-gate errno = ENOMEM; 1597c478bd9Sstevel@tonic-gate return (-1); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate memset(freelists, 0, 1627c478bd9Sstevel@tonic-gate max_size * sizeof (memcluster_element *)); 1637c478bd9Sstevel@tonic-gate memset(stats, 0, (max_size + 1) * sizeof (struct stats)); 1647c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 1657c478bd9Sstevel@tonic-gate activelists = malloc((max_size + 1) * sizeof (memcluster_element *)); 1667c478bd9Sstevel@tonic-gate if (activelists == NULL) { 1677c478bd9Sstevel@tonic-gate errno = ENOMEM; 1687c478bd9Sstevel@tonic-gate return (-1); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate memset(activelists, 0, 1717c478bd9Sstevel@tonic-gate (max_size + 1) * sizeof (memcluster_element *)); 1727c478bd9Sstevel@tonic-gate #endif 1737c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 1747c478bd9Sstevel@tonic-gate basic_blocks = NULL; 1757c478bd9Sstevel@tonic-gate #endif 1767c478bd9Sstevel@tonic-gate return (0); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate void * 1807c478bd9Sstevel@tonic-gate __memget(size_t size) { 1817c478bd9Sstevel@tonic-gate return (__memget_record(size, NULL, 0)); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate void * 1857c478bd9Sstevel@tonic-gate __memget_record(size_t size, const char *file, int line) { 1867c478bd9Sstevel@tonic-gate size_t new_size = quantize(size); 1877c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 1887c478bd9Sstevel@tonic-gate memcluster_element *e; 1897c478bd9Sstevel@tonic-gate char *p; 1907c478bd9Sstevel@tonic-gate fence_t fp = BACK_FENCEPOST; 1917c478bd9Sstevel@tonic-gate #endif 1927c478bd9Sstevel@tonic-gate void *ret; 1937c478bd9Sstevel@tonic-gate 194*9525b14bSRao Shoaib MEMLOCK; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate #if !defined(MEMCLUSTER_RECORD) 1977c478bd9Sstevel@tonic-gate UNUSED(file); 1987c478bd9Sstevel@tonic-gate UNUSED(line); 1997c478bd9Sstevel@tonic-gate #endif 200*9525b14bSRao Shoaib if (freelists == NULL) { 201*9525b14bSRao Shoaib if (meminit(0, 0) == -1) { 202*9525b14bSRao Shoaib MEMUNLOCK; 2037c478bd9Sstevel@tonic-gate return (NULL); 204*9525b14bSRao Shoaib } 205*9525b14bSRao Shoaib } 206*9525b14bSRao Shoaib if (size == 0U) { 207*9525b14bSRao Shoaib MEMUNLOCK; 2087c478bd9Sstevel@tonic-gate errno = EINVAL; 2097c478bd9Sstevel@tonic-gate return (NULL); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate if (size >= max_size || new_size >= max_size) { 2127c478bd9Sstevel@tonic-gate /* memget() was called on something beyond our upper limit. */ 2137c478bd9Sstevel@tonic-gate stats[max_size].gets++; 2147c478bd9Sstevel@tonic-gate stats[max_size].totalgets++; 2157c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 2167c478bd9Sstevel@tonic-gate e = malloc(new_size); 2177c478bd9Sstevel@tonic-gate if (e == NULL) { 218*9525b14bSRao Shoaib MEMUNLOCK; 2197c478bd9Sstevel@tonic-gate errno = ENOMEM; 2207c478bd9Sstevel@tonic-gate return (NULL); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate e->next = NULL; 2237c478bd9Sstevel@tonic-gate e->size = size; 2247c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 2257c478bd9Sstevel@tonic-gate e->file = file; 2267c478bd9Sstevel@tonic-gate e->line = line; 2277c478bd9Sstevel@tonic-gate e->next = activelists[max_size]; 2287c478bd9Sstevel@tonic-gate activelists[max_size] = e; 2297c478bd9Sstevel@tonic-gate #endif 230*9525b14bSRao Shoaib MEMUNLOCK; 2317c478bd9Sstevel@tonic-gate e->fencepost = FRONT_FENCEPOST; 2327c478bd9Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 2337c478bd9Sstevel@tonic-gate memcpy(p, &fp, sizeof fp); 2347c478bd9Sstevel@tonic-gate return ((char *)e + sizeof *e); 2357c478bd9Sstevel@tonic-gate #else 236*9525b14bSRao Shoaib MEMUNLOCK; 2377c478bd9Sstevel@tonic-gate return (malloc(size)); 2387c478bd9Sstevel@tonic-gate #endif 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* 2427c478bd9Sstevel@tonic-gate * If there are no blocks in the free list for this size, get a chunk 2437c478bd9Sstevel@tonic-gate * of memory and then break it up into "new_size"-sized blocks, adding 2447c478bd9Sstevel@tonic-gate * them to the free list. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate if (freelists[new_size] == NULL) { 2477c478bd9Sstevel@tonic-gate int i, frags; 2487c478bd9Sstevel@tonic-gate size_t total_size; 2497c478bd9Sstevel@tonic-gate void *new; 2507c478bd9Sstevel@tonic-gate char *curr, *next; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_BIG_MALLOC 2537c478bd9Sstevel@tonic-gate if (basic_blocks == NULL) { 2547c478bd9Sstevel@tonic-gate new = malloc(NUM_BASIC_BLOCKS * mem_target); 2557c478bd9Sstevel@tonic-gate if (new == NULL) { 256*9525b14bSRao Shoaib MEMUNLOCK; 2577c478bd9Sstevel@tonic-gate errno = ENOMEM; 2587c478bd9Sstevel@tonic-gate return (NULL); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate curr = new; 2617c478bd9Sstevel@tonic-gate next = curr + mem_target; 2627c478bd9Sstevel@tonic-gate for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { 2637c478bd9Sstevel@tonic-gate ((memcluster_element *)curr)->next = next; 2647c478bd9Sstevel@tonic-gate curr = next; 2657c478bd9Sstevel@tonic-gate next += mem_target; 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate /* 2687c478bd9Sstevel@tonic-gate * curr is now pointing at the last block in the 2697c478bd9Sstevel@tonic-gate * array. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate ((memcluster_element *)curr)->next = NULL; 2727c478bd9Sstevel@tonic-gate basic_blocks = new; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate total_size = mem_target; 2757c478bd9Sstevel@tonic-gate new = basic_blocks; 2767c478bd9Sstevel@tonic-gate basic_blocks = basic_blocks->next; 2777c478bd9Sstevel@tonic-gate #else 2787c478bd9Sstevel@tonic-gate if (new_size > mem_target_half) 2797c478bd9Sstevel@tonic-gate total_size = mem_target_fudge; 2807c478bd9Sstevel@tonic-gate else 2817c478bd9Sstevel@tonic-gate total_size = mem_target; 2827c478bd9Sstevel@tonic-gate new = malloc(total_size); 2837c478bd9Sstevel@tonic-gate if (new == NULL) { 284*9525b14bSRao Shoaib MEMUNLOCK; 2857c478bd9Sstevel@tonic-gate errno = ENOMEM; 2867c478bd9Sstevel@tonic-gate return (NULL); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate #endif 2897c478bd9Sstevel@tonic-gate frags = total_size / new_size; 2907c478bd9Sstevel@tonic-gate stats[new_size].blocks++; 2917c478bd9Sstevel@tonic-gate stats[new_size].freefrags += frags; 2927c478bd9Sstevel@tonic-gate /* Set up a linked-list of blocks of size "new_size". */ 2937c478bd9Sstevel@tonic-gate curr = new; 2947c478bd9Sstevel@tonic-gate next = curr + new_size; 2957c478bd9Sstevel@tonic-gate for (i = 0; i < (frags - 1); i++) { 2967c478bd9Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 2977c478bd9Sstevel@tonic-gate memset(curr, 0xa5, new_size); 2987c478bd9Sstevel@tonic-gate #endif 2997c478bd9Sstevel@tonic-gate ((memcluster_element *)curr)->next = next; 3007c478bd9Sstevel@tonic-gate curr = next; 3017c478bd9Sstevel@tonic-gate next += new_size; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate /* curr is now pointing at the last block in the array. */ 3047c478bd9Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3057c478bd9Sstevel@tonic-gate memset(curr, 0xa5, new_size); 3067c478bd9Sstevel@tonic-gate #endif 3077c478bd9Sstevel@tonic-gate ((memcluster_element *)curr)->next = freelists[new_size]; 3087c478bd9Sstevel@tonic-gate freelists[new_size] = new; 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* The free list uses the "rounded-up" size "new_size". */ 3127c478bd9Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3137c478bd9Sstevel@tonic-gate e = freelists[new_size]; 3147c478bd9Sstevel@tonic-gate ret = (char *)e + sizeof *e; 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * Check to see if this buffer has been written to while on free list. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate check(ret, 0xa5, new_size - sizeof *e); 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * Mark memory we are returning. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate memset(ret, 0xe5, size); 3237c478bd9Sstevel@tonic-gate #else 3247c478bd9Sstevel@tonic-gate ret = freelists[new_size]; 3257c478bd9Sstevel@tonic-gate #endif 3267c478bd9Sstevel@tonic-gate freelists[new_size] = freelists[new_size]->next; 3277c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 3287c478bd9Sstevel@tonic-gate e->next = NULL; 3297c478bd9Sstevel@tonic-gate e->size = size; 3307c478bd9Sstevel@tonic-gate e->fencepost = FRONT_FENCEPOST; 3317c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 3327c478bd9Sstevel@tonic-gate e->file = file; 3337c478bd9Sstevel@tonic-gate e->line = line; 3347c478bd9Sstevel@tonic-gate e->next = activelists[size]; 3357c478bd9Sstevel@tonic-gate activelists[size] = e; 3367c478bd9Sstevel@tonic-gate #endif 3377c478bd9Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 3387c478bd9Sstevel@tonic-gate memcpy(p, &fp, sizeof fp); 3397c478bd9Sstevel@tonic-gate #endif 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * The stats[] uses the _actual_ "size" requested by the 3437c478bd9Sstevel@tonic-gate * caller, with the caveat (in the code above) that "size" >= the 3447c478bd9Sstevel@tonic-gate * max. size (max_size) ends up getting recorded as a call to 3457c478bd9Sstevel@tonic-gate * max_size. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate stats[size].gets++; 3487c478bd9Sstevel@tonic-gate stats[size].totalgets++; 3497c478bd9Sstevel@tonic-gate stats[new_size].freefrags--; 350*9525b14bSRao Shoaib MEMUNLOCK; 3517c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 3527c478bd9Sstevel@tonic-gate return ((char *)e + sizeof *e); 3537c478bd9Sstevel@tonic-gate #else 3547c478bd9Sstevel@tonic-gate return (ret); 3557c478bd9Sstevel@tonic-gate #endif 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 358*9525b14bSRao Shoaib /*% 3597c478bd9Sstevel@tonic-gate * This is a call from an external caller, 3607c478bd9Sstevel@tonic-gate * so we want to count this as a user "put". 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate void 3637c478bd9Sstevel@tonic-gate __memput(void *mem, size_t size) { 3647c478bd9Sstevel@tonic-gate __memput_record(mem, size, NULL, 0); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate void 3687c478bd9Sstevel@tonic-gate __memput_record(void *mem, size_t size, const char *file, int line) { 3697c478bd9Sstevel@tonic-gate size_t new_size = quantize(size); 3707c478bd9Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3717c478bd9Sstevel@tonic-gate memcluster_element *e; 3727c478bd9Sstevel@tonic-gate memcluster_element *el; 3737c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 3747c478bd9Sstevel@tonic-gate memcluster_element *prev; 3757c478bd9Sstevel@tonic-gate #endif 3767c478bd9Sstevel@tonic-gate fence_t fp; 3777c478bd9Sstevel@tonic-gate char *p; 3787c478bd9Sstevel@tonic-gate #endif 3797c478bd9Sstevel@tonic-gate 380*9525b14bSRao Shoaib MEMLOCK; 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate #if !defined (MEMCLUSTER_RECORD) 3837c478bd9Sstevel@tonic-gate UNUSED(file); 3847c478bd9Sstevel@tonic-gate UNUSED(line); 3857c478bd9Sstevel@tonic-gate #endif 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate REQUIRE(freelists != NULL); 3887c478bd9Sstevel@tonic-gate 389*9525b14bSRao Shoaib if (size == 0U) { 390*9525b14bSRao Shoaib MEMUNLOCK; 3917c478bd9Sstevel@tonic-gate errno = EINVAL; 3927c478bd9Sstevel@tonic-gate return; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate #if defined (DEBUGGING_MEMCLUSTER) 3967c478bd9Sstevel@tonic-gate e = (memcluster_element *) ((char *)mem - sizeof *e); 3977c478bd9Sstevel@tonic-gate INSIST(e->fencepost == FRONT_FENCEPOST); 3987c478bd9Sstevel@tonic-gate INSIST(e->size == size); 3997c478bd9Sstevel@tonic-gate p = (char *)e + sizeof *e + size; 4007c478bd9Sstevel@tonic-gate memcpy(&fp, p, sizeof fp); 4017c478bd9Sstevel@tonic-gate INSIST(fp == BACK_FENCEPOST); 402*9525b14bSRao Shoaib INSIST(((u_long)mem % 4) == 0); 4037c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 4047c478bd9Sstevel@tonic-gate prev = NULL; 4057c478bd9Sstevel@tonic-gate if (size == max_size || new_size >= max_size) 4067c478bd9Sstevel@tonic-gate el = activelists[max_size]; 4077c478bd9Sstevel@tonic-gate else 4087c478bd9Sstevel@tonic-gate el = activelists[size]; 4097c478bd9Sstevel@tonic-gate while (el != NULL && el != e) { 4107c478bd9Sstevel@tonic-gate prev = el; 4117c478bd9Sstevel@tonic-gate el = el->next; 4127c478bd9Sstevel@tonic-gate } 413*9525b14bSRao Shoaib INSIST(el != NULL); /*%< double free */ 4147c478bd9Sstevel@tonic-gate if (prev == NULL) { 4157c478bd9Sstevel@tonic-gate if (size == max_size || new_size >= max_size) 4167c478bd9Sstevel@tonic-gate activelists[max_size] = el->next; 4177c478bd9Sstevel@tonic-gate else 4187c478bd9Sstevel@tonic-gate activelists[size] = el->next; 4197c478bd9Sstevel@tonic-gate } else 4207c478bd9Sstevel@tonic-gate prev->next = el->next; 4217c478bd9Sstevel@tonic-gate #endif 4227c478bd9Sstevel@tonic-gate #endif 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (size == max_size || new_size >= max_size) { 4257c478bd9Sstevel@tonic-gate /* memput() called on something beyond our upper limit */ 4267c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 4277c478bd9Sstevel@tonic-gate free(e); 4287c478bd9Sstevel@tonic-gate #else 4297c478bd9Sstevel@tonic-gate free(mem); 4307c478bd9Sstevel@tonic-gate #endif 4317c478bd9Sstevel@tonic-gate 432*9525b14bSRao Shoaib INSIST(stats[max_size].gets != 0U); 4337c478bd9Sstevel@tonic-gate stats[max_size].gets--; 434*9525b14bSRao Shoaib MEMUNLOCK; 4357c478bd9Sstevel@tonic-gate return; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* The free list uses the "rounded-up" size "new_size": */ 4397c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 440*9525b14bSRao Shoaib memset(mem, 0xa5, new_size - sizeof *e); /*%< catch write after free */ 441*9525b14bSRao Shoaib e->size = 0; /*%< catch double memput() */ 4427c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 4437c478bd9Sstevel@tonic-gate e->file = file; 4447c478bd9Sstevel@tonic-gate e->line = line; 4457c478bd9Sstevel@tonic-gate #endif 4467c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_ATEND 4477c478bd9Sstevel@tonic-gate e->next = NULL; 4487c478bd9Sstevel@tonic-gate el = freelists[new_size]; 4497c478bd9Sstevel@tonic-gate while (el != NULL && el->next != NULL) 4507c478bd9Sstevel@tonic-gate el = el->next; 4517c478bd9Sstevel@tonic-gate if (el) 4527c478bd9Sstevel@tonic-gate el->next = e; 4537c478bd9Sstevel@tonic-gate else 4547c478bd9Sstevel@tonic-gate freelists[new_size] = e; 4557c478bd9Sstevel@tonic-gate #else 4567c478bd9Sstevel@tonic-gate e->next = freelists[new_size]; 4577c478bd9Sstevel@tonic-gate freelists[new_size] = (void *)e; 4587c478bd9Sstevel@tonic-gate #endif 4597c478bd9Sstevel@tonic-gate #else 4607c478bd9Sstevel@tonic-gate ((memcluster_element *)mem)->next = freelists[new_size]; 4617c478bd9Sstevel@tonic-gate freelists[new_size] = (memcluster_element *)mem; 4627c478bd9Sstevel@tonic-gate #endif 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * The stats[] uses the _actual_ "size" requested by the 4667c478bd9Sstevel@tonic-gate * caller, with the caveat (in the code above) that "size" >= the 4677c478bd9Sstevel@tonic-gate * max. size (max_size) ends up getting recorded as a call to 4687c478bd9Sstevel@tonic-gate * max_size. 4697c478bd9Sstevel@tonic-gate */ 470*9525b14bSRao Shoaib INSIST(stats[size].gets != 0U); 4717c478bd9Sstevel@tonic-gate stats[size].gets--; 4727c478bd9Sstevel@tonic-gate stats[new_size].freefrags++; 473*9525b14bSRao Shoaib MEMUNLOCK; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate void * 4777c478bd9Sstevel@tonic-gate __memget_debug(size_t size, const char *file, int line) { 4787c478bd9Sstevel@tonic-gate void *ptr; 4797c478bd9Sstevel@tonic-gate ptr = __memget_record(size, file, line); 4807c478bd9Sstevel@tonic-gate fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line, 4817c478bd9Sstevel@tonic-gate (u_long)size, ptr); 4827c478bd9Sstevel@tonic-gate return (ptr); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate void 4867c478bd9Sstevel@tonic-gate __memput_debug(void *ptr, size_t size, const char *file, int line) { 4877c478bd9Sstevel@tonic-gate fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr, 4887c478bd9Sstevel@tonic-gate (u_long)size); 4897c478bd9Sstevel@tonic-gate __memput_record(ptr, size, file, line); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 492*9525b14bSRao Shoaib /*% 4937c478bd9Sstevel@tonic-gate * Print the stats[] on the stream "out" with suitable formatting. 4947c478bd9Sstevel@tonic-gate */ 4957c478bd9Sstevel@tonic-gate void 4967c478bd9Sstevel@tonic-gate memstats(FILE *out) { 4977c478bd9Sstevel@tonic-gate size_t i; 4987c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 4997c478bd9Sstevel@tonic-gate memcluster_element *e; 5007c478bd9Sstevel@tonic-gate #endif 5017c478bd9Sstevel@tonic-gate 502*9525b14bSRao Shoaib MEMLOCK; 503*9525b14bSRao Shoaib 504*9525b14bSRao Shoaib if (freelists == NULL) { 505*9525b14bSRao Shoaib MEMUNLOCK; 5067c478bd9Sstevel@tonic-gate return; 507*9525b14bSRao Shoaib } 5087c478bd9Sstevel@tonic-gate for (i = 1; i <= max_size; i++) { 5097c478bd9Sstevel@tonic-gate const struct stats *s = &stats[i]; 5107c478bd9Sstevel@tonic-gate 511*9525b14bSRao Shoaib if (s->totalgets == 0U && s->gets == 0U) 5127c478bd9Sstevel@tonic-gate continue; 513*9525b14bSRao Shoaib fprintf(out, "%s%5lu: %11lu gets, %11lu rem", 5147c478bd9Sstevel@tonic-gate (i == max_size) ? ">=" : " ", 515*9525b14bSRao Shoaib (unsigned long)i, s->totalgets, s->gets); 516*9525b14bSRao Shoaib if (s->blocks != 0U) 5177c478bd9Sstevel@tonic-gate fprintf(out, " (%lu bl, %lu ff)", 5187c478bd9Sstevel@tonic-gate s->blocks, s->freefrags); 5197c478bd9Sstevel@tonic-gate fputc('\n', out); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate #ifdef MEMCLUSTER_RECORD 5227c478bd9Sstevel@tonic-gate fprintf(out, "Active Memory:\n"); 5237c478bd9Sstevel@tonic-gate for (i = 1; i <= max_size; i++) { 5247c478bd9Sstevel@tonic-gate if ((e = activelists[i]) != NULL) 5257c478bd9Sstevel@tonic-gate while (e != NULL) { 526*9525b14bSRao Shoaib fprintf(out, "%s:%d %p:%lu\n", 5277c478bd9Sstevel@tonic-gate e->file != NULL ? e->file : 5287c478bd9Sstevel@tonic-gate "<UNKNOWN>", e->line, 529*9525b14bSRao Shoaib (char *)e + sizeof *e, 530*9525b14bSRao Shoaib (u_long)e->size); 5317c478bd9Sstevel@tonic-gate e = e->next; 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate #endif 535*9525b14bSRao Shoaib MEMUNLOCK; 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate int 5397c478bd9Sstevel@tonic-gate memactive(void) { 5407c478bd9Sstevel@tonic-gate size_t i; 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate if (stats == NULL) 5437c478bd9Sstevel@tonic-gate return (0); 5447c478bd9Sstevel@tonic-gate for (i = 1; i <= max_size; i++) 545*9525b14bSRao Shoaib if (stats[i].gets != 0U) 5467c478bd9Sstevel@tonic-gate return (1); 5477c478bd9Sstevel@tonic-gate return (0); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate /* Private. */ 5517c478bd9Sstevel@tonic-gate 552*9525b14bSRao Shoaib /*% 5537c478bd9Sstevel@tonic-gate * Round up size to a multiple of sizeof(void *). This guarantees that a 5547c478bd9Sstevel@tonic-gate * block is at least sizeof void *, and that we won't violate alignment 5557c478bd9Sstevel@tonic-gate * restrictions, both of which are needed to make lists of blocks. 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate static size_t 5587c478bd9Sstevel@tonic-gate quantize(size_t size) { 5597c478bd9Sstevel@tonic-gate int remainder; 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate * If there is no remainder for the integer division of 5627c478bd9Sstevel@tonic-gate * 5637c478bd9Sstevel@tonic-gate * (rightsize/P_SIZE) 5647c478bd9Sstevel@tonic-gate * 5657c478bd9Sstevel@tonic-gate * then we already have a good size; if not, then we need 5667c478bd9Sstevel@tonic-gate * to round up the result in order to get a size big 5677c478bd9Sstevel@tonic-gate * enough to satisfy the request _and_ aligned on P_SIZE boundaries. 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate remainder = size % P_SIZE; 5707c478bd9Sstevel@tonic-gate if (remainder != 0) 5717c478bd9Sstevel@tonic-gate size += P_SIZE - remainder; 5727c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 5737c478bd9Sstevel@tonic-gate return (size + SMALL_SIZE_LIMIT + sizeof (int)); 5747c478bd9Sstevel@tonic-gate #else 5757c478bd9Sstevel@tonic-gate return (size); 5767c478bd9Sstevel@tonic-gate #endif 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate #if defined(DEBUGGING_MEMCLUSTER) 5807c478bd9Sstevel@tonic-gate static void 5817c478bd9Sstevel@tonic-gate check(unsigned char *a, int value, size_t len) { 5827c478bd9Sstevel@tonic-gate size_t i; 5837c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 5847c478bd9Sstevel@tonic-gate INSIST(a[i] == value); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate #endif 587*9525b14bSRao Shoaib 588*9525b14bSRao Shoaib /*! \file */ 589