chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / h / flex
1 /*
2  * flex.h
3  *
4  * A shifting heap for RISC OS applications [APCS edition]
5  *
6  * © 1996-1998 Straylight
7  */
8
9 /*----- Licensing note ----------------------------------------------------*
10  *
11  * This file is part of Straylight's Steel library.
12  *
13  * Steel is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2, or (at your option)
16  * any later version.
17  *
18  * Steel is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with Steel.  If not, write to the Free Software Foundation,
25  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 /*----- Foreword: what are all those funny symbols in the comments? -------*
29  *
30  * This file has been marked up so that `lgrind' can process it to produce
31  * a pretty typeset listing.  Text enclosed by at signs is typeset like
32  * normal code.  There are some other neat things, but you get the idea.
33  * Note that you'll need a hacked version of lgrind.sty to get the rows
34  * of dashes typeset properly: they'll just look odd otherwise.
35  *
36  * Quite a lot of work has been put into this header file recently to make
37  * the descriptions of the routines clear and complete.  As a result, they
38  * probably read like excerpts from ISO 9899 (Computer Languages -- C).
39  */
40
41 /* --- Standard-ish preamble --- *
42  *
43  * If I understand the compiler properly, then use special magic to prevent
44  * wasted cycles reading this file more than once.  The normal #ifndef
45  * stuff should keep GNU C happy because it's particularly intelligent like
46  * that; Norcroft C would rather have some magic pragmae specified.  The
47  * usual protection is added to stop compilers of the brain-damaged version
48  * of C invented by Bjarne Stroutrup generating duff linker symbols.
49  */
50
51 #ifdef __CC_NORCROFT
52   #pragma force_top_level
53   #pragma include_only_once
54 #endif
55
56 #ifndef __flex_h
57 #define __flex_h
58
59 #ifdef __cplusplus
60   extern "C" {
61 #endif
62
63 /*----- How it all works --------------------------------------------------*
64  *
65  * In order to allow the blocks to move around, you need to tell flex where
66  * your pointer to each block is.  You do this with an anchor pointer (i.e.
67  * it points at your anchor for the block).  Flex is quite at liberty to
68  * change your anchors at any time it wants to, so if you don't want your
69  * blocks to move, don't call flex.  You must ensure that you always access
70  * data in flex blocks through the anchor, unless you're really sure the
71  * block won't move.
72  *
73  * Unlike older (Acorn) versions, Straylight flex doesn't ensure that the
74  * heap is always as compact as possible.  Instead, calling @flex_reduce@
75  * will attempt to compact the heap a little bit, so if you call it a lot,
76  * the heap will eventually become very compact.  It is envisaged that you
77  * call @flex_reduce@ every Wimp_Poll.  STEEL's @wimpt_poll@ does this for
78  * you.
79  *
80  * There is another call, @flex_compact@, which will compact the heap fully.
81  * This isn't terribly useful most of the time, since flex compacts itself
82  * if it runs out of memory.
83  *
84  * @flex_budge@ is not currently supported.  If there is a demand for it,
85  * it may be added in later, but probably not, because in the author's
86  * opinion it's just a request for unpredictable crashes.
87  */
88
89 /* --- A flex anchor pointer --- *
90  *
91  * Due to Acorn brain-damage, this is a void ** instead of a void *, meaning
92  * that you end up with typecasts all over the shop.  Strictly speaking,
93  * such typecasts invoke undefined behaviour, although it works under all
94  * known ARM compilers, and if nyone tries to use this code on any other
95  * platform they get what they deserve, because the code's written in
96  * assembler ;-).
97  */
98
99 typedef void **flex_ptr;
100
101 /* --- @flex_init@ --- *
102  *
103  * Arguments:   ---
104  *
105  * Returns:     ---
106  *
107  * Use:         Initialises flex.  It doesn't bother to check that any
108  *              memory is available.
109  *
110  *              This is now just a macro which calls the @flex_dinit@
111  *              routine with a null pointer argument, forcing the heap to
112  *              be created in the task;s WimpSlot.
113  */
114
115 #define flex_init(x) flex_dinit(0, 0);
116
117 /* --- @flex_dinit@ --- *
118  *
119  * Arguments:   @const char *name@ = name of dynamic area to create, or null
120  *              @long max@ = maximum size of the area
121  *
122  * Returns:     ---
123  *
124  * Use:         Initialises flex and creates a (zero-sized) initial heap.
125  *              If the @name@ argument is not a null pointer, and the
126  *              current operating system is RISC OS 3.50 or later, then an
127  *              attempt is made to create the heap in a dynamic area.  If
128  *              this fails, or the attempt wasn't made, then the heap is
129  *              created in the task's wimpslot instead.
130  *
131  *              The author strongly urges you not to use the dynamic area
132  *              option without good reason.  Dynamic areas are limited to
133  *              16MB, to avoid problems with address space fragmentation
134  *              on machines with large quantities of real memory.
135  *
136  *              It is your responsibility to remove the dynamic area when
137  *              your program quits.  Usually you will do this by calling
138  *              @atexit(flex_die)@ just after initialisation of the heap,
139  *              although some other method may be necessary if you're not
140  *              using the complete C library for some reason.
141  */
142
143 extern void flex_dinit(const char */* name */, long /* max */);
144
145 /* --- @flex_die@ --- *
146  *
147  * Arguments:   ---
148  *
149  * Returns:     ---
150  *
151  * Use:         Tidies up anything as required when the program end.  It is
152  *              recommended that this be done via the C library's @atexit@
153  *              mechanism or some equivalent for freestanding applications.
154  *              This is only necessary when flex has created a dynamic area
155  *              for this application, although provided flex has initialised
156  *              it is never wrong to register this routine as a closedown
157  *              function.
158  */
159
160 extern void flex_die(void);
161
162 /* --- @flex_alloc@ --- *
163  *
164  * Arguments:   @flex_ptr anchor@ = address of the anchor for this block
165  *              @unsigned long size@ = size of the block required
166  *
167  * Returns:     Nonzero if the block was successfuly allocated, zero if
168  *              there wasn't enough memory.
169  *
170  * Use:         Allocates a shifting heap block.  The address is stored in
171  *              the pointer variable whose address was passed in @anchor@.
172  *              This pointer will be updated automatically when the block is
173  *              moved during compaction.  The size of the allocated block
174  *              will be at least @size@ bytes.
175  *
176  *              If there is not enough memory currently available in the
177  *              heap, flex may attempt to reclaim space by compacting the
178  *              heap.  As a result, other heap blocks may be moved; this was
179  *              not possible under the Acorn implementation.  The new block
180  *              will always be placed at the end of the heap.
181  *
182  *              During compaction, blocks only move to lower addresses.
183  *              When a block is grown, blocks above it move to higher
184  *              addresses.  As a consequence of this, a block at the base
185  *              of the heap will never be moved by flex.  This fact may be
186  *              useful, for example if you want to create a resizing non-
187  *              shifting heap.
188  */
189
190 extern int flex_alloc(flex_ptr /* anchor*/, unsigned long /* size */);
191
192 /* --- @flex_free@ --- *
193  *
194  * Arguments;   @flex_ptr@ anchor = address of the anchor for this block
195  *
196  * Returns:     ---
197  *
198  * Use:         Frees the memory occupied by the block whose anchor address
199  *              is given in @anchor@.  The memory is marked as unoccupied
200  *              and reclaimed during compaction later.  Therefore freeing
201  *              blocks is an extremely cheap operation, as it should be.
202  */
203
204 extern void flex_free(flex_ptr /* anchor */);
205
206 /* --- @flex_extend@ --- *
207  *
208  * Arguments:   @flex_ptr anchor@ = address of the anchor for the block
209  *              @unsigned long size@ = new size for the block
210  *
211  * Returns:     Nonzero if the resize was successful, or zero if there
212  *              wasn't enough memory.
213  *
214  * Use:         Changes the size of the block whose anchor address is given
215  *              by @anchor@; the new size will be at least @size@ bytes.
216  *
217  *              If @size@ is less than or equal to the current size of the
218  *              block, this operation cannot fail; any space at the end of
219  *              the block which is no longer required is marked as unused
220  *              and reclaimed later during compaction.  No blocks are moved.
221  *
222  *              If @size@ is greater than the current size of the block,
223  *              this operation might fail.  Also, flex might compact the
224  *              heap in an attempt to obtain enough free memory, so all
225  *              blocks might move.  Blocks above the one being grown will
226  *              move anyway; blocks below the one being resized did not
227  *              move in this way under the Acorn implementation.
228  */
229
230 extern int flex_extend(flex_ptr /* anchor */, unsigned long /* newsize */);
231
232 /* --- @flex_midextend@ --- *
233  *
234  * Arguments:   @flex_ptr anchor@ = address of the anchor for the block
235  *              @unsigned long at@ = index at which to insert or remove bytes
236  *              @long by@ = number of bytes to insert or remove
237  *
238  * Returns:     Nonzero if the resize was successful, or zero if there
239  *              wasn't enough memory.
240  *
241  * Use:         Changes the size of the block whose anchor address is given
242  *              by @anchor@.  Bytes are inserted or removed at the given
243  *              offset @at@, which must be between 0 and @flex_size(anchor)@
244  *              inclusive.  If @by@ is positive, then @by@ bytes are
245  *              inserted before the indexed byte; if it is negative, then
246  *              @-by@ bytes are deleted from just before @at@.  Always,
247  *              the data which was at offset @at@ is now at offset @at + by@.
248  *              The value of @by@ must be at least @-flex_size(anchor)@.
249  *
250  *              If @by@ is negative, this operation cannot fail; the bytes
251  *              are deleted by calling @memmove@, and any space at the end of
252  *              the block which is no longer required is marked as unused
253  *              and reclaimed later during compaction.  No blocks are moved.
254  *
255  *              If @by@ is positive, this operation might fail.  Also, flex
256  *              might compact the heap in an attempt to obtain enough free
257  *              memory, so all blocks might move.  Blocks above the one
258  *              being extended will move anyway; blocks below the one being
259  *              resized did not move in this way under the Acorn
260  *              implementation.  If the block was resized successfully, bytes
261  *              with undefined values are inserted at the correct place by
262  *              calling @memmove@.  This does not occur if the operation
263  *              failed.
264  */
265
266 extern int flex_midextend(flex_ptr /* anchor */,
267                           unsigned long /* at */ , long /* by */);
268
269 /* --- @flex_size@ --- *
270  *
271  * Arguments:   @flex_ptr anchor@ = address of the anchor for the block
272  *
273  * Returns:     The size of the block.  This is returned as a @signed int@
274  *              for historical reasons: old versions of flex returned this
275  *              value, and it's likely that old code will generate large
276  *              numbers of annoying and useless `implicit narrowing cast'
277  *              if I change the return type to @unsigned long@.  However,
278  *              if you read the value as an @unsigned long@ you won't get
279  *              get any warnings, and you'll also get the correct value.
280  *
281  * Use:         Returns the current size of the block in bytes.  This is
282  *              the `conceptual' size: the actual amount of memory occupied
283  *              by the block depends on unspecified bookkeeping overhead and
284  *              alignment applied to this value.  The size returned is the
285  *              @size@ argument passed to the most recent @flex_alloc@ or
286  *              @flex_extend@ call referring to this block, added to the
287  *              sum of all the @by@ arguments passed to @flex_midextend@
288  *              since then.
289  */
290
291 extern int flex_size(flex_ptr /* anchor */);
292
293 /* --- @flex_reduce@ --- *
294  *
295  * Arguments:   ---
296  *
297  * Returns:     ---
298  *
299  * Use:         Performs a small part of the compaction process.  Calling
300  *              @flex_reduce@ enough times will result in the heap becoming
301  *              compacted; further calls will have no effect.
302  *
303  *              The idea is that you call @flex_reduce@ periodically, e.g.,
304  *              when you receive a null event code.
305  */
306
307 extern void flex_reduce(void);
308
309 /* --- @flex_compact@ --- *
310  *
311  * Arguments:   ---
312  *
313  * Returns:     ---
314  *
315  * Use:         Fully compacts the heap.  This might be useful if you've
316  *              just done a lot of freeing and compaction by normal
317  *              processes takes too long.
318  */
319
320 extern void flex_compact(void);
321
322 /* --- kernel slot extension functions --- *
323  *
324  * Only @flex_dont_budge@ is supported at the moment.  Note that the
325  * interfaces as defined here are broken, because the size should really
326  * be an unsigned type.  However, since both routines simply do @return (0)@
327  * this isn't too much of a problem.
328  */
329
330 extern int flex_dont_budge(int /* n */, void **/* p */);
331 extern int flex_budge(int /* n */, void **/* p */);
332
333 #ifdef __cplusplus
334   }
335 #endif
336
337 /*----- That's all, folks -------------------------------------------------*/
338
339 #endif