-*- text -*- Specifications for memory management routines. The following functions will be provided: mem_init - to be called just once, initializes the memory subsystem. No parameters. mem_mode - to toggle between 'dryrun' and real production modes. character*(*) mode - set to 'dry' or 'run' - sets the mode - set to 'debug' includes some extra checks. - set to 'pattern' initializes memory to a pattern. mem_clear - to clear out any allocated memory. Will complain and crash if all previously allocated memory is not freed yet. mem_get - to get a piece of memory from the stack. integer count - how many units of memory character*(*) type - 'real', 'complex', 'integer' character*(*) tag - the name of the allocating subroutine returns an index into 'array' BIGMEM mem_free - to give back a piece of memory to the stack. same parameters as mem_get mem_dump - prints the current memory allocation stack. Used for debugging. The memory model is similar to the one used in Endyne. Several ideas are derived from that code, created by George Purvis and Erik Deumens. We allocate an array somewhere, and convert all the pointers into indexes of an imaginary 'array' BIGMEM, which starts in common /MEMAREA/ (file mem.cmn). We also try to do our best to return indexes so that they always start at 8-byte word boundary. BIGMEM(1) ISTART IFREE IEND | | | | v v v v ....................++++++++++++++++++----------------......... ... - memory used for other purposes +++ - memory allocated and given out to program --- - memory allocated and free to be given out In order to find out the maximum memory requirements of the program, a 'dry run' will be performed first, where all the subroutines that deal with memory should only do the minimal work required to figure out the memory requirements, and then call the mem_get's and mem_free's as if doing real work. The peak memory usage can be found then, and the memory actually allocated. After that, mem_mode will be set to 'run', and the actual run performed. All the memory blocks are preceded by a 'overhead block', which is overhead_size bytes long, and contains the following: integer: size of this block integer: index pointing to previous block 2*integer: the name of the allocating subroutine This way we get a doubly linked list of memory blocks. There is also an overhead block at the end of the meory area, with size zero. Word 2 of the very first block points immediately past the end of this list (to the block of size zero) . Such structure allows for an easy method of tracing out-of-bound errors.