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