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