1/* $NetBSD: sl_malloc.c,v 1.3 2021/08/14 16:14:58 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-2021 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.3 2021/08/14 16:14:58 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 */ 81enum { No_sl_malloc = 1 }; 82#else 83enum { No_sl_malloc = 0 }; 84#endif 85 86#define SLAP_SLAB_SOBLOCK 64 87 88struct slab_object { 89 void *so_ptr; 90 int so_blockhead; 91 LDAP_LIST_ENTRY(slab_object) so_link; 92}; 93 94struct 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 105enum { 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 113static struct slab_object * slap_replenish_sopool(struct slab_heap* sh); 114#ifdef SLAPD_UNUSED 115static void print_slheap(int level, void *ctx); 116#endif 117 118/* Keep memory context in a thread-local var */ 119# define memctx_key ((void *) slap_sl_mem_init) 120# define SET_MEMCTX(thrctx, memctx, kfree) \ 121 ldap_pvt_thread_pool_setkey(thrctx,memctx_key, memctx,kfree, NULL,NULL) 122# define GET_MEMCTX(thrctx, memctxp) \ 123 ((void) (*(memctxp) = NULL), \ 124 (void) ldap_pvt_thread_pool_getkey(thrctx,memctx_key, memctxp,NULL), \ 125 *(memctxp)) 126 127/* Destroy the context, or if key==NULL clean it up for reuse. */ 128void 129slap_sl_mem_destroy( 130 void *key, 131 void *data 132) 133{ 134 struct slab_heap *sh = data; 135 struct slab_object *so; 136 int i; 137 138 if (!sh) 139 return; 140 141 if (!sh->sh_stack) { 142 for (i = 0; i <= sh->sh_maxorder - order_start; i++) { 143 so = LDAP_LIST_FIRST(&sh->sh_free[i]); 144 while (so) { 145 struct slab_object *so_tmp = so; 146 so = LDAP_LIST_NEXT(so, so_link); 147 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link); 148 } 149 ch_free(sh->sh_map[i]); 150 } 151 ch_free(sh->sh_free); 152 ch_free(sh->sh_map); 153 154 so = LDAP_LIST_FIRST(&sh->sh_sopool); 155 while (so) { 156 struct slab_object *so_tmp = so; 157 so = LDAP_LIST_NEXT(so, so_link); 158 if (!so_tmp->so_blockhead) { 159 LDAP_LIST_REMOVE(so_tmp, so_link); 160 } 161 } 162 so = LDAP_LIST_FIRST(&sh->sh_sopool); 163 while (so) { 164 struct slab_object *so_tmp = so; 165 so = LDAP_LIST_NEXT(so, so_link); 166 ch_free(so_tmp); 167 } 168 } 169 170 if (key != NULL) { 171 ber_memfree_x(sh->sh_base, NULL); 172 ber_memfree_x(sh, NULL); 173 } 174} 175 176BerMemoryFunctions slap_sl_mfuncs = 177 { slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free }; 178 179void 180slap_sl_mem_init() 181{ 182 assert( Align == 1 << Align_log2 ); 183 184 ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs ); 185} 186 187/* Create, reset or just return the memory context of the current thread. */ 188void * 189slap_sl_mem_create( 190 ber_len_t size, 191 int stack, 192 void *thrctx, 193 int new 194) 195{ 196 void *memctx; 197 struct slab_heap *sh; 198 ber_len_t size_shift; 199 struct slab_object *so; 200 char *base, *newptr; 201 enum { Base_offset = (unsigned) -sizeof(ber_len_t) % Align }; 202 203 sh = GET_MEMCTX(thrctx, &memctx); 204 if ( sh && !new ) 205 return sh; 206 207 /* Round up to doubleword boundary, then make room for initial 208 * padding, preserving expected available size for pool version */ 209 size = ((size + Align-1) & -Align) + Base_offset; 210 211 if (!sh) { 212 sh = ch_malloc(sizeof(struct slab_heap)); 213 base = ch_malloc(size); 214 SET_MEMCTX(thrctx, sh, slap_sl_mem_destroy); 215 VGMEMP_MARK(base, size); 216 VGMEMP_CREATE(sh, 0, 0); 217 } else { 218 slap_sl_mem_destroy(NULL, sh); 219 base = sh->sh_base; 220 if (size > (ber_len_t) ((char *) sh->sh_end - base)) { 221 newptr = ch_realloc(base, size); 222 if ( newptr == NULL ) return NULL; 223 VGMEMP_CHANGE(sh, base, newptr, size); 224 base = newptr; 225 } 226 VGMEMP_TRIM(sh, base, 0); 227 } 228 sh->sh_base = base; 229 sh->sh_end = base + size; 230 231 /* Align (base + head of first block) == first returned block */ 232 base += Base_offset; 233 size -= Base_offset; 234 235 sh->sh_stack = stack; 236 if (stack) { 237 sh->sh_last = base; 238 239 } else { 240 int i, order = -1, order_end = -1; 241 242 size_shift = size - 1; 243 do { 244 order_end++; 245 } while (size_shift >>= 1); 246 order = order_end - order_start + 1; 247 sh->sh_maxorder = order_end; 248 249 sh->sh_free = (struct sh_freelist *) 250 ch_malloc(order * sizeof(struct sh_freelist)); 251 for (i = 0; i < order; i++) { 252 LDAP_LIST_INIT(&sh->sh_free[i]); 253 } 254 255 LDAP_LIST_INIT(&sh->sh_sopool); 256 257 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 258 slap_replenish_sopool(sh); 259 } 260 so = LDAP_LIST_FIRST(&sh->sh_sopool); 261 LDAP_LIST_REMOVE(so, so_link); 262 so->so_ptr = base; 263 264 LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link); 265 266 sh->sh_map = (unsigned char **) 267 ch_malloc(order * sizeof(unsigned char *)); 268 for (i = 0; i < order; i++) { 269 int shiftamt = order_start + 1 + i; 270 int nummaps = size >> shiftamt; 271 assert(nummaps); 272 nummaps >>= 3; 273 if (!nummaps) nummaps = 1; 274 sh->sh_map[i] = (unsigned char *) ch_malloc(nummaps); 275 memset(sh->sh_map[i], 0, nummaps); 276 } 277 } 278 279 return sh; 280} 281 282/* 283 * Assign memory context to thread context. Use NULL to detach 284 * current memory context from thread. Future users must 285 * know the context, since ch_free/slap_sl_context() cannot find it. 286 */ 287void 288slap_sl_mem_setctx( 289 void *thrctx, 290 void *memctx 291) 292{ 293 SET_MEMCTX(thrctx, memctx, slap_sl_mem_destroy); 294} 295 296void * 297slap_sl_malloc( 298 ber_len_t size, 299 void *ctx 300) 301{ 302 struct slab_heap *sh = ctx; 303 ber_len_t *ptr, *newptr; 304 305 /* ber_set_option calls us like this */ 306 if (No_sl_malloc || !ctx) { 307 newptr = ber_memalloc_x( size, NULL ); 308 if ( newptr ) return newptr; 309 Debug(LDAP_DEBUG_ANY, "slap_sl_malloc of %lu bytes failed\n", 310 (unsigned long) size ); 311 assert( 0 ); 312 exit( EXIT_FAILURE ); 313 } 314 315 /* Add room for head, ensure room for tail when freed, and 316 * round up to doubleword boundary. */ 317 size = (size + sizeof(ber_len_t) + Align-1 + !size) & -Align; 318 319 if (sh->sh_stack) { 320 if (size < (ber_len_t) ((char *) sh->sh_end - (char *) sh->sh_last)) { 321 newptr = sh->sh_last; 322 sh->sh_last = (char *) sh->sh_last + size; 323 VGMEMP_ALLOC(sh, newptr, size); 324 *newptr++ = size; 325 return( (void *)newptr ); 326 } 327 328 size -= sizeof(ber_len_t); 329 330 } else { 331 struct slab_object *so_new, *so_left, *so_right; 332 ber_len_t size_shift; 333 unsigned long diff; 334 int i, j, order = -1; 335 336 size_shift = size - 1; 337 do { 338 order++; 339 } while (size_shift >>= 1); 340 341 size -= sizeof(ber_len_t); 342 343 for (i = order; i <= sh->sh_maxorder && 344 LDAP_LIST_EMPTY(&sh->sh_free[i-order_start]); i++); 345 346 if (i == order) { 347 so_new = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 348 LDAP_LIST_REMOVE(so_new, so_link); 349 ptr = so_new->so_ptr; 350 diff = (unsigned long)((char*)ptr - 351 (char*)sh->sh_base) >> (order + 1); 352 sh->sh_map[order-order_start][diff>>3] |= (1 << (diff & 0x7)); 353 *ptr++ = size; 354 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_new, so_link); 355 return((void*)ptr); 356 } else if (i <= sh->sh_maxorder) { 357 for (j = i; j > order; j--) { 358 so_left = LDAP_LIST_FIRST(&sh->sh_free[j-order_start]); 359 LDAP_LIST_REMOVE(so_left, so_link); 360 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 361 slap_replenish_sopool(sh); 362 } 363 so_right = LDAP_LIST_FIRST(&sh->sh_sopool); 364 LDAP_LIST_REMOVE(so_right, so_link); 365 so_right->so_ptr = (void *)((char *)so_left->so_ptr + (1 << j)); 366 if (j == order + 1) { 367 ptr = so_left->so_ptr; 368 diff = (unsigned long)((char*)ptr - 369 (char*)sh->sh_base) >> (order+1); 370 sh->sh_map[order-order_start][diff>>3] |= 371 (1 << (diff & 0x7)); 372 *ptr++ = size; 373 LDAP_LIST_INSERT_HEAD( 374 &sh->sh_free[j-1-order_start], so_right, so_link); 375 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_left, so_link); 376 return((void*)ptr); 377 } else { 378 LDAP_LIST_INSERT_HEAD( 379 &sh->sh_free[j-1-order_start], so_right, so_link); 380 LDAP_LIST_INSERT_HEAD( 381 &sh->sh_free[j-1-order_start], so_left, so_link); 382 } 383 } 384 } 385 /* FIXME: missing return; guessing we failed... */ 386 } 387 388 Debug(LDAP_DEBUG_TRACE, 389 "sl_malloc %lu: ch_malloc\n", 390 (unsigned long) size ); 391 return ch_malloc(size); 392} 393 394#define LIM_SQRT(t) /* some value < sqrt(max value of unsigned type t) */ \ 395 ((0UL|(t)-1) >>31>>31 > 1 ? ((t)1 <<32) - 1 : \ 396 (0UL|(t)-1) >>31 ? 65535U : (0UL|(t)-1) >>15 ? 255U : 15U) 397 398void * 399slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx ) 400{ 401 void *newptr; 402 ber_len_t total = n * size; 403 404 /* The sqrt test is a slight optimization: often avoids the division */ 405 if ((n | size) <= LIM_SQRT(ber_len_t) || n == 0 || total/n == size) { 406 newptr = slap_sl_malloc( total, ctx ); 407 memset( newptr, 0, n*size ); 408 } else { 409 Debug(LDAP_DEBUG_ANY, "slap_sl_calloc(%lu,%lu) out of range\n", 410 (unsigned long) n, (unsigned long) size ); 411 assert(0); 412 exit(EXIT_FAILURE); 413 } 414 return newptr; 415} 416 417void * 418slap_sl_realloc(void *ptr, ber_len_t size, void *ctx) 419{ 420 struct slab_heap *sh = ctx; 421 ber_len_t oldsize, *p = (ber_len_t *) ptr, *nextp; 422 void *newptr; 423 424 if (ptr == NULL) 425 return slap_sl_malloc(size, ctx); 426 427 /* Not our memory? */ 428 if (No_sl_malloc || !sh || ptr < sh->sh_base || ptr >= sh->sh_end) { 429 /* Like ch_realloc(), except not trying a new context */ 430 newptr = ber_memrealloc_x(ptr, size, NULL); 431 if (newptr) { 432 return newptr; 433 } 434 Debug(LDAP_DEBUG_ANY, "slap_sl_realloc of %lu bytes failed\n", 435 (unsigned long) size ); 436 assert(0); 437 exit( EXIT_FAILURE ); 438 } 439 440 if (size == 0) { 441 slap_sl_free(ptr, ctx); 442 return NULL; 443 } 444 445 oldsize = p[-1]; 446 447 if (sh->sh_stack) { 448 /* Add room for head, round up to doubleword boundary */ 449 size = (size + sizeof(ber_len_t) + Align-1) & -Align; 450 451 p--; 452 453 /* Never shrink blocks */ 454 if (size <= oldsize) { 455 return ptr; 456 } 457 458 oldsize &= -2; 459 nextp = (ber_len_t *) ((char *) p + oldsize); 460 461 /* If reallocing the last block, try to grow it */ 462 if (nextp == sh->sh_last) { 463 if (size < (ber_len_t) ((char *) sh->sh_end - (char *) p)) { 464 sh->sh_last = (char *) p + size; 465 p[0] = (p[0] & 1) | size; 466 return ptr; 467 } 468 469 /* Nowhere to grow, need to alloc and copy */ 470 } else { 471 /* Slight optimization of the final realloc variant */ 472 newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx); 473 AC_MEMCPY(newptr, ptr, oldsize-sizeof(ber_len_t)); 474 /* Not last block, can just mark old region as free */ 475 nextp[-1] = oldsize; 476 nextp[0] |= 1; 477 return newptr; 478 } 479 480 size -= sizeof(ber_len_t); 481 oldsize -= sizeof(ber_len_t); 482 483 } else if (oldsize > size) { 484 oldsize = size; 485 } 486 487 newptr = slap_sl_malloc(size, ctx); 488 AC_MEMCPY(newptr, ptr, oldsize); 489 slap_sl_free(ptr, ctx); 490 return newptr; 491} 492 493void 494slap_sl_free(void *ptr, void *ctx) 495{ 496 struct slab_heap *sh = ctx; 497 ber_len_t size; 498 ber_len_t *p = ptr, *nextp, *tmpp; 499 500 if (!ptr) 501 return; 502 503 if (No_sl_malloc || !sh || ptr < sh->sh_base || ptr >= sh->sh_end) { 504 ber_memfree_x(ptr, NULL); 505 return; 506 } 507 508 size = *(--p); 509 510 if (sh->sh_stack) { 511 size &= -2; 512 nextp = (ber_len_t *) ((char *) p + size); 513 if (sh->sh_last != nextp) { 514 /* Mark it free: tail = size, head of next block |= 1 */ 515 nextp[-1] = size; 516 nextp[0] |= 1; 517 /* We can't tell Valgrind about it yet, because we 518 * still need read/write access to this block for 519 * when we eventually get to reclaim it. 520 */ 521 } else { 522 /* Reclaim freed block(s) off tail */ 523 while (*p & 1) { 524 p = (ber_len_t *) ((char *) p - p[-1]); 525 } 526 sh->sh_last = p; 527 VGMEMP_TRIM(sh, sh->sh_base, 528 (char *) sh->sh_last - (char *) sh->sh_base); 529 } 530 531 } else { 532 int size_shift, order_size; 533 struct slab_object *so; 534 unsigned long diff; 535 int i, inserted = 0, order = -1; 536 537 size_shift = size + sizeof(ber_len_t) - 1; 538 do { 539 order++; 540 } while (size_shift >>= 1); 541 542 for (i = order, tmpp = p; i <= sh->sh_maxorder; i++) { 543 order_size = 1 << (i+1); 544 diff = (unsigned long)((char*)tmpp - (char*)sh->sh_base) >> (i+1); 545 sh->sh_map[i-order_start][diff>>3] &= (~(1 << (diff & 0x7))); 546 if (diff == ((diff>>1)<<1)) { 547 if (!(sh->sh_map[i-order_start][(diff+1)>>3] & 548 (1<<((diff+1)&0x7)))) { 549 so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 550 while (so) { 551 if ((char*)so->so_ptr == (char*)tmpp) { 552 LDAP_LIST_REMOVE( so, so_link ); 553 } else if ((char*)so->so_ptr == 554 (char*)tmpp + order_size) { 555 LDAP_LIST_REMOVE(so, so_link); 556 break; 557 } 558 so = LDAP_LIST_NEXT(so, so_link); 559 } 560 if (so) { 561 if (i < sh->sh_maxorder) { 562 inserted = 1; 563 so->so_ptr = tmpp; 564 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1], 565 so, so_link); 566 } 567 continue; 568 } else { 569 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 570 slap_replenish_sopool(sh); 571 } 572 so = LDAP_LIST_FIRST(&sh->sh_sopool); 573 LDAP_LIST_REMOVE(so, so_link); 574 so->so_ptr = tmpp; 575 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 576 so, so_link); 577 break; 578 579 Debug(LDAP_DEBUG_TRACE, "slap_sl_free: " 580 "free object not found while bit is clear.\n" ); 581 assert(so != NULL); 582 583 } 584 } else { 585 if (!inserted) { 586 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 587 slap_replenish_sopool(sh); 588 } 589 so = LDAP_LIST_FIRST(&sh->sh_sopool); 590 LDAP_LIST_REMOVE(so, so_link); 591 so->so_ptr = tmpp; 592 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 593 so, so_link); 594 } 595 break; 596 } 597 } else { 598 if (!(sh->sh_map[i-order_start][(diff-1)>>3] & 599 (1<<((diff-1)&0x7)))) { 600 so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 601 while (so) { 602 if ((char*)so->so_ptr == (char*)tmpp) { 603 LDAP_LIST_REMOVE(so, so_link); 604 } else if ((char*)tmpp == (char *)so->so_ptr + order_size) { 605 LDAP_LIST_REMOVE(so, so_link); 606 tmpp = so->so_ptr; 607 break; 608 } 609 so = LDAP_LIST_NEXT(so, so_link); 610 } 611 if (so) { 612 if (i < sh->sh_maxorder) { 613 inserted = 1; 614 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1], so, so_link); 615 continue; 616 } 617 } else { 618 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 619 slap_replenish_sopool(sh); 620 } 621 so = LDAP_LIST_FIRST(&sh->sh_sopool); 622 LDAP_LIST_REMOVE(so, so_link); 623 so->so_ptr = tmpp; 624 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 625 so, so_link); 626 break; 627 628 Debug(LDAP_DEBUG_TRACE, "slap_sl_free: " 629 "free object not found while bit is clear.\n" ); 630 assert(so != NULL); 631 632 } 633 } else { 634 if ( !inserted ) { 635 if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { 636 slap_replenish_sopool(sh); 637 } 638 so = LDAP_LIST_FIRST(&sh->sh_sopool); 639 LDAP_LIST_REMOVE(so, so_link); 640 so->so_ptr = tmpp; 641 LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], 642 so, so_link); 643 } 644 break; 645 } 646 } 647 } 648 } 649} 650 651void 652slap_sl_release( void *ptr, void *ctx ) 653{ 654 struct slab_heap *sh = ctx; 655 if ( sh && ptr >= sh->sh_base && ptr <= sh->sh_end ) 656 sh->sh_last = ptr; 657} 658 659void * 660slap_sl_mark( void *ctx ) 661{ 662 struct slab_heap *sh = ctx; 663 return sh->sh_last; 664} 665 666/* 667 * Return the memory context of the current thread if the given block of 668 * memory belongs to it, otherwise return NULL. 669 */ 670void * 671slap_sl_context( void *ptr ) 672{ 673 void *memctx; 674 struct slab_heap *sh; 675 676 if ( slapMode & SLAP_TOOL_MODE ) return NULL; 677 678 sh = GET_MEMCTX(ldap_pvt_thread_pool_context(), &memctx); 679 if (sh && ptr >= sh->sh_base && ptr <= sh->sh_end) { 680 return sh; 681 } 682 return NULL; 683} 684 685static struct slab_object * 686slap_replenish_sopool( 687 struct slab_heap* sh 688) 689{ 690 struct slab_object *so_block; 691 int i; 692 693 so_block = (struct slab_object *)ch_malloc( 694 SLAP_SLAB_SOBLOCK * sizeof(struct slab_object)); 695 696 if ( so_block == NULL ) { 697 return NULL; 698 } 699 700 so_block[0].so_blockhead = 1; 701 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link); 702 for (i = 1; i < SLAP_SLAB_SOBLOCK; i++) { 703 so_block[i].so_blockhead = 0; 704 LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[i], so_link ); 705 } 706 707 return so_block; 708} 709 710#ifdef SLAPD_UNUSED 711static void 712print_slheap(int level, void *ctx) 713{ 714 struct slab_heap *sh = ctx; 715 struct slab_object *so; 716 int i, j, once = 0; 717 718 if (!ctx) { 719 Debug(level, "NULL memctx\n" ); 720 return; 721 } 722 723 Debug(level, "sh->sh_maxorder=%d\n", sh->sh_maxorder ); 724 725 for (i = order_start; i <= sh->sh_maxorder; i++) { 726 once = 0; 727 Debug(level, "order=%d\n", i ); 728 for (j = 0; j < (1<<(sh->sh_maxorder-i))/8; j++) { 729 Debug(level, "%02x ", sh->sh_map[i-order_start][j] ); 730 once = 1; 731 } 732 if (!once) { 733 Debug(level, "%02x ", sh->sh_map[i-order_start][0] ); 734 } 735 Debug(level, "\n" ); 736 Debug(level, "free list:\n" ); 737 so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); 738 while (so) { 739 Debug(level, "%p\n", so->so_ptr ); 740 so = LDAP_LIST_NEXT(so, so_link); 741 } 742 } 743} 744#endif 745