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