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