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