Back to index

openldap  2.4.31
sl_malloc.c
Go to the documentation of this file.
00001 /* sl_malloc.c - malloc routines using a per-thread slab */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2003-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 
00022 #include "slap.h"
00023 
00024 #ifdef USE_VALGRIND
00025 /* Get debugging help from Valgrind */
00026 #include <valgrind/memcheck.h>
00027 #define       VGMEMP_MARK(m,s)     VALGRIND_MAKE_MEM_NOACCESS(m,s)
00028 #define VGMEMP_CREATE(h,r,z)       VALGRIND_CREATE_MEMPOOL(h,r,z)
00029 #define VGMEMP_TRIM(h,a,s)  VALGRIND_MEMPOOL_TRIM(h,a,s)
00030 #define VGMEMP_ALLOC(h,a,s) VALGRIND_MEMPOOL_ALLOC(h,a,s)
00031 #define VGMEMP_CHANGE(h,a,b,s)     VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
00032 #else
00033 #define       VGMEMP_MARK(m,s)
00034 #define VGMEMP_CREATE(h,r,z)
00035 #define VGMEMP_TRIM(h,a,s)
00036 #define VGMEMP_ALLOC(h,a,s)
00037 #define VGMEMP_CHANGE(h,a,b,s)
00038 #endif
00039 
00040 /*
00041  * This allocator returns temporary memory from a slab in a given memory
00042  * context, aligned on a 2-int boundary.  It cannot be used for data
00043  * which will outlive the task allocating it.
00044  *
00045  * A new memory context attaches to the creator's thread context, if any.
00046  * Threads cannot use other threads' memory contexts; there are no locks.
00047  *
00048  * The caller of slap_sl_malloc, usually a thread pool task, must
00049  * slap_sl_free the memory before finishing: New tasks reuse the context
00050  * and normally reset it, reclaiming memory left over from last task.
00051  *
00052  * The allocator helps memory fragmentation, speed and memory leaks.
00053  * It is not (yet) reliable as a garbage collector:
00054  *
00055  * It falls back to context NULL - plain ber_memalloc() - when the
00056  * context's slab is full.  A reset does not reclaim such memory.
00057  * Conversely, free/realloc of data not from the given context assumes
00058  * context NULL.  The data must not belong to another memory context.
00059  *
00060  * Code which has lost track of the current memory context can try
00061  * slap_sl_context() or ch_malloc.c:ch_free/ch_realloc().
00062  *
00063  * Allocations cannot yet return failure.  Like ch_malloc, they succeed
00064  * or abort slapd.  This will change, do fix code which assumes success.
00065  */
00066 
00067 /*
00068  * The stack-based allocator stores (ber_len_t)sizeof(head+block) at
00069  * allocated blocks' head - and in freed blocks also at the tail, marked
00070  * by ORing *next* block's head with 1.  Freed blocks are only reclaimed
00071  * from the last block forward.  This is fast, but when a block is never
00072  * freed, older blocks will not be reclaimed until the slab is reset...
00073  */
00074 
00075 #ifdef SLAP_NO_SL_MALLOC /* Useful with memory debuggers like Valgrind */
00076 enum { No_sl_malloc = 1 };
00077 #else
00078 enum { No_sl_malloc = 0 };
00079 #endif
00080 
00081 #define SLAP_SLAB_SOBLOCK 64
00082 
00083 struct slab_object {
00084     void *so_ptr;
00085        int so_blockhead;
00086     LDAP_LIST_ENTRY(slab_object) so_link;
00087 };
00088 
00089 struct slab_heap {
00090     void *sh_base;
00091     void *sh_last;
00092     void *sh_end;
00093        int sh_stack;
00094        int sh_maxorder;
00095     unsigned char **sh_map;
00096     LDAP_LIST_HEAD(sh_freelist, slab_object) *sh_free;
00097        LDAP_LIST_HEAD(sh_so, slab_object) sh_sopool;
00098 };
00099 
00100 enum {
00101        Align = sizeof(ber_len_t) > 2*sizeof(int)
00102               ? sizeof(ber_len_t) : 2*sizeof(int),
00103        Align_log2 = 1 + (Align>2) + (Align>4) + (Align>8) + (Align>16),
00104        order_start = Align_log2 - 1,
00105        pad = Align - 1
00106 };
00107 
00108 static struct slab_object * slap_replenish_sopool(struct slab_heap* sh);
00109 #ifdef SLAPD_UNUSED
00110 static void print_slheap(int level, void *ctx);
00111 #endif
00112 
00113 /* Keep memory context in a thread-local var, or in a global when no threads */
00114 #ifdef NO_THREADS
00115 static struct slab_heap *slheap;
00116 # define SET_MEMCTX(thrctx, memctx, sfree)       ((void) (slheap = (memctx)))
00117 # define GET_MEMCTX(thrctx, memctxp)             (*(memctxp) = slheap)
00118 #else
00119 # define memctx_key ((void *) slap_sl_mem_init)
00120 # define SET_MEMCTX(thrctx, memctx, kfree) \
00121        ldap_pvt_thread_pool_setkey(thrctx,memctx_key, memctx,kfree, NULL,NULL)
00122 # define GET_MEMCTX(thrctx, memctxp) \
00123        ((void) (*(memctxp) = NULL), \
00124         (void) ldap_pvt_thread_pool_getkey(thrctx,memctx_key, memctxp,NULL), \
00125         *(memctxp))
00126 #endif /* NO_THREADS */
00127 
00128 
00129 /* Destroy the context, or if key==NULL clean it up for reuse. */
00130 void
00131 slap_sl_mem_destroy(
00132        void *key,
00133        void *data
00134 )
00135 {
00136        struct slab_heap *sh = data;
00137        struct slab_object *so;
00138        int i;
00139 
00140        if (!sh->sh_stack) {
00141               for (i = 0; i <= sh->sh_maxorder - order_start; i++) {
00142                      so = LDAP_LIST_FIRST(&sh->sh_free[i]);
00143                      while (so) {
00144                             struct slab_object *so_tmp = so;
00145                             so = LDAP_LIST_NEXT(so, so_link);
00146                             LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link);
00147                      }
00148                      ch_free(sh->sh_map[i]);
00149               }
00150               ch_free(sh->sh_free);
00151               ch_free(sh->sh_map);
00152 
00153               so = LDAP_LIST_FIRST(&sh->sh_sopool);
00154               while (so) {
00155                      struct slab_object *so_tmp = so;
00156                      so = LDAP_LIST_NEXT(so, so_link);
00157                      if (!so_tmp->so_blockhead) {
00158                             LDAP_LIST_REMOVE(so_tmp, so_link);
00159                      }
00160               }
00161               so = LDAP_LIST_FIRST(&sh->sh_sopool);
00162               while (so) {
00163                      struct slab_object *so_tmp = so;
00164                      so = LDAP_LIST_NEXT(so, so_link);
00165                      ch_free(so_tmp);
00166               }
00167        }
00168 
00169        if (key != NULL) {
00170               ber_memfree_x(sh->sh_base, NULL);
00171               ber_memfree_x(sh, NULL);
00172        }
00173 }
00174 
00175 BerMemoryFunctions slap_sl_mfuncs =
00176        { slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free };
00177 
00178 void
00179 slap_sl_mem_init()
00180 {
00181        assert( Align == 1 << Align_log2 );
00182 
00183        ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs );
00184 }
00185 
00186 /* Create, reset or just return the memory context of the current thread. */
00187 void *
00188 slap_sl_mem_create(
00189        ber_len_t size,
00190        int stack,
00191        void *thrctx,
00192        int new
00193 )
00194 {
00195        void *memctx;
00196        struct slab_heap *sh;
00197        ber_len_t size_shift;
00198        struct slab_object *so;
00199        char *base, *newptr;
00200        enum { Base_offset = (unsigned) -sizeof(ber_len_t) % Align };
00201 
00202        sh = GET_MEMCTX(thrctx, &memctx);
00203        if ( sh && !new )
00204               return sh;
00205 
00206        /* Round up to doubleword boundary, then make room for initial
00207         * padding, preserving expected available size for pool version */
00208        size = ((size + Align-1) & -Align) + Base_offset;
00209 
00210        if (!sh) {
00211               sh = ch_malloc(sizeof(struct slab_heap));
00212               base = ch_malloc(size);
00213               SET_MEMCTX(thrctx, sh, slap_sl_mem_destroy);
00214               VGMEMP_MARK(base, size);
00215               VGMEMP_CREATE(sh, 0, 0);
00216        } else {
00217               slap_sl_mem_destroy(NULL, sh);
00218               base = sh->sh_base;
00219               if (size > (ber_len_t) ((char *) sh->sh_end - base)) {
00220                      newptr = ch_realloc(base, size);
00221                      if ( newptr == NULL ) return NULL;
00222                      VGMEMP_CHANGE(sh, base, newptr, size);
00223                      base = newptr;
00224               }
00225               VGMEMP_TRIM(sh, base, 0);
00226        }
00227        sh->sh_base = base;
00228        sh->sh_end = base + size;
00229 
00230        /* Align (base + head of first block) == first returned block */
00231        base += Base_offset;
00232        size -= Base_offset;
00233 
00234        sh->sh_stack = stack;
00235        if (stack) {
00236               sh->sh_last = base;
00237 
00238        } else {
00239               int i, order = -1, order_end = -1;
00240 
00241               size_shift = size - 1;
00242               do {
00243                      order_end++;
00244               } while (size_shift >>= 1);
00245               order = order_end - order_start + 1;
00246               sh->sh_maxorder = order_end;
00247 
00248               sh->sh_free = (struct sh_freelist *)
00249                                           ch_malloc(order * sizeof(struct sh_freelist));
00250               for (i = 0; i < order; i++) {
00251                      LDAP_LIST_INIT(&sh->sh_free[i]);
00252               }
00253 
00254               LDAP_LIST_INIT(&sh->sh_sopool);
00255 
00256               if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
00257                      slap_replenish_sopool(sh);
00258               }
00259               so = LDAP_LIST_FIRST(&sh->sh_sopool);
00260               LDAP_LIST_REMOVE(so, so_link);
00261               so->so_ptr = base;
00262 
00263               LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link);
00264 
00265               sh->sh_map = (unsigned char **)
00266                                    ch_malloc(order * sizeof(unsigned char *));
00267               for (i = 0; i < order; i++) {
00268                      int shiftamt = order_start + 1 + i;
00269                      int nummaps = size >> shiftamt;
00270                      assert(nummaps);
00271                      nummaps >>= 3;
00272                      if (!nummaps) nummaps = 1;
00273                      sh->sh_map[i] = (unsigned char *) ch_malloc(nummaps);
00274                      memset(sh->sh_map[i], 0, nummaps);
00275               }
00276        }
00277 
00278        return sh;
00279 }
00280 
00281 /*
00282  * Separate memory context from thread context.  Future users must
00283  * know the context, since ch_free/slap_sl_context() cannot find it.
00284  */
00285 void
00286 slap_sl_mem_detach(
00287        void *thrctx,
00288        void *memctx
00289 )
00290 {
00291        SET_MEMCTX(thrctx, NULL, 0);
00292 }
00293 
00294 void *
00295 slap_sl_malloc(
00296     ber_len_t size,
00297     void *ctx
00298 )
00299 {
00300        struct slab_heap *sh = ctx;
00301        ber_len_t *ptr, *newptr;
00302 
00303        /* ber_set_option calls us like this */
00304        if (No_sl_malloc || !ctx) {
00305               newptr = ber_memalloc_x( size, NULL );
00306               if ( newptr ) return newptr;
00307               Debug(LDAP_DEBUG_ANY, "slap_sl_malloc of %lu bytes failed\n",
00308                      (unsigned long) size, 0, 0);
00309               assert( 0 );
00310               exit( EXIT_FAILURE );
00311        }
00312 
00313        /* Add room for head, ensure room for tail when freed, and
00314         * round up to doubleword boundary. */
00315        size = (size + sizeof(ber_len_t) + Align-1 + !size) & -Align;
00316 
00317        if (sh->sh_stack) {
00318               if (size < (ber_len_t) ((char *) sh->sh_end - (char *) sh->sh_last)) {
00319                      newptr = sh->sh_last;
00320                      sh->sh_last = (char *) sh->sh_last + size;
00321                      VGMEMP_ALLOC(sh, newptr, size);
00322                      *newptr++ = size;
00323                      return( (void *)newptr );
00324               }
00325 
00326               size -= sizeof(ber_len_t);
00327 
00328        } else {
00329               struct slab_object *so_new, *so_left, *so_right;
00330               ber_len_t size_shift;
00331               unsigned long diff;
00332               int i, j, order = -1;
00333 
00334               size_shift = size - 1;
00335               do {
00336                      order++;
00337               } while (size_shift >>= 1);
00338 
00339               size -= sizeof(ber_len_t);
00340 
00341               for (i = order; i <= sh->sh_maxorder &&
00342                             LDAP_LIST_EMPTY(&sh->sh_free[i-order_start]); i++);
00343 
00344               if (i == order) {
00345                      so_new = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
00346                      LDAP_LIST_REMOVE(so_new, so_link);
00347                      ptr = so_new->so_ptr;
00348                      diff = (unsigned long)((char*)ptr -
00349                                    (char*)sh->sh_base) >> (order + 1);
00350                      sh->sh_map[order-order_start][diff>>3] |= (1 << (diff & 0x7));
00351                      *ptr++ = size;
00352                      LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_new, so_link);
00353                      return((void*)ptr);
00354               } else if (i <= sh->sh_maxorder) {
00355                      for (j = i; j > order; j--) {
00356                             so_left = LDAP_LIST_FIRST(&sh->sh_free[j-order_start]);
00357                             LDAP_LIST_REMOVE(so_left, so_link);
00358                             if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
00359                                    slap_replenish_sopool(sh);
00360                             }
00361                             so_right = LDAP_LIST_FIRST(&sh->sh_sopool);
00362                             LDAP_LIST_REMOVE(so_right, so_link);
00363                             so_right->so_ptr = (void *)((char *)so_left->so_ptr + (1 << j));
00364                             if (j == order + 1) {
00365                                    ptr = so_left->so_ptr;
00366                                    diff = (unsigned long)((char*)ptr -
00367                                                  (char*)sh->sh_base) >> (order+1);
00368                                    sh->sh_map[order-order_start][diff>>3] |=
00369                                                  (1 << (diff & 0x7));
00370                                    *ptr++ = size;
00371                                    LDAP_LIST_INSERT_HEAD(
00372                                                  &sh->sh_free[j-1-order_start], so_right, so_link);
00373                                    LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_left, so_link);
00374                                    return((void*)ptr);
00375                             } else {
00376                                    LDAP_LIST_INSERT_HEAD(
00377                                                  &sh->sh_free[j-1-order_start], so_right, so_link);
00378                                    LDAP_LIST_INSERT_HEAD(
00379                                                  &sh->sh_free[j-1-order_start], so_left, so_link);
00380                             }
00381                      }
00382               }
00383               /* FIXME: missing return; guessing we failed... */
00384        }
00385 
00386        Debug(LDAP_DEBUG_TRACE,
00387               "sl_malloc %lu: ch_malloc\n",
00388               (unsigned long) size, 0, 0);
00389        return ch_malloc(size);
00390 }
00391 
00392 #define LIM_SQRT(t) /* some value < sqrt(max value of unsigned type t) */ \
00393        ((0UL|(t)-1) >>31>>31 > 1 ? ((t)1 <<32) - 1 : \
00394         (0UL|(t)-1) >>31 ? 65535U : (0UL|(t)-1) >>15 ? 255U : 15U)
00395 
00396 void *
00397 slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
00398 {
00399        void *newptr;
00400        ber_len_t total = n * size;
00401 
00402        /* The sqrt test is a slight optimization: often avoids the division */
00403        if ((n | size) <= LIM_SQRT(ber_len_t) || n == 0 || total/n == size) {
00404               newptr = slap_sl_malloc( total, ctx );
00405               memset( newptr, 0, n*size );
00406        } else {
00407               Debug(LDAP_DEBUG_ANY, "slap_sl_calloc(%lu,%lu) out of range\n",
00408                      (unsigned long) n, (unsigned long) size, 0);
00409               assert(0);
00410               exit(EXIT_FAILURE);
00411        }
00412        return newptr;
00413 }
00414 
00415 void *
00416 slap_sl_realloc(void *ptr, ber_len_t size, void *ctx)
00417 {
00418        struct slab_heap *sh = ctx;
00419        ber_len_t oldsize, *p = (ber_len_t *) ptr, *nextp;
00420        void *newptr;
00421 
00422        if (ptr == NULL)
00423               return slap_sl_malloc(size, ctx);
00424 
00425        /* Not our memory? */
00426        if (No_sl_malloc || !sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
00427               /* Like ch_realloc(), except not trying a new context */
00428               newptr = ber_memrealloc_x(ptr, size, NULL);
00429               if (newptr) {
00430                      return newptr;
00431               }
00432               Debug(LDAP_DEBUG_ANY, "slap_sl_realloc of %lu bytes failed\n",
00433                      (unsigned long) size, 0, 0);
00434               assert(0);
00435               exit( EXIT_FAILURE );
00436        }
00437 
00438        if (size == 0) {
00439               slap_sl_free(ptr, ctx);
00440               return NULL;
00441        }
00442 
00443        oldsize = p[-1];
00444 
00445        if (sh->sh_stack) {
00446               /* Add room for head, round up to doubleword boundary */
00447               size = (size + sizeof(ber_len_t) + Align-1) & -Align;
00448 
00449               p--;
00450 
00451               /* Never shrink blocks */
00452               if (size <= oldsize) {
00453                      return ptr;
00454               }
00455        
00456               oldsize &= -2;
00457               nextp = (ber_len_t *) ((char *) p + oldsize);
00458 
00459               /* If reallocing the last block, try to grow it */
00460               if (nextp == sh->sh_last) {
00461                      if (size < (ber_len_t) ((char *) sh->sh_end - (char *) p)) {
00462                             sh->sh_last = (char *) p + size;
00463                             p[0] = (p[0] & 1) | size;
00464                             return ptr;
00465                      }
00466 
00467               /* Nowhere to grow, need to alloc and copy */
00468               } else {
00469                      /* Slight optimization of the final realloc variant */
00470                      newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx);
00471                      AC_MEMCPY(newptr, ptr, oldsize-sizeof(ber_len_t));
00472                      /* Not last block, can just mark old region as free */
00473                      nextp[-1] = oldsize;
00474                      nextp[0] |= 1;
00475                      return newptr;
00476               }
00477 
00478               size -= sizeof(ber_len_t);
00479               oldsize -= sizeof(ber_len_t);
00480 
00481        } else if (oldsize > size) {
00482               oldsize = size;
00483        }
00484 
00485        newptr = slap_sl_malloc(size, ctx);
00486        AC_MEMCPY(newptr, ptr, oldsize);
00487        slap_sl_free(ptr, ctx);
00488        return newptr;
00489 }
00490 
00491 void
00492 slap_sl_free(void *ptr, void *ctx)
00493 {
00494        struct slab_heap *sh = ctx;
00495        ber_len_t size;
00496        ber_len_t *p = ptr, *nextp, *tmpp;
00497 
00498        if (!ptr)
00499               return;
00500 
00501        if (No_sl_malloc || !sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
00502               ber_memfree_x(ptr, NULL);
00503               return;
00504        }
00505 
00506        size = *(--p);
00507 
00508        if (sh->sh_stack) {
00509               size &= -2;
00510               nextp = (ber_len_t *) ((char *) p + size);
00511               if (sh->sh_last != nextp) {
00512                      /* Mark it free: tail = size, head of next block |= 1 */
00513                      nextp[-1] = size;
00514                      nextp[0] |= 1;
00515                      /* We can't tell Valgrind about it yet, because we
00516                       * still need read/write access to this block for
00517                       * when we eventually get to reclaim it.
00518                       */
00519               } else {
00520                      /* Reclaim freed block(s) off tail */
00521                      while (*p & 1) {
00522                             p = (ber_len_t *) ((char *) p - p[-1]);
00523                      }
00524                      sh->sh_last = p;
00525                      VGMEMP_TRIM(sh, sh->sh_base,
00526                             (char *) sh->sh_last - (char *) sh->sh_base);
00527               }
00528 
00529        } else {
00530               int size_shift, order_size;
00531               struct slab_object *so;
00532               unsigned long diff;
00533               int i, inserted = 0, order = -1;
00534 
00535               size_shift = size + sizeof(ber_len_t) - 1;
00536               do {
00537                      order++;
00538               } while (size_shift >>= 1);
00539 
00540               for (i = order, tmpp = p; i <= sh->sh_maxorder; i++) {
00541                      order_size = 1 << (i+1);
00542                      diff = (unsigned long)((char*)tmpp - (char*)sh->sh_base) >> (i+1);
00543                      sh->sh_map[i-order_start][diff>>3] &= (~(1 << (diff & 0x7)));
00544                      if (diff == ((diff>>1)<<1)) {
00545                             if (!(sh->sh_map[i-order_start][(diff+1)>>3] &
00546                                           (1<<((diff+1)&0x7)))) {
00547                                    so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
00548                                    while (so) {
00549                                           if ((char*)so->so_ptr == (char*)tmpp) {
00550                                                  LDAP_LIST_REMOVE( so, so_link );
00551                                           } else if ((char*)so->so_ptr ==
00552                                                         (char*)tmpp + order_size) {
00553                                                  LDAP_LIST_REMOVE(so, so_link);
00554                                                  break;
00555                                           }
00556                                           so = LDAP_LIST_NEXT(so, so_link);
00557                                    }
00558                                    if (so) {
00559                                           if (i < sh->sh_maxorder) {
00560                                                  inserted = 1;
00561                                                  so->so_ptr = tmpp;
00562                                                  LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1],
00563                                                                so, so_link);
00564                                           }
00565                                           continue;
00566                                    } else {
00567                                           if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
00568                                                  slap_replenish_sopool(sh);
00569                                           }
00570                                           so = LDAP_LIST_FIRST(&sh->sh_sopool);
00571                                           LDAP_LIST_REMOVE(so, so_link);
00572                                           so->so_ptr = tmpp;
00573                                           LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
00574                                                         so, so_link);
00575                                           break;
00576 
00577                                           Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
00578                                                  "free object not found while bit is clear.\n",
00579                                                  0, 0, 0);
00580                                           assert(so != NULL);
00581 
00582                                    }
00583                             } else {
00584                                    if (!inserted) {
00585                                           if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
00586                                                  slap_replenish_sopool(sh);
00587                                           }
00588                                           so = LDAP_LIST_FIRST(&sh->sh_sopool);
00589                                           LDAP_LIST_REMOVE(so, so_link);
00590                                           so->so_ptr = tmpp;
00591                                           LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
00592                                                         so, so_link);
00593                                    }
00594                                    break;
00595                             }
00596                      } else {
00597                             if (!(sh->sh_map[i-order_start][(diff-1)>>3] &
00598                                           (1<<((diff-1)&0x7)))) {
00599                                    so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
00600                                    while (so) {
00601                                           if ((char*)so->so_ptr == (char*)tmpp) {
00602                                                  LDAP_LIST_REMOVE(so, so_link);
00603                                           } else if ((char*)tmpp == (char *)so->so_ptr + order_size) {
00604                                                  LDAP_LIST_REMOVE(so, so_link);
00605                                                  tmpp = so->so_ptr;
00606                                                  break;
00607                                           }
00608                                           so = LDAP_LIST_NEXT(so, so_link);
00609                                    }
00610                                    if (so) {
00611                                           if (i < sh->sh_maxorder) {
00612                                                  inserted = 1;
00613                                                  LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1],                                                            so, so_link);
00614                                                  continue;
00615                                           }
00616                                    } else {
00617                                           if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
00618                                                  slap_replenish_sopool(sh);
00619                                           }
00620                                           so = LDAP_LIST_FIRST(&sh->sh_sopool);
00621                                           LDAP_LIST_REMOVE(so, so_link);
00622                                           so->so_ptr = tmpp;
00623                                           LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
00624                                                         so, so_link);
00625                                           break;
00626 
00627                                           Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
00628                                                  "free object not found while bit is clear.\n",
00629                                                  0, 0, 0 );
00630                                           assert(so != NULL);
00631 
00632                                    }
00633                             } else {
00634                                    if ( !inserted ) {
00635                                           if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
00636                                                  slap_replenish_sopool(sh);
00637                                           }
00638                                           so = LDAP_LIST_FIRST(&sh->sh_sopool);
00639                                           LDAP_LIST_REMOVE(so, so_link);
00640                                           so->so_ptr = tmpp;
00641                                           LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
00642                                                         so, so_link);
00643                                    }
00644                                    break;
00645                             }
00646                      }
00647               }
00648        }
00649 }
00650 
00651 /*
00652  * Return the memory context of the current thread if the given block of
00653  * memory belongs to it, otherwise return NULL.
00654  */
00655 void *
00656 slap_sl_context( void *ptr )
00657 {
00658        void *memctx;
00659        struct slab_heap *sh;
00660 
00661        if ( slapMode & SLAP_TOOL_MODE ) return NULL;
00662 
00663        sh = GET_MEMCTX(ldap_pvt_thread_pool_context(), &memctx);
00664        if (sh && ptr >= sh->sh_base && ptr <= sh->sh_end) {
00665               return sh;
00666        }
00667        return NULL;
00668 }
00669 
00670 static struct slab_object *
00671 slap_replenish_sopool(
00672     struct slab_heap* sh
00673 )
00674 {
00675     struct slab_object *so_block;
00676     int i;
00677 
00678     so_block = (struct slab_object *)ch_malloc(
00679                     SLAP_SLAB_SOBLOCK * sizeof(struct slab_object));
00680 
00681     if ( so_block == NULL ) {
00682         return NULL;
00683     }
00684 
00685     so_block[0].so_blockhead = 1;
00686     LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link);
00687     for (i = 1; i < SLAP_SLAB_SOBLOCK; i++) {
00688         so_block[i].so_blockhead = 0;
00689         LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[i], so_link );
00690     }
00691 
00692     return so_block;
00693 }
00694 
00695 #ifdef SLAPD_UNUSED
00696 static void
00697 print_slheap(int level, void *ctx)
00698 {
00699        struct slab_heap *sh = ctx;
00700        struct slab_object *so;
00701        int i, j, once = 0;
00702 
00703        if (!ctx) {
00704               Debug(level, "NULL memctx\n", 0, 0, 0);
00705               return;
00706        }
00707 
00708        Debug(level, "sh->sh_maxorder=%d\n", sh->sh_maxorder, 0, 0);
00709 
00710        for (i = order_start; i <= sh->sh_maxorder; i++) {
00711               once = 0;
00712               Debug(level, "order=%d\n", i, 0, 0);
00713               for (j = 0; j < (1<<(sh->sh_maxorder-i))/8; j++) {
00714                      Debug(level, "%02x ", sh->sh_map[i-order_start][j], 0, 0);
00715                      once = 1;
00716               }
00717               if (!once) {
00718                      Debug(level, "%02x ", sh->sh_map[i-order_start][0], 0, 0);
00719               }
00720               Debug(level, "\n", 0, 0, 0);
00721               Debug(level, "free list:\n", 0, 0, 0);
00722               so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
00723               while (so) {
00724                      Debug(level, "%p\n", so->so_ptr, 0, 0);
00725                      so = LDAP_LIST_NEXT(so, so_link);
00726               }
00727        }
00728 }
00729 #endif