Author: Pekka Riikonen <priikone@silcnet.org>
- 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
*/
-#include "silc.h"
+#include "silcruntime.h"
/************************** Types and definitions ***************************/
void *oom_context; /* OOM handler context */
SilcUInt32 stack_size; /* Default stack size */
SilcUInt32 alignment; /* Memory alignment */
+ SilcAtomic32 refcnt; /* Reference counter */
#ifdef SILC_DIST_INPLACE
/* Statistics */
SilcUInt32 snum_malloc;
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 (but does not consume parent's own stack). */
return NULL;
}
+ /* Reference parent */
+ SILC_LOG_DEBUG(("Reference stack %p, refcnt %d > %d", stack->parent,
+ silc_atomic_get_int32(&stack->parent->refcnt),
+ silc_atomic_get_int32(&stack->parent->refcnt) + 1));
+ silc_atomic_add_int32(&stack->parent->refcnt, 1);
+
/* Set the initial stack */
stack->stack = e;
} else {
silc_mutex_alloc(&stack->lock);
}
+ silc_atomic_init32(&stack->refcnt, 1);
+
/* Use the allocated stack in first stack frame */
stack->frame = &stack->frames[0];
stack->frame->prev = NULL;
if (!stack)
return;
- SILC_LOG_DEBUG(("Free stack %p", stack));
+ SILC_LOG_DEBUG(("Free stack %p, refcnt %d > %d", stack,
+ silc_atomic_get_int32(&stack->refcnt),
+ silc_atomic_get_int32(&stack->refcnt) - 1));
+
+ /* Unreference */
+ if (silc_atomic_sub_int32(&stack->refcnt, 1) > 0)
+ return;
if (!stack->parent) {
silc_list_start(stack->stacks);
if (stack->lock)
silc_mutex_free(stack->lock);
+ silc_atomic_uninit32(&stack->refcnt);
+
silc_free(stack);
} else {
/* Return all stack blocks to the parent */
silc_stack_unref_stack(stack->parent, e);
silc_stack_unref_stack(stack->parent, stack->stack);
+
+ /* Unreference parent */
+ silc_stack_free(stack->parent);
}
}
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);
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);
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);
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;
}
}
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;
}
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. */