X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcstack.c;h=79f63d2fc8552242223be51cadbccb5c69d7ff40;hb=a85b69a00898360e6237607a90a263570ad4b3ba;hp=ab5cd62b510a7f4ff32790b85af83fe7f59eabaf;hpb=57497f3b415db66538de5e89bc11f7f5816a39e2;p=silc.git diff --git a/lib/silcutil/silcstack.c b/lib/silcutil/silcstack.c index ab5cd62b..79f63d2f 100644 --- a/lib/silcutil/silcstack.c +++ b/lib/silcutil/silcstack.c @@ -78,7 +78,8 @@ static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack, *ret_si = si; *ret_bsize = bsize; - SILC_ST_DEBUG(("Get stack block, si %d, size %lu", si, bsize)); + SILC_ST_DEBUG(("Get stack block, si %d, size %lu, stack %p", + si, bsize, stack)); silc_mutex_lock(stack->lock); @@ -94,19 +95,22 @@ static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack, return e; } + silc_mutex_unlock(stack->lock); + + /* If we are child, get block from parent */ + if (stack->parent) + return silc_stack_ref_stack(stack->parent, size, ret_si, ret_bsize); + SILC_ST_DEBUG(("Allocate new stack blocks")); /* Allocate new stack blocks */ e = silc_calloc(1, sizeof(*e)); - if (!e) { - silc_mutex_unlock(stack->lock); + if (!e) return NULL; - } e->data[si] = silc_malloc(bsize + SILC_STACK_ALIGN(sizeof(*e->data[0]), stack->alignment)); if (!e->data[si]) { silc_free(e); - silc_mutex_unlock(stack->lock); return NULL; } e->data[si]->bytes_left = bsize; @@ -115,7 +119,6 @@ static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack, SILC_ST_DEBUG(("Got stack blocks %p from stack %p", e->data, stack)); - silc_mutex_unlock(stack->lock); return e; } @@ -174,14 +177,18 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent) if (stack_size < SILC_STACK_DEFAULT_SIZE) stack_size = SILC_STACK_DEFAULT_SIZE; + /* Align by 8 */ + stack_size += ((-stack_size) % 8); + if (parent) { /* Get stack from parent. The stack itself is allocated from the - parent. */ + parent (but does not consume parent's own stack). */ e = silc_stack_ref_stack(parent, stack_size, &si, &bsize); if (!e) return NULL; - /* Allocate stack from the parent */ + /* Allocate stack from the returned stack. We allocate ourselves from + our own stack. */ stack = silc_stack_alloc_block(parent, e, 1, sizeof(*stack)); if (!stack) { silc_stack_unref_stack(parent, e); @@ -193,10 +200,11 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent) stack->alignment = SILC_STACK_DEFAULT_ALIGN; stack->oom_handler = parent->oom_handler; stack->oom_context = parent->oom_context; + stack->lock = parent->lock; silc_list_init(stack->stacks, struct SilcStackDataEntryStruct, next); - /* Allocate stack frames from the parent */ - stack->frames = silc_stack_alloc_block(parent, e, SILC_STACK_BLOCK_NUM, + /* Allocate stack frames from the stack itself */ + stack->frames = silc_stack_alloc_block(stack, e, SILC_STACK_BLOCK_NUM, sizeof(*stack->frames)); if (!stack->frames) { silc_stack_unref_stack(parent, e); @@ -244,10 +252,10 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent) silc_free(stack); return NULL; } - } - /* Allocate lock */ - silc_mutex_alloc(&stack->lock); + /* Allocate lock */ + silc_mutex_alloc(&stack->lock); + } /* Use the allocated stack in first stack frame */ stack->frame = &stack->frames[0]; @@ -273,9 +281,6 @@ void silc_stack_free(SilcStack stack) SILC_LOG_DEBUG(("Free stack %p", stack)); - if (stack->lock) - silc_mutex_free(stack->lock); - if (!stack->parent) { silc_list_start(stack->stacks); while ((e = silc_list_get(stack->stacks))) { @@ -288,6 +293,9 @@ void silc_stack_free(SilcStack stack) silc_free(stack->stack->data[i]); silc_free(stack->stack); + if (stack->lock) + silc_mutex_free(stack->lock); + silc_free(stack); } else { /* Return all stack blocks to the parent */ @@ -367,13 +375,15 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size) SILC_ST_DEBUG(("Allocating %d bytes from %p", size, stack)); if (silc_unlikely(!size)) { - SILC_LOG_ERROR(("Allocation by zero (0)")); + SILC_LOG_DEBUG(("Allocation by zero (0)")); + silc_set_errno_nofail(SILC_ERR_ZERO_ALLOCATION); SILC_STACK_STAT(stack, num_errors, 1); return NULL; } if (silc_unlikely(size > SILC_STACK_MAX_ALLOC)) { - SILC_LOG_ERROR(("Allocating too much")); + SILC_LOG_DEBUG(("Allocating too much")); + silc_set_errno_nofail(SILC_ERR_TOO_LARGE_ALLOCATION); SILC_STACK_STAT(stack, num_errors, 1); if (stack->oom_handler) stack->oom_handler(stack, stack->oom_context); @@ -407,7 +417,8 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size) si++; } if (silc_unlikely(si >= SILC_STACK_BLOCK_NUM)) { - SILC_LOG_ERROR(("Allocating too large block")); + SILC_LOG_DEBUG(("Allocating too large block")); + silc_set_errno_nofail(SILC_ERR_TOO_LARGE_ALLOCATION); SILC_STACK_STAT(stack, num_errors, 1); if (stack->oom_handler) stack->oom_handler(stack, stack->oom_context); @@ -462,13 +473,15 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, SILC_ST_DEBUG(("Reallocating %d bytes (%d) from %p", size, old_size, stack)); if (silc_unlikely(!size || !old_size)) { - SILC_LOG_ERROR(("Allocation by zero (0)")); + SILC_LOG_DEBUG(("Allocation by zero (0)")); + silc_set_errno_nofail(SILC_ERR_ZERO_ALLOCATION); SILC_STACK_STAT(stack, num_errors, 1); return NULL; } if (silc_unlikely(size > SILC_STACK_MAX_ALLOC)) { - SILC_LOG_ERROR(("Allocating too much")); + SILC_LOG_DEBUG(("Allocating too much")); + silc_set_errno_nofail(SILC_ERR_TOO_LARGE_ALLOCATION); SILC_STACK_STAT(stack, num_errors, 1); if (stack->oom_handler) stack->oom_handler(stack, stack->oom_context); @@ -487,6 +500,7 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, if (stack->stack->data[si]->bytes_left + old_size + ((unsigned char *)ptr - (unsigned char *)sptr) != bsize) { SILC_LOG_DEBUG(("Cannot reallocate")); + silc_set_errno_nofail(SILC_ERR_INVALID_ARGUMENT); SILC_STACK_STAT(stack, num_errors, 1); return NULL; } @@ -501,6 +515,8 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size, } SILC_LOG_DEBUG(("Cannot reallocate in this block")); + silc_set_errno_reason_nofail(SILC_ERR_TOO_LARGE_ALLOCATION, + "Cannot reallocate in this memory block"); SILC_STACK_STAT(stack, num_errors, 1); return NULL; } @@ -530,6 +546,63 @@ SilcUInt32 silc_stack_get_alignment(SilcStack stack) return stack->alignment; } +/* Purge stack */ + +SilcBool silc_stack_purge(SilcStack stack) +{ + SilcStackDataEntry e; + SilcBool ret = FALSE; + int i; + + SILC_LOG_DEBUG(("Purge stack %p", stack)); + + /* Go through the default stack */ + for (i = SILC_STACK_BLOCK_NUM - 1; i > 3; i--) { + if (stack->stack->data[i] && + stack->stack->data[i]->bytes_left == SILC_STACK_BLOCK_SIZE(stack, i)) { + SILC_LOG_DEBUG(("Purge %d bytes", + SILC_STACK_BLOCK_SIZE(stack, i))); + silc_free(stack->stack->data[i]); + stack->stack->data[i] = NULL; + ret = TRUE; + } + } + + silc_mutex_lock(stack->lock); + + /* Remove one child stack */ + if (silc_list_count(stack->stacks) > 2) { + silc_list_start(stack->stacks); + e = silc_list_get(stack->stacks); + + SILC_LOG_DEBUG(("Remove stack blocks %p", e->data)); + silc_list_del(stack->stacks, e); + ret = TRUE; + + for (i = 0; i < SILC_STACK_BLOCK_NUM; i++) + silc_free(e->data[i]); + silc_free(e); + } + + /* Go through the child stacks */ + silc_list_start(stack->stacks); + while ((e = silc_list_get(stack->stacks))) { + for (i = SILC_STACK_BLOCK_NUM - 1; i > 3; i--) { + if (e->data[i]) { + SILC_LOG_DEBUG(("Purge %d bytes", + SILC_STACK_BLOCK_SIZE(stack, i))); + silc_free(e->data[i]); + e->data[i] = NULL; + ret = TRUE; + } + } + } + + silc_mutex_unlock(stack->lock); + + return ret; +} + #ifdef SILC_DIST_INPLACE /* Statistics dumping. */