1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <mtmalloc.h> 30 #include "mtmalloc_impl.h" 31 #include <unistd.h> 32 #include <synch.h> 33 #include <thread.h> 34 #include <pthread.h> 35 #include <stdio.h> 36 #include <limits.h> 37 #include <errno.h> 38 #include <string.h> 39 #include <strings.h> 40 #include <sys/param.h> 41 #include <sys/sysmacros.h> 42 43 /* 44 * To turn on the asserts just compile -DDEBUG 45 */ 46 47 #ifndef DEBUG 48 #define NDEBUG 49 #endif 50 51 #include <assert.h> 52 53 /* 54 * The MT hot malloc implementation contained herein is designed to be 55 * plug-compatible with the libc version of malloc. It is not intended 56 * to replace that implementation until we decide that it is ok to break 57 * customer apps (Solaris 3.0). 58 * 59 * For requests up to 2^^16, the allocator initializes itself into NCPUS 60 * worth of chains of caches. When a memory request is made, the calling thread 61 * is vectored into one of NCPUS worth of caches. The LWP id gives us a cheap, 62 * contention-reducing index to use, eventually, this should be replaced with 63 * the actual CPU sequence number, when an interface to get it is available. 64 * 65 * Once the thread is vectored into one of the list of caches the real 66 * allocation of the memory begins. The size is determined to figure out which 67 * bucket the allocation should be satisfied from. The management of free 68 * buckets is done via a bitmask. A free bucket is represented by a 1. The 69 * first free bit represents the first free bucket. The position of the bit, 70 * represents the position of the bucket in the arena. 71 * 72 * When the memory from the arena is handed out, the address of the cache 73 * control structure is written in the word preceeding the returned memory. 74 * This cache control address is used during free() to mark the buffer free 75 * in the cache control structure. 76 * 77 * When all available memory in a cache has been depleted, a new chunk of memory 78 * is allocated via sbrk(). The new cache is allocated from this chunk of memory 79 * and initialized in the function create_cache(). New caches are installed at 80 * the front of a singly linked list of the same size memory pools. This helps 81 * to ensure that there will tend to be available memory in the beginning of the 82 * list. 83 * 84 * Long linked lists hurt performance. To decrease this effect, there is a 85 * tunable, requestsize, that bumps up the sbrk allocation size and thus 86 * increases the number of available blocks within an arena. We also keep 87 * a "hint" for each cache list, which is the last cache in the list allocated 88 * from. This lowers the cost of searching if there are a lot of fully 89 * allocated blocks at the front of the list. 90 * 91 * For requests greater than 2^^16 (oversize allocations), there are two pieces 92 * of overhead. There is the OVERHEAD used to hold the cache addr 93 * (&oversize_list), plus an oversize_t structure to further describe the block. 94 * 95 * The oversize list is kept as defragmented as possible by coalescing 96 * freed oversized allocations with adjacent neighbors. 97 * 98 * Addresses handed out are stored in a hash table, and are aligned on 99 * MTMALLOC_MIN_ALIGN-byte boundaries at both ends. Request sizes are rounded-up 100 * where necessary in order to achieve this. This eases the implementation of 101 * MTDEBUGPATTERN and MTINITPATTERN, particularly where coalescing occurs. 102 * 103 * A memalign allocation takes memalign header overhead. There's two 104 * types of memalign headers distinguished by MTMALLOC_MEMALIGN_MAGIC 105 * and MTMALLOC_MEMALIGN_MIN_MAGIC. When the size of memory taken to 106 * get to the aligned address from malloc'ed address is the minimum size 107 * OVERHEAD, we create a header taking only one OVERHEAD space with magic 108 * number MTMALLOC_MEMALIGN_MIN_MAGIC, and we know by subtracting OVERHEAD 109 * from memaligned address, we can get to the malloc'ed address. Otherwise, 110 * we create a memalign header taking two OVERHEAD space, one stores 111 * MTMALLOC_MEMALIGN_MAGIC magic number, the other one points back to the 112 * malloc'ed address. 113 */ 114 115 #if defined(__i386) || defined(__amd64) 116 #include <arpa/inet.h> /* for htonl() */ 117 #endif 118 119 static void * morecore(size_t); 120 static void create_cache(cache_t *, size_t bufsize, uint_t hunks); 121 static void * malloc_internal(size_t, percpu_t *); 122 static void * oversize(size_t); 123 static oversize_t *find_oversize(size_t); 124 static void add_oversize(oversize_t *); 125 static void copy_pattern(uint32_t, void *, size_t); 126 static void * verify_pattern(uint32_t, void *, size_t); 127 static void reinit_cpu_list(void); 128 static void reinit_cache(cache_t *); 129 static void free_oversize(oversize_t *); 130 static oversize_t *oversize_header_alloc(uintptr_t, size_t); 131 132 /* 133 * oversize hash table stuff 134 */ 135 #define NUM_BUCKETS 67 /* must be prime */ 136 #define HASH_OVERSIZE(caddr) ((uintptr_t)(caddr) % NUM_BUCKETS) 137 oversize_t *ovsz_hashtab[NUM_BUCKETS]; 138 139 #define ALIGN(x, a) ((((uintptr_t)(x) + ((uintptr_t)(a) - 1)) \ 140 & ~((uintptr_t)(a) - 1))) 141 142 /* need this to deal with little endianess of x86 */ 143 #if defined(__i386) || defined(__amd64) 144 #define FLIP_EM(x) htonl((x)) 145 #else 146 #define FLIP_EM(x) (x) 147 #endif 148 149 #define INSERT_ONLY 0 150 #define COALESCE_LEFT 0x00000001 151 #define COALESCE_RIGHT 0x00000002 152 #define COALESCE_WITH_BOTH_SIDES (COALESCE_LEFT | COALESCE_RIGHT) 153 154 #define OVERHEAD 8 /* size needed to write cache addr */ 155 #define HUNKSIZE 8192 /* just a multiplier */ 156 157 #define MAX_CACHED_SHIFT 16 /* 64K is the max cached size */ 158 #define MAX_CACHED (1 << MAX_CACHED_SHIFT) 159 #define MIN_CACHED_SHIFT 4 /* smaller requests rounded up */ 160 #define MTMALLOC_MIN_ALIGN 8 /* min guaranteed alignment */ 161 162 /* maximum size before overflow */ 163 #define MAX_MTMALLOC (SIZE_MAX - (SIZE_MAX % MTMALLOC_MIN_ALIGN) \ 164 - OVSZ_HEADER_SIZE) 165 166 #define NUM_CACHES (MAX_CACHED_SHIFT - MIN_CACHED_SHIFT + 1) 167 #define CACHELIST_SIZE ALIGN(NUM_CACHES * sizeof (cache_head_t), \ 168 CACHE_COHERENCY_UNIT) 169 170 #define MINSIZE 9 /* for requestsize, tunable */ 171 #define MAXSIZE 256 /* arbitrary, big enough, for requestsize */ 172 173 #define FREEPATTERN 0xdeadbeef /* debug fill pattern for free buf */ 174 #define INITPATTERN 0xbaddcafe /* debug fill pattern for new buf */ 175 176 #define misaligned(p) ((unsigned)(p) & (sizeof (int) - 1)) 177 #define IS_OVERSIZE(x, y) (((x) < (y)) && (((x) > MAX_CACHED)? 1 : 0)) 178 179 static long requestsize = MINSIZE; /* 9 pages per cache; tunable; 9 is min */ 180 181 static uint_t cpu_mask; 182 static curcpu_func curcpu; 183 184 static int32_t debugopt; 185 static int32_t reinit; 186 187 static percpu_t *cpu_list; 188 static oversize_t oversize_list; 189 static mutex_t oversize_lock = DEFAULTMUTEX; 190 191 static int ncpus = 0; 192 193 #define MTMALLOC_OVERSIZE_MAGIC ((uintptr_t)&oversize_list) 194 #define MTMALLOC_MEMALIGN_MAGIC ((uintptr_t)&oversize_list + 1) 195 #define MTMALLOC_MEMALIGN_MIN_MAGIC ((uintptr_t)&oversize_list + 2) 196 197 /* 198 * We require allocations handed out to be aligned on MTMALLOC_MIN_ALIGN-byte 199 * boundaries. We round up sizeof (oversize_t) (when necessary) to ensure that 200 * this is achieved. 201 */ 202 #define OVSZ_SIZE (ALIGN(sizeof (oversize_t), MTMALLOC_MIN_ALIGN)) 203 #define OVSZ_HEADER_SIZE (OVSZ_SIZE + OVERHEAD) 204 205 /* 206 * memalign header takes 2 OVERHEAD space. One for memalign magic, and the 207 * other one points back to the start address of originally allocated space. 208 */ 209 #define MEMALIGN_HEADER_SIZE 2 * OVERHEAD 210 #define MEMALIGN_HEADER_ALLOC(x, shift, malloc_addr)\ 211 if (shift == OVERHEAD)\ 212 *((uintptr_t *)((caddr_t)x - OVERHEAD)) = \ 213 MTMALLOC_MEMALIGN_MIN_MAGIC; \ 214 else {\ 215 *((uintptr_t *)((caddr_t)x - OVERHEAD)) = \ 216 MTMALLOC_MEMALIGN_MAGIC; \ 217 *((uintptr_t *)((caddr_t)x - 2 * OVERHEAD)) = \ 218 (uintptr_t)malloc_addr; \ 219 } 220 221 /* 222 * Add big to the oversize hash table at the head of the relevant bucket. 223 */ 224 static void 225 insert_hash(oversize_t *big) 226 { 227 caddr_t ret = big->addr; 228 int bucket = HASH_OVERSIZE(ret); 229 230 assert(MUTEX_HELD(&oversize_lock)); 231 big->hash_next = ovsz_hashtab[bucket]; 232 ovsz_hashtab[bucket] = big; 233 } 234 235 void * 236 malloc(size_t bytes) 237 { 238 percpu_t *list_rotor; 239 uint_t list_index; 240 241 if (bytes > MAX_CACHED) 242 return (oversize(bytes)); 243 244 list_index = (curcpu() & cpu_mask); 245 246 list_rotor = &cpu_list[list_index]; 247 248 return (malloc_internal(bytes, list_rotor)); 249 } 250 251 void * 252 realloc(void * ptr, size_t bytes) 253 { 254 void *new, *data_ptr; 255 cache_t *cacheptr; 256 caddr_t mem; 257 size_t shift = 0; 258 259 if (ptr == NULL) 260 return (malloc(bytes)); 261 262 if (bytes == 0) { 263 free(ptr); 264 return (NULL); 265 } 266 267 data_ptr = ptr; 268 mem = (caddr_t)ptr - OVERHEAD; 269 270 new = malloc(bytes); 271 272 if (new == NULL) 273 return (NULL); 274 275 /* 276 * If new == ptr, ptr has previously been freed. Passing a freed pointer 277 * to realloc() is not allowed - unless the caller specifically states 278 * otherwise, in which case we must avoid freeing ptr (ie new) before we 279 * return new. There is (obviously) no requirement to memcpy() ptr to 280 * new before we return. 281 */ 282 if (new == ptr) { 283 if (!(debugopt & MTDOUBLEFREE)) 284 abort(); 285 return (new); 286 } 287 288 if (*(uintptr_t *)mem == MTMALLOC_MEMALIGN_MAGIC) { 289 mem -= OVERHEAD; 290 ptr = (void *)*(uintptr_t *)mem; 291 mem = (caddr_t)ptr - OVERHEAD; 292 shift = (size_t)((uintptr_t)data_ptr - (uintptr_t)ptr); 293 } else if (*(uintptr_t *)mem == MTMALLOC_MEMALIGN_MIN_MAGIC) { 294 ptr = (void *) mem; 295 mem -= OVERHEAD; 296 shift = OVERHEAD; 297 } 298 299 if (*(uintptr_t *)mem == MTMALLOC_OVERSIZE_MAGIC) { 300 oversize_t *old; 301 302 old = (oversize_t *)(mem - OVSZ_SIZE); 303 (void) memcpy(new, data_ptr, MIN(bytes, old->size - shift)); 304 free(ptr); 305 return (new); 306 } 307 308 cacheptr = (cache_t *)*(uintptr_t *)mem; 309 310 (void) memcpy(new, data_ptr, 311 MIN(cacheptr->mt_size - OVERHEAD - shift, bytes)); 312 free(ptr); 313 314 return (new); 315 } 316 317 void * 318 calloc(size_t nelem, size_t bytes) 319 { 320 void * ptr; 321 size_t size = nelem * bytes; 322 323 ptr = malloc(size); 324 if (ptr == NULL) 325 return (NULL); 326 (void) memset(ptr, 0, size); 327 328 return (ptr); 329 } 330 331 void 332 free(void * ptr) 333 { 334 cache_t *cacheptr; 335 caddr_t mem; 336 int32_t i; 337 caddr_t freeblocks; 338 uintptr_t offset; 339 uchar_t mask; 340 int32_t which_bit, num_bytes; 341 342 if (ptr == NULL) 343 return; 344 345 mem = (caddr_t)ptr - OVERHEAD; 346 347 if (*(uintptr_t *)mem == MTMALLOC_MEMALIGN_MAGIC) { 348 mem -= OVERHEAD; 349 ptr = (void *)*(uintptr_t *)mem; 350 mem = (caddr_t)ptr - OVERHEAD; 351 } else if (*(uintptr_t *)mem == MTMALLOC_MEMALIGN_MIN_MAGIC) { 352 ptr = (void *) mem; 353 mem -= OVERHEAD; 354 } 355 356 if (*(uintptr_t *)mem == MTMALLOC_OVERSIZE_MAGIC) { 357 oversize_t *big, **opp; 358 int bucket; 359 360 big = (oversize_t *)(mem - OVSZ_SIZE); 361 (void) mutex_lock(&oversize_lock); 362 363 bucket = HASH_OVERSIZE(big->addr); 364 for (opp = &ovsz_hashtab[bucket]; *opp != NULL; 365 opp = &(*opp)->hash_next) 366 if (*opp == big) 367 break; 368 369 if (*opp == NULL) { 370 if (!(debugopt & MTDOUBLEFREE)) 371 abort(); 372 (void) mutex_unlock(&oversize_lock); 373 return; 374 } 375 376 *opp = big->hash_next; /* remove big from the hash table */ 377 big->hash_next = NULL; 378 379 if (debugopt & MTDEBUGPATTERN) 380 copy_pattern(FREEPATTERN, ptr, big->size); 381 add_oversize(big); 382 (void) mutex_unlock(&oversize_lock); 383 return; 384 } 385 386 cacheptr = (cache_t *)*(uintptr_t *)mem; 387 freeblocks = cacheptr->mt_freelist; 388 389 /* 390 * This is the distance measured in bits into the arena. 391 * The value of offset is in bytes but there is a 1-1 correlation 392 * between distance into the arena and distance into the 393 * freelist bitmask. 394 */ 395 offset = mem - cacheptr->mt_arena; 396 397 /* 398 * i is total number of bits to offset into freelist bitmask. 399 */ 400 401 i = offset / cacheptr->mt_size; 402 403 num_bytes = i >> 3; 404 405 /* 406 * which_bit is the bit offset into the byte in the freelist. 407 * if our freelist bitmask looks like 0xf3 and we are freeing 408 * block 5 (ie: the 6th block) our mask will be 0xf7 after 409 * the free. Things go left to right that's why the mask is 0x80 410 * and not 0x01. 411 */ 412 which_bit = i - (num_bytes << 3); 413 414 mask = 0x80 >> which_bit; 415 416 freeblocks += num_bytes; 417 418 if (debugopt & MTDEBUGPATTERN) 419 copy_pattern(FREEPATTERN, ptr, cacheptr->mt_size - OVERHEAD); 420 421 (void) mutex_lock(&cacheptr->mt_cache_lock); 422 423 if (*freeblocks & mask) { 424 if (!(debugopt & MTDOUBLEFREE)) 425 abort(); 426 } else { 427 *freeblocks |= mask; 428 cacheptr->mt_nfree++; 429 } 430 431 (void) mutex_unlock(&cacheptr->mt_cache_lock); 432 } 433 434 void * 435 memalign(size_t alignment, size_t size) 436 { 437 size_t alloc_size; 438 uintptr_t offset; 439 void *alloc_buf; 440 void *ret_buf; 441 442 if (size == 0 || alignment == 0 || 443 misaligned(alignment) || 444 (alignment & (alignment - 1)) != 0) { 445 errno = EINVAL; 446 return (NULL); 447 } 448 449 /* <= MTMALLOC_MIN_ALIGN, malloc can provide directly */ 450 if (alignment <= MTMALLOC_MIN_ALIGN) 451 return (malloc(size)); 452 453 alloc_size = size + alignment - MTMALLOC_MIN_ALIGN; 454 455 if (alloc_size < size) { /* overflow */ 456 errno = ENOMEM; 457 return (NULL); 458 } 459 460 alloc_buf = malloc(alloc_size); 461 462 if (alloc_buf == NULL) 463 /* malloc sets errno */ 464 return (NULL); 465 466 /* 467 * If alloc_size > MAX_CACHED, malloc() will have returned a multiple of 468 * MTMALLOC_MIN_ALIGN, having rounded-up alloc_size if necessary. Since 469 * we will use alloc_size to return the excess fragments to the free 470 * list, we also round-up alloc_size if necessary. 471 */ 472 if ((alloc_size > MAX_CACHED) && 473 (alloc_size & (MTMALLOC_MIN_ALIGN - 1))) 474 alloc_size = ALIGN(alloc_size, MTMALLOC_MIN_ALIGN); 475 476 if ((offset = (uintptr_t)alloc_buf & (alignment - 1)) == 0) { 477 /* aligned correctly */ 478 479 size_t frag_size = alloc_size - 480 (size + MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); 481 482 /* 483 * If the leftover piece of the memory > MAX_CACHED, 484 * split off the piece and return it back to the freelist. 485 */ 486 if (IS_OVERSIZE(frag_size, alloc_size)) { 487 oversize_t *orig, *tail; 488 uintptr_t taddr; 489 size_t data_size; 490 taddr = ALIGN((uintptr_t)alloc_buf + size, 491 MTMALLOC_MIN_ALIGN); 492 data_size = taddr - (uintptr_t)alloc_buf; 493 orig = (oversize_t *)((uintptr_t)alloc_buf - 494 OVSZ_HEADER_SIZE); 495 frag_size = orig->size - data_size - 496 OVSZ_HEADER_SIZE; 497 orig->size = data_size; 498 tail = oversize_header_alloc(taddr, frag_size); 499 free_oversize(tail); 500 } 501 ret_buf = alloc_buf; 502 } else { 503 uchar_t oversize_bits = 0; 504 size_t head_sz, data_sz, tail_sz; 505 uintptr_t ret_addr, taddr, shift, tshift; 506 oversize_t *orig, *tail, *big; 507 size_t tsize; 508 509 /* needs to be aligned */ 510 shift = alignment - offset; 511 512 assert(shift >= MTMALLOC_MIN_ALIGN); 513 514 ret_addr = ((uintptr_t)alloc_buf + shift); 515 ret_buf = (void *)ret_addr; 516 517 if (alloc_size <= MAX_CACHED) { 518 MEMALIGN_HEADER_ALLOC(ret_addr, shift, alloc_buf); 519 return (ret_buf); 520 } 521 522 /* 523 * Only check for the fragments when the memory is allocted 524 * from oversize_list. Split off a fragment and return it 525 * to the oversize freelist when it's > MAX_CACHED. 526 */ 527 528 head_sz = shift - MAX(MEMALIGN_HEADER_SIZE, OVSZ_HEADER_SIZE); 529 530 tail_sz = alloc_size - 531 (shift + size + MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); 532 533 oversize_bits |= IS_OVERSIZE(head_sz, alloc_size) | 534 IS_OVERSIZE(size, alloc_size) << DATA_SHIFT | 535 IS_OVERSIZE(tail_sz, alloc_size) << TAIL_SHIFT; 536 537 switch (oversize_bits) { 538 case NONE_OVERSIZE: 539 case DATA_OVERSIZE: 540 MEMALIGN_HEADER_ALLOC(ret_addr, shift, 541 alloc_buf); 542 break; 543 case HEAD_OVERSIZE: 544 /* 545 * If we can extend data > MAX_CACHED and have 546 * head still > MAX_CACHED, we split head-end 547 * as the case of head-end and data oversized, 548 * otherwise just create memalign header. 549 */ 550 tsize = (shift + size) - (MAX_CACHED + 8 + 551 MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); 552 553 if (!IS_OVERSIZE(tsize, alloc_size)) { 554 MEMALIGN_HEADER_ALLOC(ret_addr, shift, 555 alloc_buf); 556 break; 557 } else { 558 tsize += OVSZ_HEADER_SIZE; 559 taddr = ALIGN((uintptr_t)alloc_buf + 560 tsize, MTMALLOC_MIN_ALIGN); 561 tshift = ret_addr - taddr; 562 MEMALIGN_HEADER_ALLOC(ret_addr, tshift, 563 taddr); 564 ret_addr = taddr; 565 shift = ret_addr - (uintptr_t)alloc_buf; 566 } 567 /* FALLTHROUGH */ 568 case HEAD_AND_DATA_OVERSIZE: 569 /* 570 * Split off the head fragment and 571 * return it back to oversize freelist. 572 * Create oversize header for the piece 573 * of (data + tail fragment). 574 */ 575 orig = (oversize_t *)((uintptr_t)alloc_buf - 576 OVSZ_HEADER_SIZE); 577 big = oversize_header_alloc(ret_addr - 578 OVSZ_HEADER_SIZE, 579 (orig->size - shift)); 580 (void) mutex_lock(&oversize_lock); 581 insert_hash(big); 582 (void) mutex_unlock(&oversize_lock); 583 orig->size = shift - OVSZ_HEADER_SIZE; 584 585 /* free up the head fragment */ 586 free_oversize(orig); 587 break; 588 case TAIL_OVERSIZE: 589 /* 590 * If we can extend data > MAX_CACHED and have 591 * tail-end still > MAX_CACHED, we split tail 592 * end, otherwise just create memalign header. 593 */ 594 orig = (oversize_t *)((uintptr_t)alloc_buf - 595 OVSZ_HEADER_SIZE); 596 tsize = orig->size - (MAX_CACHED + 8 + 597 shift + OVSZ_HEADER_SIZE + 598 MTMALLOC_MIN_ALIGN); 599 if (!IS_OVERSIZE(tsize, alloc_size)) { 600 MEMALIGN_HEADER_ALLOC(ret_addr, shift, 601 alloc_buf); 602 break; 603 } else { 604 size = MAX_CACHED + 8; 605 } 606 /* FALLTHROUGH */ 607 case DATA_AND_TAIL_OVERSIZE: 608 /* 609 * Split off the tail fragment and 610 * return it back to oversize freelist. 611 * Create memalign header and adjust 612 * the size for the piece of 613 * (head fragment + data). 614 */ 615 taddr = ALIGN(ret_addr + size, 616 MTMALLOC_MIN_ALIGN); 617 data_sz = (size_t)(taddr - 618 (uintptr_t)alloc_buf); 619 orig = (oversize_t *)((uintptr_t)alloc_buf - 620 OVSZ_HEADER_SIZE); 621 tsize = orig->size - data_sz; 622 orig->size = data_sz; 623 MEMALIGN_HEADER_ALLOC(ret_buf, shift, 624 alloc_buf); 625 tsize -= OVSZ_HEADER_SIZE; 626 tail = oversize_header_alloc(taddr, tsize); 627 free_oversize(tail); 628 break; 629 case HEAD_AND_TAIL_OVERSIZE: 630 /* 631 * Split off the head fragment. 632 * We try to free up tail-end when we can 633 * extend data size to (MAX_CACHED + 8) 634 * and remain tail-end oversized. 635 * The bottom line is all split pieces 636 * should be oversize in size. 637 */ 638 orig = (oversize_t *)((uintptr_t)alloc_buf - 639 OVSZ_HEADER_SIZE); 640 tsize = orig->size - (MAX_CACHED + 8 + 641 OVSZ_HEADER_SIZE + shift + 642 MTMALLOC_MIN_ALIGN); 643 644 if (!IS_OVERSIZE(tsize, alloc_size)) { 645 /* 646 * If the chunk is not big enough 647 * to make both data and tail oversize 648 * we just keep them as one piece. 649 */ 650 big = oversize_header_alloc(ret_addr - 651 OVSZ_HEADER_SIZE, 652 orig->size - shift); 653 (void) mutex_lock(&oversize_lock); 654 insert_hash(big); 655 (void) mutex_unlock(&oversize_lock); 656 orig->size = shift - 657 OVSZ_HEADER_SIZE; 658 free_oversize(orig); 659 break; 660 } else { 661 /* 662 * extend data size > MAX_CACHED 663 * and handle it as head, data, tail 664 * are all oversized. 665 */ 666 size = MAX_CACHED + 8; 667 } 668 /* FALLTHROUGH */ 669 case ALL_OVERSIZE: 670 /* 671 * split off the head and tail fragments, 672 * return them back to the oversize freelist. 673 * Alloc oversize header for data seg. 674 */ 675 orig = (oversize_t *)((uintptr_t)alloc_buf - 676 OVSZ_HEADER_SIZE); 677 tsize = orig->size; 678 orig->size = shift - OVSZ_HEADER_SIZE; 679 free_oversize(orig); 680 681 taddr = ALIGN(ret_addr + size, 682 MTMALLOC_MIN_ALIGN); 683 data_sz = taddr - ret_addr; 684 assert(tsize > (shift + data_sz + 685 OVSZ_HEADER_SIZE)); 686 tail_sz = tsize - 687 (shift + data_sz + OVSZ_HEADER_SIZE); 688 689 /* create oversize header for data seg */ 690 big = oversize_header_alloc(ret_addr - 691 OVSZ_HEADER_SIZE, data_sz); 692 (void) mutex_lock(&oversize_lock); 693 insert_hash(big); 694 (void) mutex_unlock(&oversize_lock); 695 696 /* create oversize header for tail fragment */ 697 tail = oversize_header_alloc(taddr, tail_sz); 698 free_oversize(tail); 699 break; 700 default: 701 /* should not reach here */ 702 assert(0); 703 } 704 } 705 return (ret_buf); 706 } 707 708 709 void * 710 valloc(size_t size) 711 { 712 static unsigned pagesize; 713 714 if (size == 0) 715 return (NULL); 716 717 if (!pagesize) 718 pagesize = sysconf(_SC_PAGESIZE); 719 720 return (memalign(pagesize, size)); 721 } 722 723 void 724 mallocctl(int cmd, long value) 725 { 726 switch (cmd) { 727 728 case MTDEBUGPATTERN: 729 /* 730 * Reinitialize free blocks in case malloc() is called prior 731 * to mallocctl(). 732 */ 733 if (value && !(debugopt & cmd)) { 734 reinit++; 735 debugopt |= cmd; 736 reinit_cpu_list(); 737 } 738 /*FALLTHRU*/ 739 case MTDOUBLEFREE: 740 case MTINITBUFFER: 741 if (value) 742 debugopt |= cmd; 743 else 744 debugopt &= ~cmd; 745 break; 746 case MTCHUNKSIZE: 747 if (value >= MINSIZE && value <= MAXSIZE) 748 requestsize = value; 749 break; 750 default: 751 break; 752 } 753 } 754 755 /* 756 * Initialization function, called from the init section of the library. 757 * No locking is required here because we are single-threaded during 758 * library initialization. 759 */ 760 static void 761 setup_caches(void) 762 { 763 uintptr_t oldbrk; 764 uintptr_t newbrk; 765 766 size_t cache_space_needed; 767 size_t padding; 768 769 curcpu_func new_curcpu; 770 uint_t new_cpu_mask; 771 percpu_t *new_cpu_list; 772 773 uint_t i, j; 774 uintptr_t list_addr; 775 776 /* 777 * Get a decent "current cpu identifier", to be used to reduce 778 * contention. Eventually, this should be replaced by an interface 779 * to get the actual CPU sequence number in libthread/liblwp. 780 */ 781 new_curcpu = (curcpu_func)thr_self; 782 if ((ncpus = 2 * sysconf(_SC_NPROCESSORS_CONF)) <= 0) 783 ncpus = 4; /* decent default value */ 784 785 /* round ncpus up to a power of 2 */ 786 while (ncpus & (ncpus - 1)) 787 ncpus++; 788 789 new_cpu_mask = ncpus - 1; /* create the cpu mask */ 790 791 /* 792 * We now do some magic with the brk. What we want to get in the 793 * end is a bunch of well-aligned stuff in a big initial allocation. 794 * Along the way, we do sanity checks to make sure no one else has 795 * touched the brk (which shouldn't happen, but it's always good to 796 * check) 797 * 798 * First, make sure sbrk is sane, and store the current brk in oldbrk. 799 */ 800 oldbrk = (uintptr_t)sbrk(0); 801 if ((void *)oldbrk == (void *)-1) 802 abort(); /* sbrk is broken -- we're doomed. */ 803 804 /* 805 * Now, align the brk to a multiple of CACHE_COHERENCY_UNIT, so that 806 * the percpu structures and cache lists will be properly aligned. 807 * 808 * 2. All hunks will be page-aligned, assuming HUNKSIZE >= PAGESIZE, 809 * so they can be paged out individually. 810 */ 811 newbrk = ALIGN(oldbrk, CACHE_COHERENCY_UNIT); 812 if (newbrk != oldbrk && (uintptr_t)sbrk(newbrk - oldbrk) != oldbrk) 813 abort(); /* sbrk is broken -- we're doomed. */ 814 815 /* 816 * For each cpu, there is one percpu_t and a list of caches 817 */ 818 cache_space_needed = ncpus * (sizeof (percpu_t) + CACHELIST_SIZE); 819 820 new_cpu_list = (percpu_t *)sbrk(cache_space_needed); 821 822 if (new_cpu_list == (percpu_t *)-1 || 823 (uintptr_t)new_cpu_list != newbrk) 824 abort(); /* sbrk is broken -- we're doomed. */ 825 826 /* 827 * Finally, align the brk to HUNKSIZE so that all hunks are 828 * page-aligned, to avoid edge-effects. 829 */ 830 831 newbrk = (uintptr_t)new_cpu_list + cache_space_needed; 832 833 padding = ALIGN(newbrk, HUNKSIZE) - newbrk; 834 835 if (padding > 0 && (uintptr_t)sbrk(padding) != newbrk) 836 abort(); /* sbrk is broken -- we're doomed. */ 837 838 list_addr = ((uintptr_t)new_cpu_list + (sizeof (percpu_t) * ncpus)); 839 840 /* initialize the percpu list */ 841 for (i = 0; i < ncpus; i++) { 842 new_cpu_list[i].mt_caches = (cache_head_t *)list_addr; 843 for (j = 0; j < NUM_CACHES; j++) { 844 new_cpu_list[i].mt_caches[j].mt_cache = NULL; 845 new_cpu_list[i].mt_caches[j].mt_hint = NULL; 846 } 847 848 (void) mutex_init(&new_cpu_list[i].mt_parent_lock, 849 USYNC_THREAD, NULL); 850 851 /* get the correct cache list alignment */ 852 list_addr += CACHELIST_SIZE; 853 } 854 855 /* 856 * Initialize oversize listhead 857 */ 858 oversize_list.next_bysize = &oversize_list; 859 oversize_list.prev_bysize = &oversize_list; 860 oversize_list.next_byaddr = &oversize_list; 861 oversize_list.prev_byaddr = &oversize_list; 862 oversize_list.addr = NULL; 863 oversize_list.size = 0; /* sentinal */ 864 865 /* 866 * Now install the global variables. 867 */ 868 curcpu = new_curcpu; 869 cpu_mask = new_cpu_mask; 870 cpu_list = new_cpu_list; 871 } 872 873 static void 874 create_cache(cache_t *cp, size_t size, uint_t chunksize) 875 { 876 long nblocks; 877 878 (void) mutex_init(&cp->mt_cache_lock, USYNC_THREAD, NULL); 879 cp->mt_size = size; 880 cp->mt_freelist = ((caddr_t)cp + sizeof (cache_t)); 881 cp->mt_span = chunksize * HUNKSIZE - sizeof (cache_t); 882 cp->mt_hunks = chunksize; 883 /* 884 * rough calculation. We will need to adjust later. 885 */ 886 nblocks = cp->mt_span / cp->mt_size; 887 nblocks >>= 3; 888 if (nblocks == 0) { /* less than 8 free blocks in this pool */ 889 int32_t numblocks = 0; 890 long i = cp->mt_span; 891 size_t sub = cp->mt_size; 892 uchar_t mask = 0; 893 894 while (i > sub) { 895 numblocks++; 896 i -= sub; 897 } 898 nblocks = numblocks; 899 cp->mt_arena = (caddr_t)ALIGN(cp->mt_freelist + 8, 8); 900 cp->mt_nfree = numblocks; 901 while (numblocks--) { 902 mask |= 0x80 >> numblocks; 903 } 904 *(cp->mt_freelist) = mask; 905 } else { 906 cp->mt_arena = (caddr_t)ALIGN((caddr_t)cp->mt_freelist + 907 nblocks, 32); 908 /* recompute nblocks */ 909 nblocks = (uintptr_t)((caddr_t)cp->mt_freelist + 910 cp->mt_span - cp->mt_arena) / cp->mt_size; 911 cp->mt_nfree = ((nblocks >> 3) << 3); 912 /* Set everything to free */ 913 (void) memset(cp->mt_freelist, 0xff, nblocks >> 3); 914 } 915 916 if (debugopt & MTDEBUGPATTERN) 917 copy_pattern(FREEPATTERN, cp->mt_arena, cp->mt_size * nblocks); 918 919 cp->mt_next = NULL; 920 } 921 922 static void 923 reinit_cpu_list(void) 924 { 925 oversize_t *wp = oversize_list.next_bysize; 926 percpu_t *cpuptr; 927 cache_t *thiscache; 928 cache_head_t *cachehead; 929 930 /* Reinitialize free oversize blocks. */ 931 (void) mutex_lock(&oversize_lock); 932 if (debugopt & MTDEBUGPATTERN) 933 for (; wp != &oversize_list; wp = wp->next_bysize) 934 copy_pattern(FREEPATTERN, wp->addr, wp->size); 935 (void) mutex_unlock(&oversize_lock); 936 937 /* Reinitialize free blocks. */ 938 for (cpuptr = &cpu_list[0]; cpuptr < &cpu_list[ncpus]; cpuptr++) { 939 (void) mutex_lock(&cpuptr->mt_parent_lock); 940 for (cachehead = &cpuptr->mt_caches[0]; cachehead < 941 &cpuptr->mt_caches[NUM_CACHES]; cachehead++) { 942 for (thiscache = cachehead->mt_cache; thiscache != NULL; 943 thiscache = thiscache->mt_next) { 944 (void) mutex_lock(&thiscache->mt_cache_lock); 945 if (thiscache->mt_nfree == 0) { 946 (void) mutex_unlock( 947 &thiscache->mt_cache_lock); 948 continue; 949 } 950 if (thiscache != NULL) 951 reinit_cache(thiscache); 952 (void) mutex_unlock(&thiscache->mt_cache_lock); 953 } 954 } 955 (void) mutex_unlock(&cpuptr->mt_parent_lock); 956 } 957 reinit = 0; 958 } 959 960 static void 961 reinit_cache(cache_t *thiscache) 962 { 963 uint32_t *freeblocks; /* not a uintptr_t on purpose */ 964 int32_t i, n; 965 caddr_t ret; 966 967 freeblocks = (uint32_t *)thiscache->mt_freelist; 968 while (freeblocks < (uint32_t *)thiscache->mt_arena) { 969 if (*freeblocks & 0xffffffff) { 970 for (i = 0; i < 32; i++) { 971 if (FLIP_EM(*freeblocks) & (0x80000000 >> i)) { 972 n = (uintptr_t)(((freeblocks - 973 (uint32_t *)thiscache->mt_freelist) << 5) 974 + i) * thiscache->mt_size; 975 ret = thiscache->mt_arena + n; 976 ret += OVERHEAD; 977 copy_pattern(FREEPATTERN, ret, 978 thiscache->mt_size); 979 } 980 } 981 } 982 freeblocks++; 983 } 984 } 985 986 static void * 987 malloc_internal(size_t size, percpu_t *cpuptr) 988 { 989 cache_head_t *cachehead; 990 cache_t *thiscache, *hintcache; 991 int32_t i, n, logsz, bucket; 992 uint32_t index; 993 uint32_t *freeblocks; /* not a uintptr_t on purpose */ 994 caddr_t ret; 995 996 logsz = MIN_CACHED_SHIFT; 997 998 while (size > (1 << logsz)) 999 logsz++; 1000 1001 bucket = logsz - MIN_CACHED_SHIFT; 1002 1003 (void) mutex_lock(&cpuptr->mt_parent_lock); 1004 1005 /* 1006 * Find a cache of the appropriate size with free buffers. 1007 * 1008 * We don't need to lock each cache as we check their mt_nfree count, 1009 * since: 1010 * 1. We are only looking for caches with mt_nfree > 0. If a 1011 * free happens during our search, it will increment mt_nfree, 1012 * which will not effect the test. 1013 * 2. Allocations can decrement mt_nfree, but they can't happen 1014 * as long as we hold mt_parent_lock. 1015 */ 1016 1017 cachehead = &cpuptr->mt_caches[bucket]; 1018 1019 /* Search through the list, starting at the mt_hint */ 1020 thiscache = cachehead->mt_hint; 1021 1022 while (thiscache != NULL && thiscache->mt_nfree == 0) 1023 thiscache = thiscache->mt_next; 1024 1025 if (thiscache == NULL) { 1026 /* wrap around -- search up to the hint */ 1027 thiscache = cachehead->mt_cache; 1028 hintcache = cachehead->mt_hint; 1029 1030 while (thiscache != NULL && thiscache != hintcache && 1031 thiscache->mt_nfree == 0) 1032 thiscache = thiscache->mt_next; 1033 1034 if (thiscache == hintcache) 1035 thiscache = NULL; 1036 } 1037 1038 1039 if (thiscache == NULL) { /* there are no free caches */ 1040 int32_t thisrequest = requestsize; 1041 int32_t buffer_size = (1 << logsz) + OVERHEAD; 1042 1043 thiscache = (cache_t *)morecore(thisrequest * HUNKSIZE); 1044 1045 if (thiscache == (cache_t *)-1) { 1046 (void) mutex_unlock(&cpuptr->mt_parent_lock); 1047 errno = EAGAIN; 1048 return (NULL); 1049 } 1050 create_cache(thiscache, buffer_size, thisrequest); 1051 1052 /* link in the new block at the beginning of the list */ 1053 thiscache->mt_next = cachehead->mt_cache; 1054 cachehead->mt_cache = thiscache; 1055 } 1056 1057 /* update the hint to the cache we found or created */ 1058 cachehead->mt_hint = thiscache; 1059 1060 /* thiscache now points to a cache with available space */ 1061 (void) mutex_lock(&thiscache->mt_cache_lock); 1062 1063 freeblocks = (uint32_t *)thiscache->mt_freelist; 1064 while (freeblocks < (uint32_t *)thiscache->mt_arena) { 1065 if (*freeblocks & 0xffffffff) 1066 break; 1067 freeblocks++; 1068 if (freeblocks < (uint32_t *)thiscache->mt_arena && 1069 *freeblocks & 0xffffffff) 1070 break; 1071 freeblocks++; 1072 if (freeblocks < (uint32_t *)thiscache->mt_arena && 1073 *freeblocks & 0xffffffff) 1074 break; 1075 freeblocks++; 1076 if (freeblocks < (uint32_t *)thiscache->mt_arena && 1077 *freeblocks & 0xffffffff) 1078 break; 1079 freeblocks++; 1080 } 1081 1082 /* 1083 * the offset from mt_freelist to freeblocks is the offset into 1084 * the arena. Be sure to include the offset into freeblocks 1085 * of the bitmask. n is the offset. 1086 */ 1087 for (i = 0; i < 32; ) { 1088 if (FLIP_EM(*freeblocks) & (0x80000000 >> i++)) 1089 break; 1090 if (FLIP_EM(*freeblocks) & (0x80000000 >> i++)) 1091 break; 1092 if (FLIP_EM(*freeblocks) & (0x80000000 >> i++)) 1093 break; 1094 if (FLIP_EM(*freeblocks) & (0x80000000 >> i++)) 1095 break; 1096 } 1097 index = 0x80000000 >> --i; 1098 1099 1100 *freeblocks &= FLIP_EM(~index); 1101 1102 thiscache->mt_nfree--; 1103 1104 (void) mutex_unlock(&thiscache->mt_cache_lock); 1105 (void) mutex_unlock(&cpuptr->mt_parent_lock); 1106 1107 n = (uintptr_t)(((freeblocks - (uint32_t *)thiscache->mt_freelist) << 5) 1108 + i) * thiscache->mt_size; 1109 /* 1110 * Now you have the offset in n, you've changed the free mask 1111 * in the freelist. Nothing left to do but find the block 1112 * in the arena and put the value of thiscache in the word 1113 * ahead of the handed out address and return the memory 1114 * back to the user. 1115 */ 1116 ret = thiscache->mt_arena + n; 1117 1118 /* Store the cache addr for this buf. Makes free go fast. */ 1119 *(uintptr_t *)ret = (uintptr_t)thiscache; 1120 1121 /* 1122 * This assert makes sure we don't hand out memory that is not 1123 * owned by this cache. 1124 */ 1125 assert(ret + thiscache->mt_size <= thiscache->mt_freelist + 1126 thiscache->mt_span); 1127 1128 ret += OVERHEAD; 1129 1130 assert(((uintptr_t)ret & 7) == 0); /* are we 8 byte aligned */ 1131 1132 if (reinit == 0 && (debugopt & MTDEBUGPATTERN)) 1133 if (verify_pattern(FREEPATTERN, ret, size)) 1134 abort(); /* reference after free */ 1135 1136 if (debugopt & MTINITBUFFER) 1137 copy_pattern(INITPATTERN, ret, size); 1138 return ((void *)ret); 1139 } 1140 1141 static void * 1142 morecore(size_t bytes) 1143 { 1144 void * ret; 1145 1146 if (bytes > LONG_MAX) { 1147 intptr_t wad; 1148 /* 1149 * The request size is too big. We need to do this in 1150 * chunks. Sbrk only takes an int for an arg. 1151 */ 1152 if (bytes == ULONG_MAX) 1153 return ((void *)-1); 1154 1155 ret = sbrk(0); 1156 wad = LONG_MAX; 1157 while (wad > 0) { 1158 if (sbrk(wad) == (void *)-1) { 1159 if (ret != sbrk(0)) 1160 (void) sbrk(-LONG_MAX); 1161 return ((void *)-1); 1162 } 1163 bytes -= LONG_MAX; 1164 wad = bytes; 1165 } 1166 } else 1167 ret = sbrk(bytes); 1168 1169 return (ret); 1170 } 1171 1172 1173 static void * 1174 oversize(size_t size) 1175 { 1176 caddr_t ret; 1177 oversize_t *big; 1178 1179 /* make sure we will not overflow */ 1180 if (size > MAX_MTMALLOC) { 1181 errno = ENOMEM; 1182 return (NULL); 1183 } 1184 1185 /* 1186 * Since we ensure every address we hand back is 1187 * MTMALLOC_MIN_ALIGN-byte aligned, ALIGNing size ensures that the 1188 * memory handed out is MTMALLOC_MIN_ALIGN-byte aligned at both ends. 1189 * This eases the implementation of MTDEBUGPATTERN and MTINITPATTERN, 1190 * particularly where coalescing occurs. 1191 */ 1192 size = ALIGN(size, MTMALLOC_MIN_ALIGN); 1193 1194 /* 1195 * The idea with the global lock is that we are sure to 1196 * block in the kernel anyway since given an oversize alloc 1197 * we are sure to have to call morecore(); 1198 */ 1199 (void) mutex_lock(&oversize_lock); 1200 1201 if ((big = find_oversize(size)) != NULL) { 1202 if (reinit == 0 && (debugopt & MTDEBUGPATTERN)) 1203 if (verify_pattern(FREEPATTERN, big->addr, size)) 1204 abort(); /* reference after free */ 1205 } else { 1206 /* Get more 8-byte aligned memory from heap */ 1207 ret = morecore(size + OVSZ_HEADER_SIZE); 1208 if (ret == (caddr_t)-1) { 1209 (void) mutex_unlock(&oversize_lock); 1210 errno = ENOMEM; 1211 return (NULL); 1212 } 1213 big = oversize_header_alloc((uintptr_t)ret, size); 1214 } 1215 ret = big->addr; 1216 1217 insert_hash(big); 1218 1219 if (debugopt & MTINITBUFFER) 1220 copy_pattern(INITPATTERN, ret, size); 1221 1222 (void) mutex_unlock(&oversize_lock); 1223 assert(((uintptr_t)ret & 7) == 0); /* are we 8 byte aligned */ 1224 return ((void *)ret); 1225 } 1226 1227 static void 1228 insert_oversize(oversize_t *op, oversize_t *nx) 1229 { 1230 oversize_t *sp; 1231 1232 /* locate correct insertion point in size-ordered list */ 1233 for (sp = oversize_list.next_bysize; 1234 sp != &oversize_list && (op->size > sp->size); 1235 sp = sp->next_bysize) 1236 ; 1237 1238 /* link into size-ordered list */ 1239 op->next_bysize = sp; 1240 op->prev_bysize = sp->prev_bysize; 1241 op->prev_bysize->next_bysize = op; 1242 op->next_bysize->prev_bysize = op; 1243 1244 /* 1245 * link item into address-ordered list 1246 * (caller provides insertion point as an optimization) 1247 */ 1248 op->next_byaddr = nx; 1249 op->prev_byaddr = nx->prev_byaddr; 1250 op->prev_byaddr->next_byaddr = op; 1251 op->next_byaddr->prev_byaddr = op; 1252 1253 } 1254 1255 static void 1256 unlink_oversize(oversize_t *lp) 1257 { 1258 /* unlink from address list */ 1259 lp->prev_byaddr->next_byaddr = lp->next_byaddr; 1260 lp->next_byaddr->prev_byaddr = lp->prev_byaddr; 1261 1262 /* unlink from size list */ 1263 lp->prev_bysize->next_bysize = lp->next_bysize; 1264 lp->next_bysize->prev_bysize = lp->prev_bysize; 1265 } 1266 1267 static void 1268 position_oversize_by_size(oversize_t *op) 1269 { 1270 oversize_t *sp; 1271 1272 if (op->size > op->next_bysize->size || 1273 op->size < op->prev_bysize->size) { 1274 1275 /* unlink from size list */ 1276 op->prev_bysize->next_bysize = op->next_bysize; 1277 op->next_bysize->prev_bysize = op->prev_bysize; 1278 1279 /* locate correct insertion point in size-ordered list */ 1280 for (sp = oversize_list.next_bysize; 1281 sp != &oversize_list && (op->size > sp->size); 1282 sp = sp->next_bysize) 1283 ; 1284 1285 /* link into size-ordered list */ 1286 op->next_bysize = sp; 1287 op->prev_bysize = sp->prev_bysize; 1288 op->prev_bysize->next_bysize = op; 1289 op->next_bysize->prev_bysize = op; 1290 } 1291 } 1292 1293 static void 1294 add_oversize(oversize_t *lp) 1295 { 1296 int merge_flags = INSERT_ONLY; 1297 oversize_t *nx; /* ptr to item right of insertion point */ 1298 oversize_t *pv; /* ptr to item left of insertion point */ 1299 uint_t size_lp, size_pv, size_nx; 1300 uintptr_t endp_lp, endp_pv, endp_nx; 1301 1302 /* 1303 * Locate insertion point in address-ordered list 1304 */ 1305 1306 for (nx = oversize_list.next_byaddr; 1307 nx != &oversize_list && (lp->addr > nx->addr); 1308 nx = nx->next_byaddr) 1309 ; 1310 1311 /* 1312 * Determine how to add chunk to oversize freelist 1313 */ 1314 1315 size_lp = OVSZ_HEADER_SIZE + lp->size; 1316 endp_lp = ALIGN((uintptr_t)lp + size_lp, MTMALLOC_MIN_ALIGN); 1317 size_lp = endp_lp - (uintptr_t)lp; 1318 1319 pv = nx->prev_byaddr; 1320 1321 if (pv->size) { 1322 1323 size_pv = OVSZ_HEADER_SIZE + pv->size; 1324 endp_pv = ALIGN((uintptr_t)pv + size_pv, 1325 MTMALLOC_MIN_ALIGN); 1326 size_pv = endp_pv - (uintptr_t)pv; 1327 1328 /* Check for adjacency with left chunk */ 1329 if ((uintptr_t)lp == endp_pv) 1330 merge_flags |= COALESCE_LEFT; 1331 } 1332 1333 if (nx->size) { 1334 1335 /* Check for adjacency with right chunk */ 1336 if ((uintptr_t)nx == endp_lp) { 1337 size_nx = OVSZ_HEADER_SIZE + nx->size; 1338 endp_nx = ALIGN((uintptr_t)nx + size_nx, 1339 MTMALLOC_MIN_ALIGN); 1340 size_nx = endp_nx - (uintptr_t)nx; 1341 merge_flags |= COALESCE_RIGHT; 1342 } 1343 } 1344 1345 /* 1346 * If MTDEBUGPATTERN==1, lp->addr will have been overwritten with 1347 * FREEPATTERN for lp->size bytes. If we can merge, the oversize 1348 * header(s) that will also become part of the memory available for 1349 * reallocation (ie lp and/or nx) must also be overwritten with 1350 * FREEPATTERN or we will SIGABRT when this memory is next reallocated. 1351 */ 1352 switch (merge_flags) { 1353 1354 case INSERT_ONLY: /* Coalescing not possible */ 1355 insert_oversize(lp, nx); 1356 break; 1357 case COALESCE_LEFT: 1358 pv->size += size_lp; 1359 position_oversize_by_size(pv); 1360 if (debugopt & MTDEBUGPATTERN) 1361 copy_pattern(FREEPATTERN, lp, OVSZ_HEADER_SIZE); 1362 break; 1363 case COALESCE_RIGHT: 1364 unlink_oversize(nx); 1365 lp->size += size_nx; 1366 insert_oversize(lp, pv->next_byaddr); 1367 if (debugopt & MTDEBUGPATTERN) 1368 copy_pattern(FREEPATTERN, nx, OVSZ_HEADER_SIZE); 1369 break; 1370 case COALESCE_WITH_BOTH_SIDES: /* Merge (with right) to the left */ 1371 pv->size += size_lp + size_nx; 1372 unlink_oversize(nx); 1373 position_oversize_by_size(pv); 1374 if (debugopt & MTDEBUGPATTERN) { 1375 copy_pattern(FREEPATTERN, lp, OVSZ_HEADER_SIZE); 1376 copy_pattern(FREEPATTERN, nx, OVSZ_HEADER_SIZE); 1377 } 1378 break; 1379 } 1380 } 1381 1382 /* 1383 * Find memory on our list that is at least size big. If we find a block that is 1384 * big enough, we break it up and return the associated oversize_t struct back 1385 * to the calling client. Any leftover piece of that block is returned to the 1386 * freelist. 1387 */ 1388 static oversize_t * 1389 find_oversize(size_t size) 1390 { 1391 oversize_t *wp = oversize_list.next_bysize; 1392 while (wp != &oversize_list && size > wp->size) 1393 wp = wp->next_bysize; 1394 1395 if (wp == &oversize_list) /* empty list or nothing big enough */ 1396 return (NULL); 1397 /* breaking up a chunk of memory */ 1398 if ((long)((wp->size - (size + OVSZ_HEADER_SIZE + MTMALLOC_MIN_ALIGN))) 1399 > MAX_CACHED) { 1400 caddr_t off; 1401 oversize_t *np; 1402 size_t osize; 1403 off = (caddr_t)ALIGN(wp->addr + size, 1404 MTMALLOC_MIN_ALIGN); 1405 osize = wp->size; 1406 wp->size = (size_t)(off - wp->addr); 1407 np = oversize_header_alloc((uintptr_t)off, 1408 osize - (wp->size + OVSZ_HEADER_SIZE)); 1409 if ((long)np->size < 0) 1410 abort(); 1411 unlink_oversize(wp); 1412 add_oversize(np); 1413 } else { 1414 unlink_oversize(wp); 1415 } 1416 return (wp); 1417 } 1418 1419 static void 1420 copy_pattern(uint32_t pattern, void *buf_arg, size_t size) 1421 { 1422 uint32_t *bufend = (uint32_t *)((char *)buf_arg + size); 1423 uint32_t *buf = buf_arg; 1424 1425 while (buf < bufend - 3) { 1426 buf[3] = buf[2] = buf[1] = buf[0] = pattern; 1427 buf += 4; 1428 } 1429 while (buf < bufend) 1430 *buf++ = pattern; 1431 } 1432 1433 static void * 1434 verify_pattern(uint32_t pattern, void *buf_arg, size_t size) 1435 { 1436 uint32_t *bufend = (uint32_t *)((char *)buf_arg + size); 1437 uint32_t *buf; 1438 1439 for (buf = buf_arg; buf < bufend; buf++) 1440 if (*buf != pattern) 1441 return (buf); 1442 return (NULL); 1443 } 1444 1445 static void 1446 free_oversize(oversize_t *ovp) 1447 { 1448 assert(((uintptr_t)ovp->addr & 7) == 0); /* are we 8 byte aligned */ 1449 assert(ovp->size > MAX_CACHED); 1450 1451 ovp->next_bysize = ovp->prev_bysize = NULL; 1452 ovp->next_byaddr = ovp->prev_byaddr = NULL; 1453 (void) mutex_lock(&oversize_lock); 1454 add_oversize(ovp); 1455 (void) mutex_unlock(&oversize_lock); 1456 } 1457 1458 static oversize_t * 1459 oversize_header_alloc(uintptr_t mem, size_t size) 1460 { 1461 oversize_t *ovsz_hdr; 1462 1463 assert(size > MAX_CACHED); 1464 1465 ovsz_hdr = (oversize_t *)mem; 1466 ovsz_hdr->prev_bysize = NULL; 1467 ovsz_hdr->next_bysize = NULL; 1468 ovsz_hdr->prev_byaddr = NULL; 1469 ovsz_hdr->next_byaddr = NULL; 1470 ovsz_hdr->hash_next = NULL; 1471 ovsz_hdr->size = size; 1472 mem += OVSZ_SIZE; 1473 *(uintptr_t *)mem = MTMALLOC_OVERSIZE_MAGIC; 1474 mem += OVERHEAD; 1475 assert(((uintptr_t)mem & 7) == 0); /* are we 8 byte aligned */ 1476 ovsz_hdr->addr = (caddr_t)mem; 1477 return (ovsz_hdr); 1478 } 1479 1480 static void 1481 malloc_prepare() 1482 { 1483 percpu_t *cpuptr; 1484 cache_head_t *cachehead; 1485 cache_t *thiscache; 1486 1487 (void) mutex_lock(&oversize_lock); 1488 for (cpuptr = &cpu_list[0]; cpuptr < &cpu_list[ncpus]; cpuptr++) { 1489 (void) mutex_lock(&cpuptr->mt_parent_lock); 1490 for (cachehead = &cpuptr->mt_caches[0]; 1491 cachehead < &cpuptr->mt_caches[NUM_CACHES]; 1492 cachehead++) { 1493 for (thiscache = cachehead->mt_cache; 1494 thiscache != NULL; 1495 thiscache = thiscache->mt_next) { 1496 (void) mutex_lock( 1497 &thiscache->mt_cache_lock); 1498 } 1499 } 1500 } 1501 } 1502 1503 static void 1504 malloc_release() 1505 { 1506 percpu_t *cpuptr; 1507 cache_head_t *cachehead; 1508 cache_t *thiscache; 1509 1510 for (cpuptr = &cpu_list[ncpus - 1]; cpuptr >= &cpu_list[0]; cpuptr--) { 1511 for (cachehead = &cpuptr->mt_caches[NUM_CACHES - 1]; 1512 cachehead >= &cpuptr->mt_caches[0]; 1513 cachehead--) { 1514 for (thiscache = cachehead->mt_cache; 1515 thiscache != NULL; 1516 thiscache = thiscache->mt_next) { 1517 (void) mutex_unlock( 1518 &thiscache->mt_cache_lock); 1519 } 1520 } 1521 (void) mutex_unlock(&cpuptr->mt_parent_lock); 1522 } 1523 (void) mutex_unlock(&oversize_lock); 1524 } 1525 1526 #pragma init(malloc_init) 1527 static void 1528 malloc_init(void) 1529 { 1530 /* 1531 * This works in the init section for this library 1532 * because setup_caches() doesn't call anything in libc 1533 * that calls malloc(). If it did, disaster would ensue. 1534 * 1535 * For this to work properly, this library must be the first 1536 * one to have its init section called (after libc) by the 1537 * dynamic linker. If some other library's init section 1538 * ran first and called malloc(), disaster would ensue. 1539 * Because this is an interposer library for malloc(), the 1540 * dynamic linker arranges for its init section to run first. 1541 */ 1542 (void) setup_caches(); 1543 1544 (void) pthread_atfork(malloc_prepare, malloc_release, malloc_release); 1545 } 1546