X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcstack.c;h=3fd06d331459680cefa66328ccdb735500c6f866;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=7f179eb4e5c4ca5c7a516985f1ac20445ee5072a;hpb=3d836f704311455db019d48b0666bb11a52a5a88;p=silc.git diff --git a/lib/silcutil/silcstack.c b/lib/silcutil/silcstack.c index 7f179eb4..3fd06d33 100644 --- a/lib/silcutil/silcstack.c +++ b/lib/silcutil/silcstack.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 - 2007 Pekka Riikonen + Copyright (C) 2003 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,10 +24,13 @@ /* The SilcStack context */ struct SilcStackStruct { SilcStack parent; /* Parent stack */ - SilcList stacks; /* List of stacks */ - SilcStackDataEntry stack; /* Allocated stack blocks */ + SilcMutex lock; /* Stack lock */ + SilcList stacks; /* List of stacks for childs */ + SilcStackDataEntry stack; /* The allocated stack */ SilcStackFrame *frames; /* Allocated stack frames */ SilcStackFrame *frame; /* Current stack frame */ + SilcStackOomHandler oom_handler; /* OOM handler */ + void *oom_context; /* OOM handler context */ SilcUInt32 stack_size; /* Default stack size */ SilcUInt32 alignment; /* Memory alignment */ #ifdef SILC_DIST_INPLACE @@ -75,7 +78,10 @@ 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); /* Get stack that has block that can house our size requirement. */ silc_list_start(stack->stacks); @@ -85,9 +91,16 @@ static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack, silc_list_del(stack->stacks, e); SILC_ST_DEBUG(("Got stack blocks %p from stack %p", e->data, stack)); + silc_mutex_unlock(stack->lock); 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 */ @@ -105,6 +118,7 @@ static SilcStackDataEntry silc_stack_ref_stack(SilcStack stack, e->bsize = bsize; SILC_ST_DEBUG(("Got stack blocks %p from stack %p", e->data, stack)); + return e; } @@ -127,7 +141,9 @@ static void silc_stack_unref_stack(SilcStack stack, SilcStackDataEntry e) e->data[i]->bytes_left = SILC_STACK_BLOCK_SIZE(stack, i); } + silc_mutex_lock(stack->lock); silc_list_add(stack->stacks, e); + silc_mutex_unlock(stack->lock); } /* Allocate memory from a specific stack block */ @@ -161,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); @@ -178,10 +198,13 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent) stack->parent = parent; stack->stack_size = stack_size; 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); @@ -229,6 +252,9 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent) silc_free(stack); return NULL; } + + /* Allocate lock */ + silc_mutex_alloc(&stack->lock); } /* Use the allocated stack in first stack frame */ @@ -250,6 +276,9 @@ void silc_stack_free(SilcStack stack) SilcStackDataEntry e; int i; + if (!stack) + return; + SILC_LOG_DEBUG(("Free stack %p", stack)); if (!stack->parent) { @@ -264,8 +293,12 @@ 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 */ silc_list_start(stack->stacks); while ((e = silc_list_get(stack->stacks))) silc_stack_unref_stack(stack->parent, e); @@ -342,14 +375,18 @@ 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); return NULL; } @@ -380,8 +417,11 @@ 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); return NULL; } @@ -394,6 +434,8 @@ void *silc_stack_malloc(SilcStack stack, SilcUInt32 size) stack->alignment)); if (silc_unlikely(!stack->stack->data[si])) { SILC_STACK_STAT(stack, num_errors, 1); + if (stack->oom_handler) + stack->oom_handler(stack, stack->oom_context); return NULL; } stack->stack->data[si]->bytes_left = bsize2; @@ -431,14 +473,18 @@ 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); return NULL; } @@ -454,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; } @@ -468,10 +515,22 @@ 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; } +/* Set OOM handler */ + +void silc_stack_set_oom_handler(SilcStack stack, + SilcStackOomHandler oom_handler, + void *context) +{ + stack->oom_handler = oom_handler; + stack->oom_context = context; +} + /* Set default alignment */ void silc_stack_set_alignment(SilcStack stack, SilcUInt32 alignment) @@ -487,6 +546,92 @@ 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; +} + +/* Set global stack */ + +void silc_stack_set_global(SilcStack stack) +{ + SilcTls tls = silc_thread_get_tls(); + + if (!tls) { + /* Try to initialize Tls */ + tls = silc_thread_tls_init(); + SILC_VERIFY(tls); + if (!tls) + return; + } + + tls->stack = stack; +} + +/* Return global stack */ + +SilcStack silc_stack_get_global(void) +{ + SilcTls tls = silc_thread_get_tls(); + + if (!tls) + return NULL; + + return tls->stack; +} + #ifdef SILC_DIST_INPLACE /* Statistics dumping. */