X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fsl_malloc.c;h=b4e0ac614680e6d91cc887e7baa55e8aef32998b;hb=68ab1a2272b21d43d14db7e5dfe9cef3345b1310;hp=ae1581888835faf78829778521f2226f82d0338f;hpb=6f182a754712cdecc7e824bc6b64465de31e864a;p=openldap diff --git a/servers/slapd/sl_malloc.c b/servers/slapd/sl_malloc.c index ae15818888..b4e0ac6146 100644 --- a/servers/slapd/sl_malloc.c +++ b/servers/slapd/sl_malloc.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2003-2004 The OpenLDAP Foundation. + * Copyright 2003-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,10 @@ #include "slap.h" +static struct slab_object * slap_replenish_sopool(struct slab_heap* sh); +#ifdef SLAPD_UNUSED static void print_slheap(int level, void *ctx); +#endif void slap_sl_mem_destroy( @@ -87,27 +90,41 @@ slap_sl_mem_init() static struct slab_heap *slheap; #endif +/* This allocator always returns memory aligned on a 2-int boundary. + * + * The stack-based allocator stores the size as a ber_len_t at both + * the head and tail of the allocated block. When freeing a block, the + * tail length is ORed with 1 to mark it as free. Freed space can only + * be reclaimed from the tail forward. If the tail block is never freed, + * nothing else will be reclaimed until the slab is reset... + */ void * slap_sl_mem_create( ber_len_t size, int stack, - void *ctx + void *ctx, + int new ) { - struct slab_heap *sh = NULL; + struct slab_heap *sh; ber_len_t size_shift; int pad = 2*sizeof(int)-1, pad_shift; int order = -1, order_start = -1, order_end = -1; - int i, k; - struct slab_object *so, *so_block; + int i; + struct slab_object *so; #ifdef NO_THREADS sh = slheap; #else + void *sh_tmp = NULL; ldap_pvt_thread_pool_getkey( - ctx, (void *)slap_sl_mem_init, (void **)&sh, NULL ); + ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL ); + sh = sh_tmp; #endif + if ( sh && !new ) + return sh; + /* round up to doubleword boundary */ size += pad; size &= ~pad; @@ -120,12 +137,21 @@ slap_sl_mem_create( slheap = sh; #else ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init, - (void *)sh, slap_sl_mem_destroy); + (void *)sh, slap_sl_mem_destroy, NULL, NULL); #endif } else if ( size > (char *)sh->sh_end - (char *)sh->sh_base ) { - sh->sh_base = ch_realloc(sh->sh_base, size); + void *newptr; + + newptr = ch_realloc( sh->sh_base, size ); + if ( newptr == NULL ) return NULL; + sh->sh_base = newptr; + } + /* insert dummy len */ + { + ber_len_t *i = sh->sh_base; + *i++ = 0; + sh->sh_last = i; } - sh->sh_last = sh->sh_base; sh->sh_end = (char *) sh->sh_base + size; sh->sh_stack = stack; return sh; @@ -149,7 +175,7 @@ slap_sl_mem_create( slheap = sh; #else ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init, - (void *)sh, slap_sl_mem_destroy); + (void *)sh, slap_sl_mem_destroy, NULL, NULL); #endif } else { for (i = 0; i <= sh->sh_maxorder - order_start; i++) { @@ -180,7 +206,11 @@ slap_sl_mem_create( } if (size > (char *)sh->sh_end - (char *)sh->sh_base) { - sh->sh_base = realloc(sh->sh_base, size); + void *newptr; + + newptr = ch_realloc( sh->sh_base, size ); + if ( newptr == NULL ) return NULL; + sh->sh_base = newptr; } } sh->sh_end = (char *)sh->sh_base + size; @@ -195,31 +225,24 @@ slap_sl_mem_create( LDAP_LIST_INIT(&sh->sh_sopool); if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { - so_block = (struct slab_object *)ch_malloc( - SLAP_SLAB_SOBLOCK * sizeof( struct slab_object)); - so_block[0].so_blockhead = 1; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link); - for (k = 1; k < SLAP_SLAB_SOBLOCK; k++) { - so_block[k].so_blockhead = 0; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[k], so_link); - } - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = sh->sh_base; - } else { - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = sh->sh_base; + slap_replenish_sopool(sh); } + so = LDAP_LIST_FIRST(&sh->sh_sopool); + LDAP_LIST_REMOVE(so, so_link); + so->so_ptr = sh->sh_base; LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link); sh->sh_map = (unsigned char **) - ch_malloc(order * sizeof(unsigned long *)); + ch_malloc(order * sizeof(unsigned char *)); for (i = 0; i < order; i++) { - sh->sh_map[i] = (unsigned char *) - ch_malloc(size >> (1 << (order_start + i + 3))); - memset(sh->sh_map[i], 0, size >> (1 << (order_start + i + 3))); + int shiftamt = order_start + 1 + i; + int nummaps = size >> shiftamt; + assert(nummaps); + nummaps >>= 3; + if (!nummaps) nummaps = 1; + sh->sh_map[i] = (unsigned char *) ch_malloc(nummaps); + memset(sh->sh_map[i], 0, nummaps); } sh->sh_stack = stack; return sh; @@ -236,7 +259,8 @@ slap_sl_mem_detach( slheap = NULL; #else /* separate from context */ - ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init, NULL, NULL ); + ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init, + NULL, 0, NULL, NULL ); #endif } @@ -247,21 +271,26 @@ slap_sl_malloc( ) { struct slab_heap *sh = ctx; - int size_shift; int pad = 2*sizeof(int)-1, pad_shift; - int order = -1, order_start = -1; - struct slab_object *so_new, *so_left, *so_right, *so_block; - ber_len_t *ptr, *new; - unsigned long diff; - int i, j, k; + ber_len_t *ptr, *newptr; - /* ber_set_option calls us like this */ - if (!ctx) return ber_memalloc_x(size, NULL); +#ifdef SLAP_NO_SL_MALLOC + newptr = ber_memalloc_x( size, NULL ); + if ( newptr ) return newptr; + assert( 0 ); + exit( EXIT_FAILURE ); +#endif - Debug(LDAP_DEBUG_ANY, "slap_sl_malloc (%d)\n", size, 0, 0); + /* ber_set_option calls us like this */ + if (!ctx) { + newptr = ber_memalloc_x( size, NULL ); + if ( newptr ) return newptr; + assert( 0 ); + exit( EXIT_FAILURE ); + } - /* round up to doubleword boundary */ - size += pad + sizeof(ber_len_t); + /* round up to doubleword boundary, plus space for len at head and tail */ + size += 2*sizeof(ber_len_t) + pad; size &= ~pad; if (sh->sh_stack) { @@ -271,11 +300,19 @@ slap_sl_malloc( (long)size, 0, 0); return ch_malloc(size); } - new = sh->sh_last; - *new++ = size - sizeof(ber_len_t); + newptr = sh->sh_last; sh->sh_last = (char *) sh->sh_last + size; - return( (void *)new ); + size -= sizeof(ber_len_t); + *newptr++ = size; + *(ber_len_t *)((char *)sh->sh_last - sizeof(ber_len_t)) = size; + return( (void *)newptr ); } else { + struct slab_object *so_new, *so_left, *so_right; + ber_len_t size_shift; + int order = -1, order_start = -1; + unsigned long diff; + int i, j; + size_shift = size - 1; do { order++; @@ -304,24 +341,11 @@ slap_sl_malloc( so_left = LDAP_LIST_FIRST(&sh->sh_free[j-order_start]); LDAP_LIST_REMOVE(so_left, so_link); if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { - so_block = (struct slab_object *)ch_malloc( - SLAP_SLAB_SOBLOCK * sizeof(struct slab_object)); - so_block[0].so_blockhead = 1; - LDAP_LIST_INSERT_HEAD( - &sh->sh_sopool, &so_block[0], so_link); - for (k = 1; k < SLAP_SLAB_SOBLOCK; k++) { - so_block[k].so_blockhead = 0; - LDAP_LIST_INSERT_HEAD( - &sh->sh_sopool, &so_block[k], so_link); - } - so_right = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so_right, so_link); - so_right->so_ptr = so_left->so_ptr + (1 << j); - } else { - so_right = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so_right, so_link); - so_right->so_ptr = so_left->so_ptr + (1 << j); + slap_replenish_sopool(sh); } + so_right = LDAP_LIST_FIRST(&sh->sh_sopool); + LDAP_LIST_REMOVE(so_right, so_link); + so_right->so_ptr = (void *)((char *)so_left->so_ptr + (1 << j)); if (j == order + 1) { ptr = so_left->so_ptr; diff = (unsigned long)((char*)ptr - @@ -347,40 +371,46 @@ slap_sl_malloc( return (void*)ch_malloc(size); } } + + /* FIXME: missing return; guessing... */ + return NULL; } void * slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx ) { - void *new; + void *newptr; - new = slap_sl_malloc( n*size, ctx ); - if ( new ) { - memset( new, 0, n*size ); + newptr = slap_sl_malloc( n*size, ctx ); + if ( newptr ) { + memset( newptr, 0, n*size ); } - return new; + return newptr; } void * slap_sl_realloc(void *ptr, ber_len_t size, void *ctx) { struct slab_heap *sh = ctx; - int size_shift; - int pad = 2*sizeof(int)-1, pad_shift; - int order_start = -1, order = -1; - struct slab_object *so; - ber_len_t *p = (ber_len_t *)ptr, *new; - unsigned long diff; + int pad = 2*sizeof(int) -1; + ber_len_t *p = (ber_len_t *)ptr, *newptr; if (ptr == NULL) return slap_sl_malloc(size, ctx); +#ifdef SLAP_NO_SL_MALLOC + newptr = ber_memrealloc_x( ptr, size, NULL ); + if ( newptr ) return newptr; + assert( 0 ); + exit( EXIT_FAILURE ); +#endif + /* Not our memory? */ if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) { /* duplicate of realloc behavior, oh well */ - new = ber_memrealloc_x(ptr, size, NULL); - if (new) { - return new; + newptr = ber_memrealloc_x(ptr, size, NULL); + if (newptr) { + return newptr; } Debug(LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n", (long) size, 0, 0); @@ -394,32 +424,43 @@ slap_sl_realloc(void *ptr, ber_len_t size, void *ctx) } if (sh->sh_stack) { + /* round up to doubleword boundary */ + size += pad + sizeof( ber_len_t ); + size &= ~pad; + + p--; + /* Never shrink blocks */ - if (size <= p[-1]) { - new = p; + if (size <= p[0]) { + newptr = ptr; /* If reallocing the last block, we can grow it */ - } else if ((char *)ptr + p[-1] == sh->sh_last) { - new = p; - sh->sh_last = (char *)sh->sh_last + size - p[-1]; - p[-1] = size; - + } else if ((char *)ptr + p[0] == sh->sh_last && + (char *)ptr + size < (char *)sh->sh_end ) { + newptr = ptr; + sh->sh_last = (char *)ptr + size; + p[0] = size; + p[size/sizeof(ber_len_t)] = size; + /* Nowhere to grow, need to alloc and copy */ } else { - new = slap_sl_malloc(size, ctx); - AC_MEMCPY(new, ptr, p[-1]); + newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx); + AC_MEMCPY(newptr, ptr, p[0]-sizeof(ber_len_t)); + /* mark old region as free */ + p[p[0]/sizeof(ber_len_t)] |= 1; } - return new; + return newptr; } else { - void *newptr; - newptr = slap_sl_malloc(size, ctx); + void *newptr2; + + newptr2 = slap_sl_malloc(size, ctx); if (size < p[-1]) { - AC_MEMCPY(newptr, ptr, size); + AC_MEMCPY(newptr2, ptr, size); } else { - AC_MEMCPY(newptr, ptr, p[-1]); + AC_MEMCPY(newptr2, ptr, p[-1]); } slap_sl_free(ptr, ctx); - return newptr; + return newptr2; } } @@ -427,22 +468,44 @@ void slap_sl_free(void *ptr, void *ctx) { struct slab_heap *sh = ctx; - int size, size_shift, order_size; - int pad = 2*sizeof(int)-1, pad_shift; + ber_len_t size; ber_len_t *p = (ber_len_t *)ptr, *tmpp; - int order_start = -1, order = -1; - struct slab_object *so, *so_block; - unsigned long diff; - int i, k, inserted = 0; - Debug( LDAP_DEBUG_ANY, "==> slap_sl_free \n", 0, 0, 0); + if (!ptr) + return; + +#ifdef SLAP_NO_SL_MALLOC + ber_memfree_x( ptr, NULL ); + return; +#endif if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) { ber_memfree_x(ptr, NULL); - } else if (sh->sh_stack && (char *)ptr + p[-1] == sh->sh_last) { - p--; - sh->sh_last = p; - } else if (!sh->sh_stack) { + } else if (sh->sh_stack) { + tmpp = (ber_len_t *)((char *)ptr + p[-1]); + /* mark it free */ + tmpp[-1] |= 1; + /* reclaim free space off tail */ + while ( tmpp == sh->sh_last ) { + if ( tmpp[-1] & 1 ) { + size = tmpp[-1] ^ 1; + ptr = (char *)tmpp - size; + p = (ber_len_t *)ptr; + p--; + sh->sh_last = p; + tmpp = sh->sh_last; + } else { + break; + } + } + } else { + int size_shift, order_size; + int pad = 2*sizeof(int)-1, pad_shift; + int order_start = -1, order = -1; + struct slab_object *so; + unsigned long diff; + int i, inserted = 0; + size = *(--p); size_shift = size + sizeof(ber_len_t) - 1; do { @@ -482,57 +545,29 @@ slap_sl_free(void *ptr, void *ctx) continue; } else { if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { - so_block = (struct slab_object *)ch_malloc( - SLAP_SLAB_SOBLOCK * - sizeof( struct slab_object)); - so_block[0].so_blockhead = 1; - LDAP_LIST_INSERT_HEAD( &sh->sh_sopool, - &so_block[0], so_link ); - for ( k = 1; k < SLAP_SLAB_SOBLOCK; k++ ) { - so_block[k].so_blockhead = 0; - LDAP_LIST_INSERT_HEAD( &sh->sh_sopool, - &so_block[k], so_link ); - } - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; - } else { - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; + slap_replenish_sopool(sh); } + so = LDAP_LIST_FIRST(&sh->sh_sopool); + LDAP_LIST_REMOVE(so, so_link); + so->so_ptr = tmpp; LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], so, so_link); break; - Debug(LDAP_DEBUG_ANY, "slap_sl_free: " + Debug(LDAP_DEBUG_TRACE, "slap_sl_free: " "free object not found while bit is clear.\n", 0, 0, 0); - assert(so); + assert(so != NULL); } } else { if (!inserted) { if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { - so_block = (struct slab_object *)ch_malloc( - SLAP_SLAB_SOBLOCK * - sizeof(struct slab_object)); - so_block[0].so_blockhead = 1; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, - &so_block[0], so_link); - for (k = 1; k < SLAP_SLAB_SOBLOCK; k++) { - so_block[k].so_blockhead = 0; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, - &so_block[k], so_link); - } - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; - } else { - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; + slap_replenish_sopool(sh); } + so = LDAP_LIST_FIRST(&sh->sh_sopool); + LDAP_LIST_REMOVE(so, so_link); + so->so_ptr = tmpp; LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], so, so_link); } @@ -545,7 +580,7 @@ slap_sl_free(void *ptr, void *ctx) while (so) { if ((char*)so->so_ptr == (char*)tmpp) { LDAP_LIST_REMOVE(so, so_link); - } else if ((char*)tmpp == so->so_ptr + order_size) { + } else if ((char*)tmpp == (char *)so->so_ptr + order_size) { LDAP_LIST_REMOVE(so, so_link); tmpp = so->so_ptr; break; @@ -560,57 +595,29 @@ slap_sl_free(void *ptr, void *ctx) } } else { if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { - so_block = (struct slab_object *)ch_malloc( - SLAP_SLAB_SOBLOCK * - sizeof(struct slab_object)); - so_block[0].so_blockhead = 1; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, - &so_block[0], so_link); - for (k = 1; k < SLAP_SLAB_SOBLOCK; k++) { - so_block[k].so_blockhead = 0; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, - &so_block[k], so_link ); - } - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; - } else { - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; + slap_replenish_sopool(sh); } + so = LDAP_LIST_FIRST(&sh->sh_sopool); + LDAP_LIST_REMOVE(so, so_link); + so->so_ptr = tmpp; LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], so, so_link); break; - Debug(LDAP_DEBUG_ANY, "slap_sl_free: " + Debug(LDAP_DEBUG_TRACE, "slap_sl_free: " "free object not found while bit is clear.\n", 0, 0, 0 ); - assert( so ); + assert(so != NULL); } } else { if ( !inserted ) { if (LDAP_LIST_EMPTY(&sh->sh_sopool)) { - so_block = (struct slab_object *)ch_malloc( - SLAP_SLAB_SOBLOCK * - sizeof(struct slab_object)); - so_block[0].so_blockhead = 1; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, - &so_block[0], so_link ); - for (k = 1; k < SLAP_SLAB_SOBLOCK; k++) { - so_block[k].so_blockhead = 0; - LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, - &so_block[k], so_link ); - } - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; - } else { - so = LDAP_LIST_FIRST(&sh->sh_sopool); - LDAP_LIST_REMOVE(so, so_link); - so->so_ptr = tmpp; + slap_replenish_sopool(sh); } + so = LDAP_LIST_FIRST(&sh->sh_sopool); + LDAP_LIST_REMOVE(so, so_link); + so->so_ptr = tmpp; LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start], so, so_link); } @@ -624,16 +631,20 @@ slap_sl_free(void *ptr, void *ctx) void * slap_sl_context( void *ptr ) { - struct slab_heap *sh = NULL; - void *ctx; + struct slab_heap *sh; + void *ctx, *sh_tmp; + + if ( slapMode & SLAP_TOOL_MODE ) return NULL; #ifdef NO_THREADS sh = slheap; #else ctx = ldap_pvt_thread_pool_context(); - ldap_pvt_thread_pool_getkey(ctx, (void *)slap_sl_mem_init, - (void **)&sh, NULL); + sh_tmp = NULL; + ldap_pvt_thread_pool_getkey( + ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL); + sh = sh_tmp; #endif if (sh && ptr >= sh->sh_base && ptr <= sh->sh_end) { @@ -642,6 +653,32 @@ slap_sl_context( void *ptr ) return NULL; } +static struct slab_object * +slap_replenish_sopool( + struct slab_heap* sh +) +{ + struct slab_object *so_block; + int i; + + so_block = (struct slab_object *)ch_malloc( + SLAP_SLAB_SOBLOCK * sizeof(struct slab_object)); + + if ( so_block == NULL ) { + return NULL; + } + + so_block[0].so_blockhead = 1; + LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link); + for (i = 1; i < SLAP_SLAB_SOBLOCK; i++) { + so_block[i].so_blockhead = 0; + LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[i], so_link ); + } + + return so_block; +} + +#ifdef SLAPD_UNUSED static void print_slheap(int level, void *ctx) { @@ -677,8 +714,9 @@ print_slheap(int level, void *ctx) Debug(level, "free list:\n", 0, 0, 0); so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]); while (so) { - Debug(level, "%x\n",so->so_ptr, 0, 0); + Debug(level, "%lx\n", (unsigned long) so->so_ptr, 0, 0); so = LDAP_LIST_NEXT(so, so_link); } } } +#endif