1 /* 2 3 silcstack.h 4 5 Author: Pekka Riikonen <priikone@silcnet.org> 6 7 Copyright (C) 2003 - 2007 Pekka Riikonen 8 9 The contents of this file are subject to one of the Licenses specified 10 in the COPYING file; You may not use this file except in compliance 11 with the License. 12 13 The software distributed under the License is distributed on an "AS IS" 14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY 15 KIND, either expressed or implied. See the COPYING file for more 16 information. 17 18 */ 19 20 /****h* silcutil/SilcStack Interface 21 * 22 * DESCRIPTION 23 * 24 * Implementation of data stack which can be used to allocate memory from 25 * the stack. Basicly SilcStack is a pre-allocated memory pool system 26 * which allows fast memory allocation for routines and applications that 27 * frequently allocate small amounts of memory. Other advantage of this 28 * system is that there are no memory leaks, as long as the stack is 29 * freed eventually. Since the stack is usually allocated only once this 30 * is not an issue. 31 * 32 * SilcStack can be used to allocate both aligned and unaligned memory so 33 * it is suitable for allocating structures and is optimal for allocating 34 * strings and data buffers. SilcStack also supports stack pushing and 35 * popping allowing to push the stack, allocate memory and then pop it 36 * to free the allocated memory. The freeing does not actually do any 37 * real memory freeing so it is optimized for performance. 38 * 39 * A basic set of utility functions are provided for application that wish 40 * to use the SilcStack as their primary memory allocation source. The 41 * following functions support SilcStack: 42 * 43 * silc_smalloc, silc_smalloc_ua, silc_scalloc, silc_srealloc, silc_smemdup, 44 * silc_sstrdup, silc_buffer_salloc, silc_buffer_salloc_size, 45 * silc_buffer_srealloc, silc_buffer_srealloc_size, silc_buffer_scopy, 46 * silc_buffer_sclone, silc_buffer_sformat, silc_buffer_sformat_vp, 47 * silc_buffer_sstrformat, silc_buffer_senlarge, silc_mp_sinit 48 * 49 * The data stack is not thread-safe. If the same stack context must be 50 * used in multithreaded environment concurrency control must be employed. 51 * Each thread should allocate their own SilcStack. 52 * 53 ***/ 54 55 #ifndef SILCSTACK_H 56 #define SILCSTACK_H 57 58 /****s* silcutil/SilcStackAPI/SilcStack 59 * 60 * NAME 61 * 62 * typedef struct SilcStackStruct *SilcStack; 63 * 64 * DESCRIPTION 65 * 66 * This context represents the stack and it is allocated by 67 * silc_stack_alloc and is destroyed with silc_stack_free functions. 68 * The context is given as argument to all routines that use this 69 * stack allocation library. 70 * 71 ***/ 72 typedef struct SilcStackStruct *SilcStack; 73 74 /****s* silcutil/SilcStackAPI/SilcStackFrame 75 * 76 * NAME 77 * 78 * typedef struct SilcStackFrameStruct SilcStackFrame; 79 * 80 * DESCRIPTION 81 * 82 * Static stack frame context that optionally can be used as stack 83 * frame in SilcStack. By default silc_stack_push use pre-allocated 84 * stack frame (or allocates new one if all frames are reserved), but 85 * user may also use statically allocated SilcStackFrame instead. This 86 * is recommended when using SilcStack in recursive routine and the 87 * recursion may become deep. Using static frame assures that during 88 * recursion frames never run out and silc_stack_push never allocates 89 * any memory. In other normal usage statically allocated SilcStackFrame 90 * is not needed, unless performance is critical. 91 * 92 ***/ 93 typedef struct SilcStackFrameStruct SilcStackFrame; 94 95 /****f* silcutil/SilcStackAPI/silc_stack_alloc 96 * 97 * SYNOPSIS 98 * 99 * SilcStack silc_stack_alloc(SilcUInt32 stack_size); 100 * 101 * DESCRIPTION 102 * 103 * Allocates new data stack that can be used as stack for fast memory 104 * allocation by various routines. Returns the pointer to the stack 105 * that must be freed with silc_stack_free function when it is not 106 * needed anymore. If the `stack_size' is zero (0) by default a 107 * 1 kilobyte (1024 bytes) stack is allocated. If the `stack_size' 108 * is non-zero the byte value must be multiple by 8. 109 * 110 ***/ 111 SilcStack silc_stack_alloc(SilcUInt32 stack_size); 112 113 /****f* silcutil/SilcStackAPI/silc_stack_free 114 * 115 * SYNOPSIS 116 * 117 * void silc_stack_free(SilcStack stack); 118 * 119 * DESCRIPTION 120 * 121 * Frees the data stack context. The stack cannot be used anymore after 122 * this and all allocated memory are freed. 123 * 124 ***/ 125 void silc_stack_free(SilcStack stack); 126 127 /****f* silcutil/SilcStackAPI/silc_stack_push 128 * 129 * SYNOPSIS 130 * 131 * SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame); 132 * 133 * DESCRIPTION 134 * 135 * Push the top of the stack down which becomes the new top of the stack. 136 * For every silc_stack_push call there must be silc_stack_pop call. All 137 * allocations between these two calls will be done from the top of the 138 * stack and all allocated memory is freed after the next silc_stack_pop 139 * is called. This returns so called stack pointer for the new stack 140 * frame, which the caller may use to check that all calls to 141 * silc_stack_pop has been made. This call may do a small memory 142 * allocation in some cases, but usually it does not allocate any memory. 143 * If this returns zero (0) the system is out of memory. 144 * 145 * If the `frame' is non-NULL then that SilcStackFrame is used as 146 * stack frame. Usually `frame' is set to NULL by user. Statically 147 * allocated SilcStackFrame should be used when using silc_stack_push 148 * in recursive function and the recursion may become deep. In this 149 * case using statically allocated SilcStackFrame is recommended since 150 * it assures that frames never run out and silc_stack_push never 151 * allocates any memory. If your routine is not recursive then 152 * setting `frame' to NULL is recommended, unless performance is 153 * critical. 154 * 155 * This function is used when a routine is doing frequent allocations 156 * from the stack. If the stack is not pushed and later popped all 157 * allocations are made from the stack and the stack eventually runs out 158 * (it gets enlarged by normal memory allocation). By pushing and then 159 * later popping the frequent allocations does not consume the stack. 160 * 161 * If `stack' is NULL this call has no effect. 162 * 163 * EXAMPLE 164 * 165 * All memory allocations in silc_foo_parse_packet will be done in 166 * a fresh stack frame and that data is freed after the parsing is 167 * completed. 168 * 169 * silc_stack_push(stack, NULL); 170 * silc_foo_parse_packet(packet, stack); 171 * silc_stack_pop(stack); 172 * 173 * Another example with recursion and using statically allocated 174 * SilcStackFrame. After popping the statically allocated frame can 175 * be reused if necessary. 176 * 177 * void silc_foo_this_function(SilcStack stack) 178 * { 179 * SilcStackFrame frame; 180 * ... 181 * silc_stack_push(stack, &frame); 182 * silc_foo_this_function(stack); // Call recursively 183 * silc_stack_pop(stack); 184 * ... 185 * } 186 * 187 ***/ 188 SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame); 189 190 /****f* silcutil/SilcStackAPI/silc_stack_pop 191 * 192 * SYNOPSIS 193 * 194 * SilcUInt32 silc_stack_pop(SilcStack stack); 195 * 196 * DESCRIPTION 197 * 198 * Pop the top of the stack upwards which reveals the previous stack frame 199 * and becomes the top of the stack. After popping, memory allocated in 200 * the old frame is freed. For each silc_stack_push call there must be 201 * silc_stack_pop call to free all memory (in reality any memory is not 202 * freed but within the stack it is). This returns the stack pointer of 203 * old frame after popping and caller may check that it is same as 204 * returned by the silc_stack_push. If it they differ, some routine 205 * has called silc_stack_push but has not called silc_stack_pop, or 206 * silc_stack_pop has been called too many times. Application should 207 * treat this as a fatal error, as it is a bug in the application code. 208 * 209 * If `stack' is NULL this call has no effect. 210 * 211 * EXAMPLE 212 * 213 * This example saves the stack pointer which is checked when popping 214 * the current stack frame. If the stack pointer differs then someone 215 * has pushed the stack frame but forgot to pop it (or has called it 216 * too many times). 217 * 218 * sp = silc_stack_push(stack, NULL); 219 * silc_foo_parse_packet(packet, stack); 220 * if (silc_stack_pop(stack) != sp) 221 * fatal("corrupted stack"); 222 * 223 ***/ 224 SilcUInt32 silc_stack_pop(SilcStack stack); 225 226 #include "silcstack_i.h" 227 228 #endif /* SILCSTACK_H */ 229