Home | History | Annotate | Line # | Download | only in slapd
sl_malloc.c revision 1.1.1.2
      1 /*	$NetBSD: sl_malloc.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
      2 
      3 /* sl_malloc.c - malloc routines using a per-thread slab */
      4 /* OpenLDAP: pkg/ldap/servers/slapd/sl_malloc.c,v 1.39.2.10 2009/11/18 01:22:22 quanah Exp */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2003-2009 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 "portable.h"
     20 
     21 #include <stdio.h>
     22 #include <ac/string.h>
     23 
     24 #include "slap.h"
     25 
     26 static struct slab_object * slap_replenish_sopool(struct slab_heap* sh);
     27 #ifdef SLAPD_UNUSED
     28 static void print_slheap(int level, void *ctx);
     29 #endif
     30 
     31 void
     32 slap_sl_mem_destroy(
     33 	void *key,
     34 	void *data
     35 )
     36 {
     37 	struct slab_heap *sh = data;
     38 	int pad = 2*sizeof(int)-1, pad_shift;
     39 	int order_start = -1, i;
     40 	struct slab_object *so;
     41 
     42 	if (sh->sh_stack) {
     43 		ber_memfree_x(sh->sh_base, NULL);
     44 		ber_memfree_x(sh, NULL);
     45 	} else {
     46 		pad_shift = pad - 1;
     47 		do {
     48 			order_start++;
     49 		} while (pad_shift >>= 1);
     50 
     51 		for (i = 0; i <= sh->sh_maxorder - order_start; i++) {
     52 			so = LDAP_LIST_FIRST(&sh->sh_free[i]);
     53 			while (so) {
     54 				struct slab_object *so_tmp = so;
     55 				so = LDAP_LIST_NEXT(so, so_link);
     56 				LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link);
     57 			}
     58 			ch_free(sh->sh_map[i]);
     59 		}
     60 		ch_free(sh->sh_free);
     61 		ch_free(sh->sh_map);
     62 
     63 		so = LDAP_LIST_FIRST(&sh->sh_sopool);
     64 		while (so) {
     65 			struct slab_object *so_tmp = so;
     66 			so = LDAP_LIST_NEXT(so, so_link);
     67 			if (!so_tmp->so_blockhead) {
     68 				LDAP_LIST_REMOVE(so_tmp, so_link);
     69 			}
     70 		}
     71 		so = LDAP_LIST_FIRST(&sh->sh_sopool);
     72 		while (so) {
     73 			struct slab_object *so_tmp = so;
     74 			so = LDAP_LIST_NEXT(so, so_link);
     75 			ch_free(so_tmp);
     76 		}
     77 		ber_memfree_x(sh->sh_base, NULL);
     78 		ber_memfree_x(sh, NULL);
     79 	}
     80 }
     81 
     82 BerMemoryFunctions slap_sl_mfuncs =
     83 	{ slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free };
     84 
     85 void
     86 slap_sl_mem_init()
     87 {
     88 	ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs );
     89 }
     90 
     91 #ifdef NO_THREADS
     92 static struct slab_heap *slheap;
     93 #endif
     94 
     95 /* This allocator always returns memory aligned on a 2-int boundary.
     96  *
     97  * The stack-based allocator stores the size as a ber_len_t at both
     98  * the head and tail of the allocated block. When freeing a block, the
     99  * tail length is ORed with 1 to mark it as free. Freed space can only
    100  * be reclaimed from the tail forward. If the tail block is never freed,
    101  * nothing else will be reclaimed until the slab is reset...
    102  */
    103 void *
    104 slap_sl_mem_create(
    105 	ber_len_t size,
    106 	int stack,
    107 	void *ctx,
    108 	int new
    109 )
    110 {
    111 	struct slab_heap *sh;
    112 	ber_len_t size_shift;
    113 	int pad = 2*sizeof(int)-1, pad_shift;
    114 	int order = -1, order_start = -1, order_end = -1;
    115 	int i;
    116 	struct slab_object *so;
    117 
    118 #ifdef NO_THREADS
    119 	sh = slheap;
    120 #else
    121 	void *sh_tmp = NULL;
    122 	ldap_pvt_thread_pool_getkey(
    123 		ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL );
    124 	sh = sh_tmp;
    125 #endif
    126 
    127 	if ( sh && !new )
    128 		return sh;
    129 
    130 	/* round up to doubleword boundary */
    131 	size += pad;
    132 	size &= ~pad;
    133 
    134 	if (stack) {
    135 		if (!sh) {
    136 			sh = ch_malloc(sizeof(struct slab_heap));
    137 			sh->sh_base = ch_malloc(size);
    138 #ifdef NO_THREADS
    139 			slheap = sh;
    140 #else
    141 			ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init,
    142 				(void *)sh, slap_sl_mem_destroy, NULL, NULL);
    143 #endif
    144 		} else if ( size > (char *)sh->sh_end - (char *)sh->sh_base ) {
    145 			void	*newptr;
    146 
    147 			newptr = ch_realloc( sh->sh_base, size );
    148 			if ( newptr == NULL ) return NULL;
    149 			sh->sh_base = newptr;
    150 		}
    151 		/* insert dummy len */
    152 		{
    153 			ber_len_t *i = sh->sh_base;
    154 			*i++ = 0;
    155 			sh->sh_last = i;
    156 		}
    157 		sh->sh_end = (char *) sh->sh_base + size;
    158 		sh->sh_stack = stack;
    159 		return sh;
    160 	} else {
    161 		size_shift = size - 1;
    162 		do {
    163 			order_end++;
    164 		} while (size_shift >>= 1);
    165 
    166 		pad_shift = pad - 1;
    167 		do {
    168 			order_start++;
    169 		} while (pad_shift >>= 1);
    170 
    171 		order = order_end - order_start + 1;
    172 
    173 		if (!sh) {
    174 			sh = (struct slab_heap *) ch_malloc(sizeof(struct slab_heap));
    175 			sh->sh_base = ch_malloc(size);
    176 #ifdef NO_THREADS
    177 			slheap = sh;
    178 #else
    179 			ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init,
    180 				(void *)sh, slap_sl_mem_destroy, NULL, NULL);
    181 #endif
    182 		} else {
    183 			for (i = 0; i <= sh->sh_maxorder - order_start; i++) {
    184 				so = LDAP_LIST_FIRST(&sh->sh_free[i]);
    185 				while (so) {
    186 					struct slab_object *so_tmp = so;
    187 					so = LDAP_LIST_NEXT(so, so_link);
    188 					LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link);
    189 				}
    190 				ch_free(sh->sh_map[i]);
    191 			}
    192 			ch_free(sh->sh_free);
    193 			ch_free(sh->sh_map);
    194 
    195 			so = LDAP_LIST_FIRST(&sh->sh_sopool);
    196 			while (so) {
    197 				struct slab_object *so_tmp = so;
    198 				so = LDAP_LIST_NEXT(so, so_link);
    199 				if (!so_tmp->so_blockhead) {
    200 					LDAP_LIST_REMOVE(so_tmp, so_link);
    201 				}
    202 			}
    203 			so = LDAP_LIST_FIRST(&sh->sh_sopool);
    204 			while (so) {
    205 				struct slab_object *so_tmp = so;
    206 				so = LDAP_LIST_NEXT(so, so_link);
    207 				ch_free(so_tmp);
    208 			}
    209 
    210 			if (size > (char *)sh->sh_end - (char *)sh->sh_base) {
    211 				void	*newptr;
    212 
    213 				newptr = ch_realloc( sh->sh_base, size );
    214 				if ( newptr == NULL ) return NULL;
    215 				sh->sh_base = newptr;
    216 			}
    217 		}
    218 		sh->sh_end = (char *)sh->sh_base + size;
    219 		sh->sh_maxorder = order_end;
    220 
    221 		sh->sh_free = (struct sh_freelist *)
    222 						ch_malloc(order * sizeof(struct sh_freelist));
    223 		for (i = 0; i < order; i++) {
    224 			LDAP_LIST_INIT(&sh->sh_free[i]);
    225 		}
    226 
    227 		LDAP_LIST_INIT(&sh->sh_sopool);
    228 
    229 		if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
    230 			slap_replenish_sopool(sh);
    231 		}
    232 		so = LDAP_LIST_FIRST(&sh->sh_sopool);
    233 		LDAP_LIST_REMOVE(so, so_link);
    234 		so->so_ptr = sh->sh_base;
    235 
    236 		LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link);
    237 
    238 		sh->sh_map = (unsigned char **)
    239 					ch_malloc(order * sizeof(unsigned char *));
    240 		for (i = 0; i < order; i++) {
    241 			int shiftamt = order_start + 1 + i;
    242 			int nummaps = size >> shiftamt;
    243 			assert(nummaps);
    244 			nummaps >>= 3;
    245 			if (!nummaps) nummaps = 1;
    246 			sh->sh_map[i] = (unsigned char *) ch_malloc(nummaps);
    247 			memset(sh->sh_map[i], 0, nummaps);
    248 		}
    249 		sh->sh_stack = stack;
    250 		return sh;
    251 	}
    252 }
    253 
    254 void
    255 slap_sl_mem_detach(
    256 	void *ctx,
    257 	void *memctx
    258 )
    259 {
    260 #ifdef NO_THREADS
    261 	slheap = NULL;
    262 #else
    263 	/* separate from context */
    264 	ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init,
    265 		NULL, 0, NULL, NULL );
    266 #endif
    267 }
    268 
    269 void *
    270 slap_sl_malloc(
    271     ber_len_t	size,
    272     void *ctx
    273 )
    274 {
    275 	struct slab_heap *sh = ctx;
    276 	int pad = 2*sizeof(int)-1, pad_shift;
    277 	ber_len_t *ptr, *newptr;
    278 
    279 #ifdef SLAP_NO_SL_MALLOC
    280 	newptr = ber_memalloc_x( size, NULL );
    281 	if ( newptr ) return newptr;
    282 	assert( 0 );
    283 	exit( EXIT_FAILURE );
    284 #endif
    285 
    286 	/* ber_set_option calls us like this */
    287 	if (!ctx) {
    288 		newptr = ber_memalloc_x( size, NULL );
    289 		if ( newptr ) return newptr;
    290 		assert( 0 );
    291 		exit( EXIT_FAILURE );
    292 	}
    293 
    294 	/* round up to doubleword boundary, plus space for len at head and tail */
    295 	size += 2*sizeof(ber_len_t) + pad;
    296 	size &= ~pad;
    297 
    298 	if (sh->sh_stack) {
    299 		if ((char *)sh->sh_last + size >= (char *)sh->sh_end) {
    300 			Debug(LDAP_DEBUG_TRACE,
    301 				"slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
    302 				(long)size, 0, 0);
    303 			return ch_malloc(size);
    304 		}
    305 		newptr = sh->sh_last;
    306 		sh->sh_last = (char *) sh->sh_last + size;
    307 		size -= sizeof(ber_len_t);
    308 		*newptr++ = size;
    309 		*(ber_len_t *)((char *)sh->sh_last - sizeof(ber_len_t)) = size;
    310 		return( (void *)newptr );
    311 	} else {
    312 		struct slab_object *so_new, *so_left, *so_right;
    313 		ber_len_t size_shift;
    314 		int order = -1, order_start = -1;
    315 		unsigned long diff;
    316 		int i, j;
    317 
    318 		size_shift = size - 1;
    319 		do {
    320 			order++;
    321 		} while (size_shift >>= 1);
    322 
    323 		pad_shift = pad - 1;
    324 		do {
    325 			order_start++;
    326 		} while (pad_shift >>= 1);
    327 
    328 		for (i = order; i <= sh->sh_maxorder &&
    329 				LDAP_LIST_EMPTY(&sh->sh_free[i-order_start]); i++);
    330 
    331 		if (i == order) {
    332 			so_new = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
    333 			LDAP_LIST_REMOVE(so_new, so_link);
    334 			ptr = so_new->so_ptr;
    335 			diff = (unsigned long)((char*)ptr -
    336 					(char*)sh->sh_base) >> (order + 1);
    337 			sh->sh_map[order-order_start][diff>>3] |= (1 << (diff & 0x7));
    338 			*ptr++ = size - sizeof(ber_len_t);
    339 			LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_new, so_link);
    340 			return((void*)ptr);
    341 		} else if (i <= sh->sh_maxorder) {
    342 			for (j = i; j > order; j--) {
    343 				so_left = LDAP_LIST_FIRST(&sh->sh_free[j-order_start]);
    344 				LDAP_LIST_REMOVE(so_left, so_link);
    345 				if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
    346 					slap_replenish_sopool(sh);
    347 				}
    348 				so_right = LDAP_LIST_FIRST(&sh->sh_sopool);
    349 				LDAP_LIST_REMOVE(so_right, so_link);
    350 				so_right->so_ptr = (void *)((char *)so_left->so_ptr + (1 << j));
    351 				if (j == order + 1) {
    352 					ptr = so_left->so_ptr;
    353 					diff = (unsigned long)((char*)ptr -
    354 							(char*)sh->sh_base) >> (order+1);
    355 					sh->sh_map[order-order_start][diff>>3] |=
    356 							(1 << (diff & 0x7));
    357 					*ptr++ = size - sizeof(ber_len_t);
    358 					LDAP_LIST_INSERT_HEAD(
    359 							&sh->sh_free[j-1-order_start], so_right, so_link);
    360 					LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_left, so_link);
    361 					return((void*)ptr);
    362 				} else {
    363 					LDAP_LIST_INSERT_HEAD(
    364 							&sh->sh_free[j-1-order_start], so_right, so_link);
    365 					LDAP_LIST_INSERT_HEAD(
    366 							&sh->sh_free[j-1-order_start], so_left, so_link);
    367 				}
    368 			}
    369 		} else {
    370 			Debug( LDAP_DEBUG_TRACE,
    371 				"slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
    372 				(long)size, 0, 0);
    373 			return (void*)ch_malloc(size);
    374 		}
    375 	}
    376 
    377 	/* FIXME: missing return; guessing... */
    378 	return NULL;
    379 }
    380 
    381 void *
    382 slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
    383 {
    384 	void *newptr;
    385 
    386 	newptr = slap_sl_malloc( n*size, ctx );
    387 	if ( newptr ) {
    388 		memset( newptr, 0, n*size );
    389 	}
    390 	return newptr;
    391 }
    392 
    393 void *
    394 slap_sl_realloc(void *ptr, ber_len_t size, void *ctx)
    395 {
    396 	struct slab_heap *sh = ctx;
    397 	int pad = 2*sizeof(int) -1;
    398 	ber_len_t *p = (ber_len_t *)ptr, *newptr;
    399 
    400 	if (ptr == NULL)
    401 		return slap_sl_malloc(size, ctx);
    402 
    403 #ifdef SLAP_NO_SL_MALLOC
    404 	newptr = ber_memrealloc_x( ptr, size, NULL );
    405 	if ( newptr ) return newptr;
    406 	assert( 0 );
    407 	exit( EXIT_FAILURE );
    408 #endif
    409 
    410 	/* Not our memory? */
    411 	if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
    412 		/* duplicate of realloc behavior, oh well */
    413 		newptr = ber_memrealloc_x(ptr, size, NULL);
    414 		if (newptr) {
    415 			return newptr;
    416 		}
    417 		Debug(LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
    418 				(long) size, 0, 0);
    419 		assert(0);
    420 		exit( EXIT_FAILURE );
    421 	}
    422 
    423 	if (size == 0) {
    424 		slap_sl_free(ptr, ctx);
    425 		return NULL;
    426 	}
    427 
    428 	if (sh->sh_stack) {
    429 		/* round up to doubleword boundary */
    430 		size += pad + sizeof( ber_len_t );
    431 		size &= ~pad;
    432 
    433 		p--;
    434 
    435 		/* Never shrink blocks */
    436 		if (size <= p[0]) {
    437 			newptr = ptr;
    438 
    439 		/* If reallocing the last block, we can grow it */
    440 		} else if ((char *)ptr + p[0] == sh->sh_last &&
    441 			(char *)ptr + size < (char *)sh->sh_end ) {
    442 			newptr = ptr;
    443 			sh->sh_last = (char *)ptr + size;
    444 			p[0] = size;
    445 			p[size/sizeof(ber_len_t)] = size;
    446 
    447 		/* Nowhere to grow, need to alloc and copy */
    448 		} else {
    449 			newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx);
    450 			AC_MEMCPY(newptr, ptr, p[0]-sizeof(ber_len_t));
    451 			/* mark old region as free */
    452 			p[p[0]/sizeof(ber_len_t)] |= 1;
    453 		}
    454 		return newptr;
    455 	} else {
    456 		void *newptr2;
    457 
    458 		newptr2 = slap_sl_malloc(size, ctx);
    459 		if (size < p[-1]) {
    460 			AC_MEMCPY(newptr2, ptr, size);
    461 		} else {
    462 			AC_MEMCPY(newptr2, ptr, p[-1]);
    463 		}
    464 		slap_sl_free(ptr, ctx);
    465 		return newptr2;
    466 	}
    467 }
    468 
    469 void
    470 slap_sl_free(void *ptr, void *ctx)
    471 {
    472 	struct slab_heap *sh = ctx;
    473 	ber_len_t size;
    474 	ber_len_t *p = (ber_len_t *)ptr, *tmpp;
    475 
    476 	if (!ptr)
    477 		return;
    478 
    479 #ifdef SLAP_NO_SL_MALLOC
    480 	ber_memfree_x( ptr, NULL );
    481 	return;
    482 #endif
    483 
    484 	if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
    485 		ber_memfree_x(ptr, NULL);
    486 	} else if (sh->sh_stack) {
    487 		tmpp = (ber_len_t *)((char *)ptr + p[-1]);
    488 		/* mark it free */
    489 		tmpp[-1] |= 1;
    490 		/* reclaim free space off tail */
    491 		while ( tmpp == sh->sh_last ) {
    492 			if ( tmpp[-1] & 1 ) {
    493 				size = tmpp[-1] ^ 1;
    494 				ptr = (char *)tmpp - size;
    495 				p = (ber_len_t *)ptr;
    496 				p--;
    497 				sh->sh_last = p;
    498 				tmpp = sh->sh_last;
    499 			} else {
    500 				break;
    501 			}
    502 		}
    503 	} else {
    504 		int size_shift, order_size;
    505 		int pad = 2*sizeof(int)-1, pad_shift;
    506 		int order_start = -1, order = -1;
    507 		struct slab_object *so;
    508 		unsigned long diff;
    509 		int i, inserted = 0;
    510 
    511 		size = *(--p);
    512 		size_shift = size + sizeof(ber_len_t) - 1;
    513 		do {
    514 			order++;
    515 		} while (size_shift >>= 1);
    516 
    517 		pad_shift = pad - 1;
    518 		do {
    519 			order_start++;
    520 		} while (pad_shift >>= 1);
    521 
    522 		for (i = order, tmpp = p; i <= sh->sh_maxorder; i++) {
    523 			order_size = 1 << (i+1);
    524 			diff = (unsigned long)((char*)tmpp - (char*)sh->sh_base) >> (i+1);
    525 			sh->sh_map[i-order_start][diff>>3] &= (~(1 << (diff & 0x7)));
    526 			if (diff == ((diff>>1)<<1)) {
    527 				if (!(sh->sh_map[i-order_start][(diff+1)>>3] &
    528 						(1<<((diff+1)&0x7)))) {
    529 					so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
    530 					while (so) {
    531 						if ((char*)so->so_ptr == (char*)tmpp) {
    532 							LDAP_LIST_REMOVE( so, so_link );
    533 						} else if ((char*)so->so_ptr ==
    534 								(char*)tmpp + order_size) {
    535 							LDAP_LIST_REMOVE(so, so_link);
    536 							break;
    537 						}
    538 						so = LDAP_LIST_NEXT(so, so_link);
    539 					}
    540 					if (so) {
    541 						if (i < sh->sh_maxorder) {
    542 							inserted = 1;
    543 							so->so_ptr = tmpp;
    544 							LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1],
    545 									so, so_link);
    546 						}
    547 						continue;
    548 					} else {
    549 						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
    550 							slap_replenish_sopool(sh);
    551 						}
    552 						so = LDAP_LIST_FIRST(&sh->sh_sopool);
    553 						LDAP_LIST_REMOVE(so, so_link);
    554 						so->so_ptr = tmpp;
    555 						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
    556 								so, so_link);
    557 						break;
    558 
    559 						Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
    560 							"free object not found while bit is clear.\n",
    561 							0, 0, 0);
    562 						assert(so != NULL);
    563 
    564 					}
    565 				} else {
    566 					if (!inserted) {
    567 						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
    568 							slap_replenish_sopool(sh);
    569 						}
    570 						so = LDAP_LIST_FIRST(&sh->sh_sopool);
    571 						LDAP_LIST_REMOVE(so, so_link);
    572 						so->so_ptr = tmpp;
    573 						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
    574 								so, so_link);
    575 					}
    576 					break;
    577 				}
    578 			} else {
    579 				if (!(sh->sh_map[i-order_start][(diff-1)>>3] &
    580 						(1<<((diff-1)&0x7)))) {
    581 					so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
    582 					while (so) {
    583 						if ((char*)so->so_ptr == (char*)tmpp) {
    584 							LDAP_LIST_REMOVE(so, so_link);
    585 						} else if ((char*)tmpp == (char *)so->so_ptr + order_size) {
    586 							LDAP_LIST_REMOVE(so, so_link);
    587 							tmpp = so->so_ptr;
    588 							break;
    589 						}
    590 						so = LDAP_LIST_NEXT(so, so_link);
    591 					}
    592 					if (so) {
    593 						if (i < sh->sh_maxorder) {
    594 							inserted = 1;
    595 							LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1],									so, so_link);
    596 							continue;
    597 						}
    598 					} else {
    599 						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
    600 							slap_replenish_sopool(sh);
    601 						}
    602 						so = LDAP_LIST_FIRST(&sh->sh_sopool);
    603 						LDAP_LIST_REMOVE(so, so_link);
    604 						so->so_ptr = tmpp;
    605 						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
    606 								so, so_link);
    607 						break;
    608 
    609 						Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
    610 							"free object not found while bit is clear.\n",
    611 							0, 0, 0 );
    612 						assert(so != NULL);
    613 
    614 					}
    615 				} else {
    616 					if ( !inserted ) {
    617 						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
    618 							slap_replenish_sopool(sh);
    619 						}
    620 						so = LDAP_LIST_FIRST(&sh->sh_sopool);
    621 						LDAP_LIST_REMOVE(so, so_link);
    622 						so->so_ptr = tmpp;
    623 						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
    624 								so, so_link);
    625 					}
    626 					break;
    627 				}
    628 			}
    629 		}
    630 	}
    631 }
    632 
    633 void *
    634 slap_sl_context( void *ptr )
    635 {
    636 	struct slab_heap *sh;
    637 	void *ctx, *sh_tmp;
    638 
    639 	if ( slapMode & SLAP_TOOL_MODE ) return NULL;
    640 
    641 #ifdef NO_THREADS
    642 	sh = slheap;
    643 #else
    644 	ctx = ldap_pvt_thread_pool_context();
    645 
    646 	sh_tmp = NULL;
    647 	ldap_pvt_thread_pool_getkey(
    648 		ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL);
    649 	sh = sh_tmp;
    650 #endif
    651 
    652 	if (sh && ptr >= sh->sh_base && ptr <= sh->sh_end) {
    653 		return sh;
    654 	}
    655 	return NULL;
    656 }
    657 
    658 static struct slab_object *
    659 slap_replenish_sopool(
    660     struct slab_heap* sh
    661 )
    662 {
    663     struct slab_object *so_block;
    664     int i;
    665 
    666     so_block = (struct slab_object *)ch_malloc(
    667                     SLAP_SLAB_SOBLOCK * sizeof(struct slab_object));
    668 
    669     if ( so_block == NULL ) {
    670         return NULL;
    671     }
    672 
    673     so_block[0].so_blockhead = 1;
    674     LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link);
    675     for (i = 1; i < SLAP_SLAB_SOBLOCK; i++) {
    676         so_block[i].so_blockhead = 0;
    677         LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[i], so_link );
    678     }
    679 
    680     return so_block;
    681 }
    682 
    683 #ifdef SLAPD_UNUSED
    684 static void
    685 print_slheap(int level, void *ctx)
    686 {
    687 	struct slab_heap *sh = ctx;
    688 	int order_start = -1;
    689 	int pad = 2*sizeof(int)-1, pad_shift;
    690 	struct slab_object *so;
    691 	int i, j, once = 0;
    692 
    693 	if (!ctx) {
    694 		Debug(level, "NULL memctx\n", 0, 0, 0);
    695 		return;
    696 	}
    697 
    698 	pad_shift = pad - 1;
    699 	do {
    700 		order_start++;
    701 	} while (pad_shift >>= 1);
    702 
    703 	Debug(level, "sh->sh_maxorder=%d\n", sh->sh_maxorder, 0, 0);
    704 
    705 	for (i = order_start; i <= sh->sh_maxorder; i++) {
    706 		once = 0;
    707 		Debug(level, "order=%d\n", i, 0, 0);
    708 		for (j = 0; j < (1<<(sh->sh_maxorder-i))/8; j++) {
    709 			Debug(level, "%02x ", sh->sh_map[i-order_start][j], 0, 0);
    710 			once = 1;
    711 		}
    712 		if (!once) {
    713 			Debug(level, "%02x ", sh->sh_map[i-order_start][0], 0, 0);
    714 		}
    715 		Debug(level, "\n", 0, 0, 0);
    716 		Debug(level, "free list:\n", 0, 0, 0);
    717 		so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
    718 		while (so) {
    719 			Debug(level, "%lx\n", (unsigned long) so->so_ptr, 0, 0);
    720 			so = LDAP_LIST_NEXT(so, so_link);
    721 		}
    722 	}
    723 }
    724 #endif
    725