/* * flex.h * * A shifting heap for RISC OS applications [APCS edition] * * © 1996-1998 Straylight */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Steel library. * * Steel is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * Steel is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Steel. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*----- Foreword: what are all those funny symbols in the comments? -------* * * This file has been marked up so that `lgrind' can process it to produce * a pretty typeset listing. Text enclosed by at signs is typeset like * normal code. There are some other neat things, but you get the idea. * Note that you'll need a hacked version of lgrind.sty to get the rows * of dashes typeset properly: they'll just look odd otherwise. * * Quite a lot of work has been put into this header file recently to make * the descriptions of the routines clear and complete. As a result, they * probably read like excerpts from ISO 9899 (Computer Languages -- C). */ /* --- Standard-ish preamble --- * * * If I understand the compiler properly, then use special magic to prevent * wasted cycles reading this file more than once. The normal #ifndef * stuff should keep GNU C happy because it's particularly intelligent like * that; Norcroft C would rather have some magic pragmae specified. The * usual protection is added to stop compilers of the brain-damaged version * of C invented by Bjarne Stroutrup generating duff linker symbols. */ #ifdef __CC_NORCROFT #pragma force_top_level #pragma include_only_once #endif #ifndef __flex_h #define __flex_h #ifdef __cplusplus extern "C" { #endif /*----- How it all works --------------------------------------------------* * * In order to allow the blocks to move around, you need to tell flex where * your pointer to each block is. You do this with an anchor pointer (i.e. * it points at your anchor for the block). Flex is quite at liberty to * change your anchors at any time it wants to, so if you don't want your * blocks to move, don't call flex. You must ensure that you always access * data in flex blocks through the anchor, unless you're really sure the * block won't move. * * Unlike older (Acorn) versions, Straylight flex doesn't ensure that the * heap is always as compact as possible. Instead, calling @flex_reduce@ * will attempt to compact the heap a little bit, so if you call it a lot, * the heap will eventually become very compact. It is envisaged that you * call @flex_reduce@ every Wimp_Poll. STEEL's @wimpt_poll@ does this for * you. * * There is another call, @flex_compact@, which will compact the heap fully. * This isn't terribly useful most of the time, since flex compacts itself * if it runs out of memory. * * @flex_budge@ is not currently supported. If there is a demand for it, * it may be added in later, but probably not, because in the author's * opinion it's just a request for unpredictable crashes. */ /* --- A flex anchor pointer --- * * * Due to Acorn brain-damage, this is a void ** instead of a void *, meaning * that you end up with typecasts all over the shop. Strictly speaking, * such typecasts invoke undefined behaviour, although it works under all * known ARM compilers, and if nyone tries to use this code on any other * platform they get what they deserve, because the code's written in * assembler ;-). */ typedef void **flex_ptr; /* --- @flex_init@ --- * * * Arguments: --- * * Returns: --- * * Use: Initialises flex. It doesn't bother to check that any * memory is available. * * This is now just a macro which calls the @flex_dinit@ * routine with a null pointer argument, forcing the heap to * be created in the task;s WimpSlot. */ #define flex_init(x) flex_dinit(0, 0); /* --- @flex_dinit@ --- * * * Arguments: @const char *name@ = name of dynamic area to create, or null * @long max@ = maximum size of the area * * Returns: --- * * Use: Initialises flex and creates a (zero-sized) initial heap. * If the @name@ argument is not a null pointer, and the * current operating system is RISC OS 3.50 or later, then an * attempt is made to create the heap in a dynamic area. If * this fails, or the attempt wasn't made, then the heap is * created in the task's wimpslot instead. * * The author strongly urges you not to use the dynamic area * option without good reason. Dynamic areas are limited to * 16MB, to avoid problems with address space fragmentation * on machines with large quantities of real memory. * * It is your responsibility to remove the dynamic area when * your program quits. Usually you will do this by calling * @atexit(flex_die)@ just after initialisation of the heap, * although some other method may be necessary if you're not * using the complete C library for some reason. */ extern void flex_dinit(const char */* name */, long /* max */); /* --- @flex_die@ --- * * * Arguments: --- * * Returns: --- * * Use: Tidies up anything as required when the program end. It is * recommended that this be done via the C library's @atexit@ * mechanism or some equivalent for freestanding applications. * This is only necessary when flex has created a dynamic area * for this application, although provided flex has initialised * it is never wrong to register this routine as a closedown * function. */ extern void flex_die(void); /* --- @flex_alloc@ --- * * * Arguments: @flex_ptr anchor@ = address of the anchor for this block * @unsigned long size@ = size of the block required * * Returns: Nonzero if the block was successfuly allocated, zero if * there wasn't enough memory. * * Use: Allocates a shifting heap block. The address is stored in * the pointer variable whose address was passed in @anchor@. * This pointer will be updated automatically when the block is * moved during compaction. The size of the allocated block * will be at least @size@ bytes. * * If there is not enough memory currently available in the * heap, flex may attempt to reclaim space by compacting the * heap. As a result, other heap blocks may be moved; this was * not possible under the Acorn implementation. The new block * will always be placed at the end of the heap. * * During compaction, blocks only move to lower addresses. * When a block is grown, blocks above it move to higher * addresses. As a consequence of this, a block at the base * of the heap will never be moved by flex. This fact may be * useful, for example if you want to create a resizing non- * shifting heap. */ extern int flex_alloc(flex_ptr /* anchor*/, unsigned long /* size */); /* --- @flex_free@ --- * * * Arguments; @flex_ptr@ anchor = address of the anchor for this block * * Returns: --- * * Use: Frees the memory occupied by the block whose anchor address * is given in @anchor@. The memory is marked as unoccupied * and reclaimed during compaction later. Therefore freeing * blocks is an extremely cheap operation, as it should be. */ extern void flex_free(flex_ptr /* anchor */); /* --- @flex_extend@ --- * * * Arguments: @flex_ptr anchor@ = address of the anchor for the block * @unsigned long size@ = new size for the block * * Returns: Nonzero if the resize was successful, or zero if there * wasn't enough memory. * * Use: Changes the size of the block whose anchor address is given * by @anchor@; the new size will be at least @size@ bytes. * * If @size@ is less than or equal to the current size of the * block, this operation cannot fail; any space at the end of * the block which is no longer required is marked as unused * and reclaimed later during compaction. No blocks are moved. * * If @size@ is greater than the current size of the block, * this operation might fail. Also, flex might compact the * heap in an attempt to obtain enough free memory, so all * blocks might move. Blocks above the one being grown will * move anyway; blocks below the one being resized did not * move in this way under the Acorn implementation. */ extern int flex_extend(flex_ptr /* anchor */, unsigned long /* newsize */); /* --- @flex_midextend@ --- * * * Arguments: @flex_ptr anchor@ = address of the anchor for the block * @unsigned long at@ = index at which to insert or remove bytes * @long by@ = number of bytes to insert or remove * * Returns: Nonzero if the resize was successful, or zero if there * wasn't enough memory. * * Use: Changes the size of the block whose anchor address is given * by @anchor@. Bytes are inserted or removed at the given * offset @at@, which must be between 0 and @flex_size(anchor)@ * inclusive. If @by@ is positive, then @by@ bytes are * inserted before the indexed byte; if it is negative, then * @-by@ bytes are deleted from just before @at@. Always, * the data which was at offset @at@ is now at offset @at + by@. * The value of @by@ must be at least @-flex_size(anchor)@. * * If @by@ is negative, this operation cannot fail; the bytes * are deleted by calling @memmove@, and any space at the end of * the block which is no longer required is marked as unused * and reclaimed later during compaction. No blocks are moved. * * If @by@ is positive, this operation might fail. Also, flex * might compact the heap in an attempt to obtain enough free * memory, so all blocks might move. Blocks above the one * being extended will move anyway; blocks below the one being * resized did not move in this way under the Acorn * implementation. If the block was resized successfully, bytes * with undefined values are inserted at the correct place by * calling @memmove@. This does not occur if the operation * failed. */ extern int flex_midextend(flex_ptr /* anchor */, unsigned long /* at */ , long /* by */); /* --- @flex_size@ --- * * * Arguments: @flex_ptr anchor@ = address of the anchor for the block * * Returns: The size of the block. This is returned as a @signed int@ * for historical reasons: old versions of flex returned this * value, and it's likely that old code will generate large * numbers of annoying and useless `implicit narrowing cast' * if I change the return type to @unsigned long@. However, * if you read the value as an @unsigned long@ you won't get * get any warnings, and you'll also get the correct value. * * Use: Returns the current size of the block in bytes. This is * the `conceptual' size: the actual amount of memory occupied * by the block depends on unspecified bookkeeping overhead and * alignment applied to this value. The size returned is the * @size@ argument passed to the most recent @flex_alloc@ or * @flex_extend@ call referring to this block, added to the * sum of all the @by@ arguments passed to @flex_midextend@ * since then. */ extern int flex_size(flex_ptr /* anchor */); /* --- @flex_reduce@ --- * * * Arguments: --- * * Returns: --- * * Use: Performs a small part of the compaction process. Calling * @flex_reduce@ enough times will result in the heap becoming * compacted; further calls will have no effect. * * The idea is that you call @flex_reduce@ periodically, e.g., * when you receive a null event code. */ extern void flex_reduce(void); /* --- @flex_compact@ --- * * * Arguments: --- * * Returns: --- * * Use: Fully compacts the heap. This might be useful if you've * just done a lot of freeing and compaction by normal * processes takes too long. */ extern void flex_compact(void); /* --- kernel slot extension functions --- * * * Only @flex_dont_budge@ is supported at the moment. Note that the * interfaces as defined here are broken, because the size should really * be an unsigned type. However, since both routines simply do @return (0)@ * this isn't too much of a problem. */ extern int flex_dont_budge(int /* n */, void **/* p */); extern int flex_budge(int /* n */, void **/* p */); #ifdef __cplusplus } #endif /*----- That's all, folks -------------------------------------------------*/ #endif