1 /* $NetBSD: sl_malloc.c,v 1.1.1.6 2018/02/06 01:53:15 christos Exp $ */ 2 3 /* sl_malloc.c - malloc routines using a per-thread slab */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2017 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19 #include <sys/cdefs.h> 20 __RCSID("$NetBSD: sl_malloc.c,v 1.1.1.6 2018/02/06 01:53:15 christos Exp $"); 21 22 #include "portable.h" 23 24 #include <stdio.h> 25 #include <ac/string.h> 26 27 #include "slap.h" 28 29 #ifdef USE_VALGRIND 30 /* Get debugging help from Valgrind */ 31 #include <valgrind/memcheck.h> 32 #define VGMEMP_MARK(m,s) VALGRIND_MAKE_MEM_NOACCESS(m,s) 33 #define VGMEMP_CREATE(h,r,z) VALGRIND_CREATE_MEMPOOL(h,r,z) 34 #define VGMEMP_TRIM(h,a,s) VALGRIND_MEMPOOL_TRIM(h,a,s) 35 #define VGMEMP_ALLOC(h,a,s) VALGRIND_MEMPOOL_ALLOC(h,a,s) 36 #define VGMEMP_CHANGE(h,a,b,s) VALGRIND_MEMPOOL_CHANGE(h,a,b,s) 37 #else 38 #define VGMEMP_MARK(m,s) 39 #define VGMEMP_CREATE(h,r,z) 40 #define VGMEMP_TRIM(h,a,s) 41 #define VGMEMP_ALLOC(h,a,s) 42 #define VGMEMP_CHANGE(h,a,b,s) 43 #endif 44 45 /* 46 * This allocator returns temporary memory from a slab in a given memory 47 * context, aligned on a 2-int boundary. It cannot be used for data 48 * which will outlive the task allocating it. 49 * 50 * A new memory context attaches to the creator's thread context, if any. 51 * Threads cannot use other threads' memory contexts; there are no locks. 52 * 53 * The caller of slap_sl_malloc, usually a thread pool task, must 54 * slap_sl_free the memory before finishing: New tasks reuse the context 55 * and normally reset it, reclaiming memory left over from last task. 56 * 57 * The allocator helps memory fragmentation, speed and memory leaks. 58 * It is not (yet) reliable as a garbage collector: 59 * 60 * It falls back to context NULL - plain ber_memalloc() - when the 61 * context's slab is full. A reset does not reclaim such memory. 62 * Conversely, free/realloc of data not from the given context assumes 63 * context NULL. The data must not belong to another memory context. 64 * 65 * Code which has lost track of the current memory context can try 66 * slap_sl_context() or ch_malloc.c:ch_free/ch_realloc(). 67 * 68 * Allocations cannot yet return failure. Like ch_malloc, they succeed 69 * or abort slapd. This will change, do fix code which assumes success. 70 */ 71 72 /* 73 * The stack-based allocator stores (ber_len_t)sizeof(head+block) at 74 * allocated blocks' head - and in freed blocks also at the tail, marked 75 * by ORing *next* block's head with 1. Freed blocks are only reclaimed 76 * from the last block forward. This is fast, but when a block is never 77 * freed, older blocks will not be reclaimed until the slab is reset... 78 */ 79 80 #ifdef SLAP_NO_SL_MALLOC /* Useful with memory debuggers like Valgrind */ 81 enum { No_sl_malloc = 1 }; 82 #else 83 enum { No_sl_malloc = 0 }; 84 #endif 85 86 #define SLAP_SLAB_SOBLOCK 64 87 88 struct slab_object { 89 void *so_ptr; 90 int so_blockhead; 91 LDAP_LIST_ENTRY(slab_object) so_link; 92 }; 93 94 struct slab_heap { 95 void *sh_base; 96 void *sh_last; 97 void *sh_end; 98 int sh_stack; 99 int sh_maxorder; 100 unsigned char **sh_map; 101 LDAP_LIST_HEAD(sh_freelist, slab_object) *sh_free; 102 LDAP_LIST_HEAD(sh_so, slab_object) sh_sopool; 103 }; 104 105 enum { 106 Align = sizeof(ber_len_t) > 2*sizeof(int) 107 ? sizeof(ber_len_t) : 2*sizeof(int), 108 Align_log2 = 1 + (Align>2) + (Align>4) + (Align>8) + (Align>16), 109 order_start = Align_log2 - 1, 110 pad = Align - 1 111 }; 112 113 static struct slab_object * slap_replenish_sopool(struct slab_heap* sh); 114 #ifdef SLAPD_UNUSED 115 static void print_slheap(int level, void *ctx); 116 #endif 117 118 /* Keep memory context in a thread-local var, or in a global when no threads */ 119 #ifdef NO_THREADS 120 static struct slab_heap *slheap; 121 # define SET_MEMCTX(thrctx, memctx, sfree) ((void) (slheap = (memctx))) 122 # define GET_MEMCTX(thrctx, memctxp) (*(memctxp) = slheap) 123 #else 124 # define memctx_key ((void *) slap_sl_mem_init) 125 # define SET_MEMCTX(thrctx, memctx, kfree) \ 126 ldap_pvt_thread_pool_setkey(thrctx,memctx_key, memctx,kfree, NULL,NULL) 127 # define GET_MEMCTX(thrctx, memctxp) \ 128 ((void) (*(memctxp) = NULL), \ 129 (void) ldap_pvt_thread_pool_getkey(thrctx,memctx_key, memctxp,NULL), \ 130 *(memctxp)) 131 #endif /* NO_THREADS */ 132 133 134 /* Destroy the context, or if key==NULL clean it up for reuse. */ 135 void 136 slap_sl_mem_destroy( 137 void *key, 138 void *data 139 ) 140 { 141 struct slab_heap *sh = data; 142 struct slab_object *so; 143 int i; 144 145 if (!sh->sh_stack) { 146 for (i = 0; i <= sh->sh_maxorder - order_start; i++) { 147 so = LDAP_LIST_FIRST(&sh->sh_free[i]); 148 while (so) { 149 struct slab_object *so_tmp = so; 150 so = LDAP_LIST_NEXT(so, so_link); 151 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link); 152 } 153 ch_free(sh->sh_map[i]); 154 } 155 ch_free(sh->sh_free); 156 ch_free(sh->sh_map); 157 158 so = LDAP_LIST_FIRST(&sh->sh_sopool); 159 while (so) { 160 struct slab_object *so_tmp = so; 161 so = LDAP_LIST_NEXT(so, so_link); 162 if (!so_tmp->so_blockhead) { 163 LDAP_LIST_REMOVE(so_tmp, so_link); 164 } 165 } 166 so = LDAP_LIST_FIRST(&sh->sh_sopool); 167 while (so) { 168 struct slab_object *so_tmp = so; 169 so = LDAP_LIST_NEXT(so, so_link); 170 ch_free(so_tmp); 171 } 172 } 173 174 if (key != NULL) { 175 ber_memfree_x(sh->sh_base, NULL); 176 ber_memfree_x(sh, NULL); 177 } 178 } 179 180 BerMemoryFunctions slap_sl_mfuncs = 181 { slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free }; 182 183 void 184 slap_sl_mem_init() 185 { 186 assert( Align == 1 << Align_log2 ); 187 188 ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs ); 189 } 190 191 /* Create, reset or just return the memory context of the current thread. */ 192 void * 193 slap_sl_mem_create( 194 ber_len_t size, 195 int stack, 196 void *thrctx, 197 int new 198 ) 199 { 200 void *memctx; 201 struct slab_heap *sh; 202 ber_len_t size_shift; 203 struct slab_object *so; 204 char *base, *newptr; 205 enum { Base_offset = (unsigned) -sizeof(ber_len_t) % Align }; 206 207 sh = GET_MEMCTX(thrctx, &memctx); 208 if ( sh && !new ) 209 return sh; 210 211 /* Round up to doubleword boundary, then make room for initial 212 * padding, preserving expected available size for pool version */ 213 size = ((size + Align-1) & -Align) + Base_offset; 214 215 if (!sh) { 216 sh = ch_malloc(sizeof(struct slab_heap)); 217 base = ch_malloc(size); 218 SET_MEMCTX(thrctx, sh, slap_sl_mem_destroy); 219 VGMEMP_MARK(base, size); 220 VGMEMP_CREATE(sh, 0, 0); 221 } else { 222 slap_sl_mem_destroy(NULL, sh); 223 base = sh->sh_base; 224 if (size > (ber_len_t) ((char *) sh->sh_end - base)) { 225 newptr = ch_realloc(base, size); 226 if ( newptr == NULL ) return NULL; 227 VGMEMP_CHANGE(sh, base, newptr, size); 228 base = newptr; 229 } 230 VGMEMP_TRIM(sh, base, 0); 231 } 232 sh->sh_base = base; 233 sh->sh_end = base + size; 234 235 /* Align (base + head of first block) == first returned block */ 236 base += Base_offset; 237 size -= Base_offset; 238 239 sh->sh_stack = stack; 240 if (stack) { 241 sh->sh_last = base; 242 243 } else { 244 int i, order = -1, order_end = -1; 245 246 size_shift = size - 1; 247 do { 248 order_end++; 249 } while (size_shift >>= 1); 250 order = order_end - order_start + 1; 251 sh->sh_maxorder = order_end; 252 253 sh->sh_free = (struct sh_freelist *) 254 ch_malloc(order * sizeof(struct sh_freelist)); 255 for (i = 0; i < order; i++) { 256 LDAP_LIST_INIT(&sh->sh_free[i]); 257 } 258 259 LDAP_LIST_INIT(&sh->sh_sopool); 260 261 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 262 slap_replenish_sopool(sh); 263 } 264 so = LDAP_LIST_FIRST(&sh->sh_sopool); 265 LDAP_LIST_REMOVE(so, so_link); 266 so->so_ptr = base; 267 268 LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link); 269 270 sh->sh_map = (unsigned char **) 271 ch_malloc(order * sizeof(unsigned char *)); 272 for (i = 0; i < order; i++) { 273 int shiftamt = order_start + 1 + i; 274 int nummaps = size >> shiftamt; 275 assert(nummaps); 276 nummaps >>= 3; 277 if (!nummaps) nummaps = 1; 278 sh->sh_map[i] = (unsigned char *) ch_malloc(nummaps); 279 memset(sh->sh_map[i], 0, nummaps); 280 } 281 } 282 283 return sh; 284 } 285 286 /* 287 * Assign memory context to thread context. Use NULL to detach 288 * current memory context from thread. Future users must 289 * know the context, since ch_free/slap_sl_context() cannot find it. 290 */ 291 void 292 slap_sl_mem_setctx( 293 void *thrctx, 294 void *memctx 295 ) 296 { 297 SET_MEMCTX(thrctx, memctx, slap_sl_mem_destroy); 298 } 299 300 void * 301 slap_sl_malloc( 302 ber_len_t size, 303 void *ctx 304 ) 305 { 306 struct slab_heap *sh = ctx; 307 ber_len_t *ptr, *newptr; 308 309 /* ber_set_option calls us like this */ 310 if (No_sl_malloc || !ctx) { 311 newptr = ber_memalloc_x( size, NULL ); 312 if ( newptr ) return newptr; 313 Debug(LDAP_DEBUG_ANY, "slap_sl_malloc of %lu bytes failed\n", 314 (unsigned long) size, 0, 0); 315 assert( 0 ); 316 exit( EXIT_FAILURE ); 317 } 318 319 /* Add room for head, ensure room for tail when freed, and 320 * round up to doubleword boundary. */ 321 size = (size + sizeof(ber_len_t) + Align-1 + !size) & -Align; 322 323 if (sh->sh_stack) { 324 if (size < (ber_len_t) ((char *) sh->sh_end - (char *) sh->sh_last)) { 325 newptr = sh->sh_last; 326 sh->sh_last = (char *) sh->sh_last + size; 327 VGMEMP_ALLOC(sh, newptr, size); 328 *newptr++ = size; 329 return( (void *)newptr ); 330 } 331 332 size -= sizeof(ber_len_t); 333 334 } else { 335 struct slab_object *so_new, *so_left, *so_right; 336 ber_len_t size_shift; 337 unsigned long diff; 338 int i, j, order = -1; 339 340 size_shift = size - 1; 341 do { 342 order++; 343 } while (size_shift >>= 1); 344 345 size -= sizeof(ber_len_t); 346 347 for (i = order; i <= sh->sh_maxorder && 348 LDAP_LIST_EMPTY(&sh->sh_free[i-order_start]); i++); 349 350 if (i == order) { 351 so_new = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 352 LDAP_LIST_REMOVE(so_new, so_link); 353 ptr = so_new->so_ptr; 354 diff = (unsigned long)((char*)ptr - 355 (char*)sh->sh_base) >> (order + 1); 356 sh->sh_map[order-order_start][diff>>3] |= (1 << (diff & 0x7)); 357 *ptr++ = size; 358 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_new, so_link); 359 return((void*)ptr); 360 } else if (i <= sh->sh_maxorder) { 361 for (j = i; j > order; j--) { 362 so_left = LDAP_LIST_FIRST(&sh->sh_free[j-order_start]); 363 LDAP_LIST_REMOVE(so_left, so_link); 364 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 365 slap_replenish_sopool(sh); 366 } 367 so_right = LDAP_LIST_FIRST(&sh->sh_sopool); 368 LDAP_LIST_REMOVE(so_right, so_link); 369 so_right->so_ptr = (void *)((char *)so_left->so_ptr + (1 << j)); 370 if (j == order + 1) { 371 ptr = so_left->so_ptr; 372 diff = (unsigned long)((char*)ptr - 373 (char*)sh->sh_base) >> (order+1); 374 sh->sh_map[order-order_start][diff>>3] |= 375 (1 << (diff & 0x7)); 376 *ptr++ = size; 377 LDAP_LIST_INSERT_HEAD( 378 &sh->sh_free[j-1-order_start], so_right, so_link); 379 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_left, so_link); 380 return((void*)ptr); 381 } else { 382 LDAP_LIST_INSERT_HEAD( 383 &sh->sh_free[j-1-order_start], so_right, so_link); 384 LDAP_LIST_INSERT_HEAD( 385 &sh->sh_free[j-1-order_start], so_left, so_link); 386 } 387 } 388 } 389 /* FIXME: missing return; guessing we failed... */ 390 } 391 392 Debug(LDAP_DEBUG_TRACE, 393 "sl_malloc %lu: ch_malloc\n", 394 (unsigned long) size, 0, 0); 395 return ch_malloc(size); 396 } 397 398 #define LIM_SQRT(t) /* some value < sqrt(max value of unsigned type t) */ \ 399 ((0UL|(t)-1) >>31>>31 > 1 ? ((t)1 <<32) - 1 : \ 400 (0UL|(t)-1) >>31 ? 65535U : (0UL|(t)-1) >>15 ? 255U : 15U) 401 402 void * 403 slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx ) 404 { 405 void *newptr; 406 ber_len_t total = n * size; 407 408 /* The sqrt test is a slight optimization: often avoids the division */ 409 if ((n | size) <= LIM_SQRT(ber_len_t) || n == 0 || total/n == size) { 410 newptr = slap_sl_malloc( total, ctx ); 411 memset( newptr, 0, n*size ); 412 } else { 413 Debug(LDAP_DEBUG_ANY, "slap_sl_calloc(%lu,%lu) out of range\n", 414 (unsigned long) n, (unsigned long) size, 0); 415 assert(0); 416 exit(EXIT_FAILURE); 417 } 418 return newptr; 419 } 420 421 void * 422 slap_sl_realloc(void *ptr, ber_len_t size, void *ctx) 423 { 424 struct slab_heap *sh = ctx; 425 ber_len_t oldsize, *p = (ber_len_t *) ptr, *nextp; 426 void *newptr; 427 428 if (ptr == NULL) 429 return slap_sl_malloc(size, ctx); 430 431 /* Not our memory? */ 432 if (No_sl_malloc || !sh || ptr < sh->sh_base || ptr >= sh->sh_end) { 433 /* Like ch_realloc(), except not trying a new context */ 434 newptr = ber_memrealloc_x(ptr, size, NULL); 435 if (newptr) { 436 return newptr; 437 } 438 Debug(LDAP_DEBUG_ANY, "slap_sl_realloc of %lu bytes failed\n", 439 (unsigned long) size, 0, 0); 440 assert(0); 441 exit( EXIT_FAILURE ); 442 } 443 444 if (size == 0) { 445 slap_sl_free(ptr, ctx); 446 return NULL; 447 } 448 449 oldsize = p[-1]; 450 451 if (sh->sh_stack) { 452 /* Add room for head, round up to doubleword boundary */ 453 size = (size + sizeof(ber_len_t) + Align-1) & -Align; 454 455 p--; 456 457 /* Never shrink blocks */ 458 if (size <= oldsize) { 459 return ptr; 460 } 461 462 oldsize &= -2; 463 nextp = (ber_len_t *) ((char *) p + oldsize); 464 465 /* If reallocing the last block, try to grow it */ 466 if (nextp == sh->sh_last) { 467 if (size < (ber_len_t) ((char *) sh->sh_end - (char *) p)) { 468 sh->sh_last = (char *) p + size; 469 p[0] = (p[0] & 1) | size; 470 return ptr; 471 } 472 473 /* Nowhere to grow, need to alloc and copy */ 474 } else { 475 /* Slight optimization of the final realloc variant */ 476 newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx); 477 AC_MEMCPY(newptr, ptr, oldsize-sizeof(ber_len_t)); 478 /* Not last block, can just mark old region as free */ 479 nextp[-1] = oldsize; 480 nextp[0] |= 1; 481 return newptr; 482 } 483 484 size -= sizeof(ber_len_t); 485 oldsize -= sizeof(ber_len_t); 486 487 } else if (oldsize > size) { 488 oldsize = size; 489 } 490 491 newptr = slap_sl_malloc(size, ctx); 492 AC_MEMCPY(newptr, ptr, oldsize); 493 slap_sl_free(ptr, ctx); 494 return newptr; 495 } 496 497 void 498 slap_sl_free(void *ptr, void *ctx) 499 { 500 struct slab_heap *sh = ctx; 501 ber_len_t size; 502 ber_len_t *p = ptr, *nextp, *tmpp; 503 504 if (!ptr) 505 return; 506 507 if (No_sl_malloc || !sh || ptr < sh->sh_base || ptr >= sh->sh_end) { 508 ber_memfree_x(ptr, NULL); 509 return; 510 } 511 512 size = *(--p); 513 514 if (sh->sh_stack) { 515 size &= -2; 516 nextp = (ber_len_t *) ((char *) p + size); 517 if (sh->sh_last != nextp) { 518 /* Mark it free: tail = size, head of next block |= 1 */ 519 nextp[-1] = size; 520 nextp[0] |= 1; 521 /* We can't tell Valgrind about it yet, because we 522 * still need read/write access to this block for 523 * when we eventually get to reclaim it. 524 */ 525 } else { 526 /* Reclaim freed block(s) off tail */ 527 while (*p & 1) { 528 p = (ber_len_t *) ((char *) p - p[-1]); 529 } 530 sh->sh_last = p; 531 VGMEMP_TRIM(sh, sh->sh_base, 532 (char *) sh->sh_last - (char *) sh->sh_base); 533 } 534 535 } else { 536 int size_shift, order_size; 537 struct slab_object *so; 538 unsigned long diff; 539 int i, inserted = 0, order = -1; 540 541 size_shift = size + sizeof(ber_len_t) - 1; 542 do { 543 order++; 544 } while (size_shift >>= 1); 545 546 for (i = order, tmpp = p; i <= sh->sh_maxorder; i++) { 547 order_size = 1 << (i+1); 548 diff = (unsigned long)((char*)tmpp - (char*)sh->sh_base) >> (i+1); 549 sh->sh_map[i-order_start][diff>>3] &= (~(1 << (diff & 0x7))); 550 if (diff == ((diff>>1)<<1)) { 551 if (!(sh->sh_map[i-order_start][(diff+1)>>3] & 552 (1<<((diff+1)&0x7)))) { 553 so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 554 while (so) { 555 if ((char*)so->so_ptr == (char*)tmpp) { 556 LDAP_LIST_REMOVE( so, so_link ); 557 } else if ((char*)so->so_ptr == 558 (char*)tmpp + order_size) { 559 LDAP_LIST_REMOVE(so, so_link); 560 break; 561 } 562 so = LDAP_LIST_NEXT(so, so_link); 563 } 564 if (so) { 565 if (i < sh->sh_maxorder) { 566 inserted = 1; 567 so->so_ptr = tmpp; 568 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1], 569 so, so_link); 570 } 571 continue; 572 } else { 573 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 574 slap_replenish_sopool(sh); 575 } 576 so = LDAP_LIST_FIRST(&sh->sh_sopool); 577 LDAP_LIST_REMOVE(so, so_link); 578 so->so_ptr = tmpp; 579 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 580 so, so_link); 581 break; 582 583 Debug(LDAP_DEBUG_TRACE, "slap_sl_free: " 584 "free object not found while bit is clear.\n", 585 0, 0, 0); 586 assert(so != NULL); 587 588 } 589 } else { 590 if (!inserted) { 591 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 592 slap_replenish_sopool(sh); 593 } 594 so = LDAP_LIST_FIRST(&sh->sh_sopool); 595 LDAP_LIST_REMOVE(so, so_link); 596 so->so_ptr = tmpp; 597 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 598 so, so_link); 599 } 600 break; 601 } 602 } else { 603 if (!(sh->sh_map[i-order_start][(diff-1)>>3] & 604 (1<<((diff-1)&0x7)))) { 605 so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 606 while (so) { 607 if ((char*)so->so_ptr == (char*)tmpp) { 608 LDAP_LIST_REMOVE(so, so_link); 609 } else if ((char*)tmpp == (char *)so->so_ptr + order_size) { 610 LDAP_LIST_REMOVE(so, so_link); 611 tmpp = so->so_ptr; 612 break; 613 } 614 so = LDAP_LIST_NEXT(so, so_link); 615 } 616 if (so) { 617 if (i < sh->sh_maxorder) { 618 inserted = 1; 619 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1], so, so_link); 620 continue; 621 } 622 } else { 623 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 624 slap_replenish_sopool(sh); 625 } 626 so = LDAP_LIST_FIRST(&sh->sh_sopool); 627 LDAP_LIST_REMOVE(so, so_link); 628 so->so_ptr = tmpp; 629 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 630 so, so_link); 631 break; 632 633 Debug(LDAP_DEBUG_TRACE, "slap_sl_free: " 634 "free object not found while bit is clear.\n", 635 0, 0, 0 ); 636 assert(so != NULL); 637 638 } 639 } else { 640 if ( !inserted ) { 641 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 642 slap_replenish_sopool(sh); 643 } 644 so = LDAP_LIST_FIRST(&sh->sh_sopool); 645 LDAP_LIST_REMOVE(so, so_link); 646 so->so_ptr = tmpp; 647 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 648 so, so_link); 649 } 650 break; 651 } 652 } 653 } 654 } 655 } 656 657 /* 658 * Return the memory context of the current thread if the given block of 659 * memory belongs to it, otherwise return NULL. 660 */ 661 void * 662 slap_sl_context( void *ptr ) 663 { 664 void *memctx; 665 struct slab_heap *sh; 666 667 if ( slapMode & SLAP_TOOL_MODE ) return NULL; 668 669 sh = GET_MEMCTX(ldap_pvt_thread_pool_context(), &memctx); 670 if (sh && ptr >= sh->sh_base && ptr <= sh->sh_end) { 671 return sh; 672 } 673 return NULL; 674 } 675 676 static struct slab_object * 677 slap_replenish_sopool( 678 struct slab_heap* sh 679 ) 680 { 681 struct slab_object *so_block; 682 int i; 683 684 so_block = (struct slab_object *)ch_malloc( 685 SLAP_SLAB_SOBLOCK * sizeof(struct slab_object)); 686 687 if ( so_block == NULL ) { 688 return NULL; 689 } 690 691 so_block[0].so_blockhead = 1; 692 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link); 693 for (i = 1; i < SLAP_SLAB_SOBLOCK; i++) { 694 so_block[i].so_blockhead = 0; 695 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[i], so_link ); 696 } 697 698 return so_block; 699 } 700 701 #ifdef SLAPD_UNUSED 702 static void 703 print_slheap(int level, void *ctx) 704 { 705 struct slab_heap *sh = ctx; 706 struct slab_object *so; 707 int i, j, once = 0; 708 709 if (!ctx) { 710 Debug(level, "NULL memctx\n", 0, 0, 0); 711 return; 712 } 713 714 Debug(level, "sh->sh_maxorder=%d\n", sh->sh_maxorder, 0, 0); 715 716 for (i = order_start; i <= sh->sh_maxorder; i++) { 717 once = 0; 718 Debug(level, "order=%d\n", i, 0, 0); 719 for (j = 0; j < (1<<(sh->sh_maxorder-i))/8; j++) { 720 Debug(level, "%02x ", sh->sh_map[i-order_start][j], 0, 0); 721 once = 1; 722 } 723 if (!once) { 724 Debug(level, "%02x ", sh->sh_map[i-order_start][0], 0, 0); 725 } 726 Debug(level, "\n", 0, 0, 0); 727 Debug(level, "free list:\n", 0, 0, 0); 728 so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 729 while (so) { 730 Debug(level, "%p\n", so->so_ptr, 0, 0); 731 so = LDAP_LIST_NEXT(so, so_link); 732 } 733 } 734 } 735 #endif 736