xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/sl_malloc.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /*	$NetBSD: sl_malloc.c,v 1.1.1.3 2010/12/12 15:22:45 adam 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.13 2010/04/19 20:58:45 quanah Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2003-2010 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 				"sl_malloc %lu: 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