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