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