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