Added SILC Thread Queue API
[silc.git] / lib / silcutil / silcstack.h
index 3543de2af26bf3ac91a35d7bff5f38bb7994abfd..f2663eef949e4b37b8774b9391d85ca56a301d48 100644 (file)
@@ -4,7 +4,7 @@
 
   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
  *
  * DESCRIPTION
  *
- * Implementation of data stack which can be used to allocate memory from
- * the stack.  Basicly SilcStack is a pre-allocated memory pool system
+ * Implementation of data stack which can be used to do fast allocations from
+ * the stack.  Basically SilcStack is a pre-allocated memory pool system
  * which allows fast memory allocation for routines and applications that
  * frequently allocate small amounts of memory.  Other advantage of this
  * system is that there are no memory leaks, as long as the stack is
  * freed eventually.  Since the stack is usually allocated only once this
  * is not an issue.
  *
- * SilcStack can be used to allocate both aligned and unaligned memory so
- * it is suitable for allocating structures and is optimal for allocating
- * strings and data buffers.  SilcStack also supports stack pushing and
- * popping allowing to push the stack, allocate memory and then pop it
- * to free the allocated memory.  The freeing does not actually do any
- * real memory freeing so it is optimized for performance.
+ * SilcStack supports stack pushing and popping allowing to push the stack,
+ * allocate memory and then pop it to free the allocated memory.  The freeing
+ * does not actually do any real memory freeing so it is optimized for
+ * performance.  The memory alignment may also be specified by user for
+ * the stack.  This allows the caller to use special alignment for memory
+ * allocations, if needed.
+ *
+ * SilcStack is also a full featured memory pool which allows user to group
+ * together multiple stacks.  Child stacks may be created from a parent stack
+ * without consuming the parent stack.  When the child is freed, its memory
+ * is returned back to the parent and can be used again by other childs.
+ * It is also possible to create child stacks from another child stack.
  *
  * A basic set of utility functions are provided for application that wish
  * to use the SilcStack as their primary memory allocation source.  The
  * following functions support SilcStack:
  *
- * silc_smalloc, silc_smalloc_ua, silc_scalloc, silc_srealloc, silc_smemdup,
- * silc_sstrdup, silc_buffer_salloc, silc_buffer_salloc_size,
+ * silc_smalloc, silc_smalloc, silc_scalloc, silc_srealloc, silc_smemdup,
+ * silc_sfree, silc_sstrdup, silc_buffer_salloc, silc_buffer_salloc_size,
  * silc_buffer_srealloc, silc_buffer_srealloc_size, silc_buffer_scopy,
  * silc_buffer_sclone, silc_buffer_sformat, silc_buffer_sformat_vp,
- * silc_buffer_sstrformat, silc_buffer_senlarge, silc_mp_sinit
+ * silc_buffer_sstrformat, silc_buffer_senlarge, silc_mp_sinit,
+ * silc_dlist_sinit, silc_hash_table_alloc
  *
- * The data stack is not thread-safe.  If the same stack context must be
- * used in multithreaded environment concurrency control must be employed.
- * Each thread should allocate their own SilcStack.
+ * The SilcStack is not thread-safe so that same context could be used for
+ * allocations from multiple threads.  It is however safe to create and use
+ * child stacks in a different thread from the parent stack.  Each thread
+ * should allocate their own SilcStack, however they may be child stacks.
  *
  ***/
 
@@ -81,22 +89,35 @@ typedef struct SilcStackStruct *SilcStack;
  *
  *    Static stack frame context that optionally can be used as stack
  *    frame in SilcStack.  By default silc_stack_push use pre-allocated
- *    stack frame (or allocates new one if all frames are reserved), but
- *    user may also use statically allocated SilcStackFrame instead.  This
- *    is recommended when using SilcStack in recursive routine and the
- *    recursion may become deep.  Using static frame assures that during
- *    recursion frames never run out and silc_stack_push never allocates
- *    any memory.  In other normal usage statically allocated SilcStackFrame
- *    is not needed, unless performance is critical.
+ *    stack frame, but user may also use statically allocated SilcStackFrame
+ *    instead.  This is recommended when using SilcStack in recursive routine
+ *    and the recursion may become deep.  Using static frame assures that
+ *    during recursion frames never run out.
  *
  ***/
 typedef struct SilcStackFrameStruct SilcStackFrame;
 
+/****f* silcutil/SilcStackAPI/SilcStackOomHandler
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcStackOomHandler)(SilcStack stack, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Callback of this type can be given to silc_stack_set_oom_handler
+ *    to set Out of Memory handler to `stack'.  If memory allocation from
+ *    `stack' fails this callback is called to indicate error.  The `context'
+ *    is the context given to silc_stack_set_oom_handler.
+ *
+ ***/
+typedef void (*SilcStackOomHandler)(SilcStack stack, void *context);
+
 /****f* silcutil/SilcStackAPI/silc_stack_alloc
  *
  * SYNOPSIS
  *
- *    SilcStack silc_stack_alloc(SilcUInt32 stack_size);
+ *    SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent);
  *
  * DESCRIPTION
  *
@@ -104,11 +125,18 @@ typedef struct SilcStackFrameStruct SilcStackFrame;
  *    allocation by various routines.  Returns the pointer to the stack
  *    that must be freed with silc_stack_free function when it is not
  *    needed anymore.  If the `stack_size' is zero (0) by default a
- *    1 kilobyte (1024 bytes) stack is allocated.  If the `stack_size'
- *    is non-zero the byte value must be multiple by 8.
+ *    1 kilobyte (1024 bytes) stack is allocated.
+ *
+ *    If `parent' is non-NULL the created stack is a child of the `parent'
+ *    stack.  All of childs the memory is allocated from the `parent' and
+ *    will be returned back to the parent when the child is freed.  Note
+ *    that, even though child allocates memory from the parent, the parent's
+ *    stack is not consumed.
+ *
+ *    Returns NULL on error.
  *
  ***/
-SilcStack silc_stack_alloc(SilcUInt32 stack_size);
+SilcStack silc_stack_alloc(SilcUInt32 stack_size, SilcStack parent);
 
 /****f* silcutil/SilcStackAPI/silc_stack_free
  *
@@ -121,6 +149,9 @@ SilcStack silc_stack_alloc(SilcUInt32 stack_size);
  *    Frees the data stack context.  The stack cannot be used anymore after
  *    this and all allocated memory are freed.
  *
+ *    If `stack' is a child stack, its memory is returned back to its
+ *    parent.  If `stack' is NULL this function does nothing.
+ *
  ***/
 void silc_stack_free(SilcStack stack);
 
@@ -138,19 +169,15 @@ void silc_stack_free(SilcStack stack);
  *    stack and all allocated memory is freed after the next silc_stack_pop
  *    is called.  This returns so called stack pointer for the new stack
  *    frame, which the caller may use to check that all calls to
- *    silc_stack_pop has been made.  This call may do a small memory
- *    allocation in some cases, but usually it does not allocate any memory.
- *    If this returns zero (0) the system is out of memory.
+ *    silc_stack_pop has been made.
  *
  *    If the `frame' is non-NULL then that SilcStackFrame is used as
  *    stack frame.  Usually `frame' is set to NULL by user.  Statically
  *    allocated SilcStackFrame should be used when using silc_stack_push
  *    in recursive function and the recursion may become deep.  In this
  *    case using statically allocated SilcStackFrame is recommended since
- *    it assures that frames never run out and silc_stack_push never
- *    allocates any memory.  If your routine is not recursive then
- *    setting `frame' to NULL is recommended, unless performance is
- *    critical.
+ *    it assures that frames never run out.  If your routine is not recursive
+ *    then setting `frame' to NULL is recommended.
  *
  *    This function is used when a routine is doing frequent allocations
  *    from the stack.  If the stack is not pushed and later popped all
@@ -158,7 +185,8 @@ void silc_stack_free(SilcStack stack);
  *    (it gets enlarged by normal memory allocation).  By pushing and then
  *    later popping the frequent allocations does not consume the stack.
  *
- *    If `stack' is NULL this call has no effect.
+ *    If `stack' is NULL this call has no effect.  This function does not
+ *    allocate any memory.
  *
  * EXAMPLE
  *
@@ -195,8 +223,8 @@ SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame);
  *
  * DESCRIPTION
  *
- *    Pop the top of the stack upwards which reveals the previous stack frame
- *    and becomes the top of the stack.  After popping, memory allocated in
+ *    Pop the top of the stack which removes the previous stack frame and
+ *    becomes the top of the stack.  After popping, memory allocated in
  *    the old frame is freed.  For each silc_stack_push call there must be
  *    silc_stack_pop call to free all memory (in reality any memory is not
  *    freed but within the stack it is).  This returns the stack pointer of
@@ -206,7 +234,8 @@ SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame);
  *    silc_stack_pop has been called too many times.  Application should
  *    treat this as a fatal error, as it is a bug in the application code.
  *
- *    If `stack' is NULL this call has no effect.
+ *    If `stack' is NULL this call has no effect.   This function does not
+ *    allocate any memory.
  *
  * EXAMPLE
  *
@@ -223,6 +252,174 @@ SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame);
  ***/
 SilcUInt32 silc_stack_pop(SilcStack stack);
 
+/****f* silcutil/SilcStackAPI/silc_stack_malloc
+ *
+ * SYNOPSIS
+ *
+ *    void *silc_stack_malloc(SilcStack stack, SilcUInt32 size);
+ *
+ * DESCRIPTION
+ *
+ *    Low level memory allocation routine.  Allocates memory block of size of
+ *    `size' from the `stack'.  The allocated memory is aligned so it can be
+ *    used to allocate memory for structures, for example.  Returns the
+ *    allocated memory address or NULL if memory could not be allocated from
+ *    the `stack'.
+ *
+ * NOTES
+ *
+ *    This function should be used only if low level memory allocation with
+ *    SilcStack is needed.  Instead, silc_smalloc and silc_scalloc could
+ *    be used.
+ *
+ ***/
+void *silc_stack_malloc(SilcStack stack, SilcUInt32 size);
+
+/****f* silcutil/SilcStackAPI/silc_stack_realloc
+ *
+ * SYNOPSIS
+ *
+ *    void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size,
+ *                             void *ptr, SilcUInt32 size);
+ *
+ * DESCRIPTION
+ *
+ *    Attempts to reallocate memory by changing the size of the `ptr' into
+ *    `size'.  This routine works only if the previous allocation to `stack'
+ *    was `ptr'.  If there is another memory allocation between allocating
+ *    `ptr' and this call this routine will return NULL (and silc_errno is
+ *    set to SILC_ERR_INVALID_ARGUMENT).  NULL is also returned if the `size'
+ *    does not fit into the current stack block.  If NULL is returned the old
+ *    memory remains intact.
+ *
+ * NOTES
+ *
+ *    This function should be used only if low level memory allocation with
+ *    SilcStack is needed.  Instead, silc_srealloc could be used.
+ *
+ ***/
+void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size,
+                        void *ptr, SilcUInt32 size);
+
+/****f* silcutil/SilcStackAPI/silc_stack_set_oom_handler
+ *
+ * SYNOPSIS
+ *
+ *    void silc_stack_set_oom_handler(SilcStack stack,
+ *                                    SilcStackOomHandler oom_handler,
+ *                                    void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Sets Out of Memory handler `oom_handler' to `stack' to be called
+ *    if memory allocation from `stack' fails.  The `context' is delivered
+ *    to `oom_handler'.
+ *
+ *    Usually Out of Memory handler is set only when failed memory allocation
+ *    is a fatal error.  In this case the application would abort() inside
+ *    the `oom_handler'.  It may also be set if in case of failed allocation
+ *    application wants to do clean up properly.
+ *
+ ***/
+void silc_stack_set_oom_handler(SilcStack stack,
+                               SilcStackOomHandler oom_handler,
+                               void *context);
+
+/****f* silcutil/SilcStackAPI/silc_stack_set_alignment
+ *
+ * SYNOPSIS
+ *
+ *    void silc_stack_set_alignment(SilcStack stack, SilcUInt32 alignment);
+ *
+ * DESCRIPTION
+ *
+ *    Sets/changes the memory alignment in the `stack' to `alignment' which
+ *    is the alignment in bytes.  By default, the SilcStack will use alignment
+ *    suited for the platform where it is used.  This function can be used
+ *    to change this alignment, if such change is needed.  You may check the
+ *    current alignment by calling silc_stack_get_alignment.
+ *
+ * NOTES
+ *
+ *    It is not mandatory to call this function.  By default the SilcStack
+ *    will always use alignment suited for the used platform.  This function
+ *    should be called only if the alignment needs to be changed to something
+ *    other than the default on the used platform.  For example, some
+ *    hardware device, such as crypto accelerator, may require special
+ *    alignment.
+ *
+ ***/
+void silc_stack_set_alignment(SilcStack stack, SilcUInt32 alignment);
+
+/****f* silcutil/SilcStackAPI/silc_stack_get_alignment
+ *
+ * SYNOPSIS
+ *
+ *    SilcUInt32 silc_stack_get_alignment(SilcStack stack);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the memory alignment used with `stack'.  The alignment is in
+ *    bytes.
+ *
+ ***/
+SilcUInt32 silc_stack_get_alignment(SilcStack stack);
+
+/****f* silcutil/SilcStackAPI/silc_stack_purge
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_stack_purge(SilcStack stack);
+ *
+ * DESCRIPTION
+ *
+ *    Purges the `stack' from extra unused memory.  This purges only `stack'
+ *    and not its parent if `stack' is a child.  This purges only large
+ *    allocations.  The 1024, 2048, 4096 and 8192 bytes of allocations remain.
+ *    Call this multiple times to purge even more.  Returns FALSE when there
+ *    is no more to purge.  This does not purge memory blocks that currently
+ *    have allocations.  No memory allocations from the stack are lost, so
+ *    this is always safe to call.
+ *
+ ***/
+SilcBool silc_stack_purge(SilcStack stack);
+
+/****f* silcutil/SilcStackAPI/silc_stack_set_global
+ *
+ * SYNOPSIS
+ *
+ *    void silc_stack_set_global(SilcStack stack);
+ *
+ * DESCRIPTION
+ *
+ *    Sets global SilcStack `stack' that can be retrieved at any time
+ *    by using silc_stack_get_global.  The global stack is global only
+ *    to the current thread.  Each thread can have their own global stack.
+ *    If each thread must have own stack this must be called in each
+ *    thread.  If the global stack has been set already, new call will
+ *    replace the old one.
+ *
+ *    This routine is provided only as a convenience function to store
+ *    program's or thread's stack in one global place.  It is not mandatory
+ *    to call this function in order to use SilcStack.
+ *
+ ***/
+void silc_stack_set_global(SilcStack stack);
+
+/****f* silcutil/SilcStackAPI/silc_stack_get_global
+ *
+ * SYNOPSIS
+ *
+ *    SilcStack silc_stack_get_global(void);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the thread's global stack that was set by calling the
+ *    silc_stack_set_global or NULL if global stack has not been set.
+ *
+ ***/
+SilcStack silc_stack_get_global(void);
+
 #include "silcstack_i.h"
 
 #endif /* SILCSTACK_H */