/* Copyright 1996 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Title: alloc - Storage management (dynamic allocation/deallocation) Copyright: (C) 1987, Acorn Computers Ltd., Cambridge, England. Revision: 4.2 LDS, LH 03-Nov-89 */ #ifndef __alloc__h #define __alloc__h #ifndef __stddef__h #include <stddef.h> #endif /* #define CAMEL */ #define BLOCKS_GUARDED */ #define MULTITHREADED */ /* #define GC */ /* #define STATS */ /* #define DEBUG */ /* #define STACKCHECK */ /* #define VERBOSE */ /* #define ANALYSIS prints +No on allocate and -No on deallocate */ /* #define MEMDUMP gives a memory dump to screen and $.memdump when corrupt */ /* * if the OSStorage can not be depended upon to allocate areas of the * heap in consistently increasing address order then the following * constant must be set to FALSE. */ #define HEAP_ALLOCATED_IN_ASCENDING_ADDRESS_ORDER 1 typedef struct BlockStruct { #ifdef BLOCKS_GUARDED unsigned int guard; /* guard word should contain GuardConstant if all ok */ #endif size_t size; /* block size (not including header) in address units. */ /* The bottom 2 bits of size hold the flags declared below */ struct BlockStruct *next; /* next and previous are used internaly in */ struct BlockStruct *previous; /* coalescing and managing free blocks. */ /* next is the first word of the user block */ } Block, *BlockP; #define OK 0 #define FAILED -1 #define CORRUPT -2 #define MINHEAPERROR -2 /* ensure you update this if you add any new errors */ #define SIZEMASK 0xfffffffc /* all except bottom two bits, when applied */ /* to block.size yields no of address units */ /* of user space in this block. */ #define FREEBIT (1U<<0) /* if set, indicates that the block is free */ #define HEAPHOLEBIT (1U<<1) /* block used for marking start of heap hole */ #define GUARDCONSTANT 0x3E694C3C /* not a legal word pointer */ #define BYTESPERWORD sizeof(int) /* Block.next offset from Block (in words) */ #define FIRSTUSERWORD ((sizeof(Block)-sizeof(BlockP)*2) / BYTESPERWORD) extern void _init_alloc(void); /* * Initialise allocate (not to be called by anyone outside the M2Core!) */ typedef void FreeProc (BlockP block); /* block = pointer to start of header of block to be freed */ extern size_t _byte_size(void *p); /* * Return an approximation to the allocated size of the object pointed * to by p. The only guarantee is that:- * requested_size(p) <= _byte_size(p) <= allocated_size(p). */ extern void *_sys_alloc(size_t n); /* * A paranoid variant of malloc used by the C compiler. */ extern int __coalesce(void); /* * Perform a colesce step on the heap. Returns OK or Corrupt. */ /* ---------------------------- Debug aids --------------------------------- */ #ifdef BLOCKS_GUARDED extern void __heap_checking_on_all_deallocates(int on); /* * If on = TRUE, the structure of the heap is checked on every deallocate */ extern void __heap_checking_on_all_allocates(int on); /* * If on = TRUE, the structure of the heap is checked on every allocate */ #endif /* ------------------------- Statistics reporting --------------------------*/ typedef enum { COALESCE, EXTENSION, COALESCE_AND_EXTENSION } Event; typedef struct StorageInfoStruct { BlockP heapLow; /* heap base */ BlockP heapHigh; /* heap top */ unsigned int userHeap; /* user part of heap = heapHigh-heapLow-gcbitmaps */ unsigned int maxHeapRequirement; /* max storage actually requested by user */ unsigned int currentHeapRequirement; /* current user requested storage */ unsigned int coalesces; /* number of coalesces performed, includes number of garbage collections cos a coalesce is done after every garbage collection. */ unsigned int heapExtensions; /* number of times that heap is extended */ unsigned int blocksAllocated; /* total number of allocates requested */ unsigned int blocksDeallocated; /* total number of deallocates requested */ unsigned int bytesAllocated; /* total number of bytes allocated */ unsigned int bytesDeallocated; /* total number of bytes deallocated */ } StorageInfo, *StorageInfoP; typedef struct EventInfoStruct { Event event; size_t blockThatCausedEvent; /* size of allocate that caused event */ unsigned int totalFree; /* amount of heap that user can actually write to, does not include bitmaps and block overheads */ unsigned int userHeap; /* user part of heap = heapHigh-heapLow-gcbitmaps */ /* the following are changes from previous event */ unsigned int allocates; /* number of allocates requested */ unsigned int bytesAllocated; /* number of bytes allocated */ unsigned int deallocates; /* number of deallocates requested */ unsigned int bytesDeallocated; /* number of bytes deallocated */ } EventInfo, *EventInfoP; #ifdef STATS extern void _GetStorageInfo(StorageInfoP info); /* * Get statistics on the current state of the storage manager */ extern int _GetLastEvent(void); /* * returns the number of the last event to happen in the storage manager. */ extern int _GetEventData(int event, EventInfoP info); /* * get the record which describes the state of the storage manager for the * given event. Returns FALSE if no more records available. All records can * be read from GetLastEvent() downwards until FALSE is returned. */ extern void _NextHeapElement( BlockP *nextBase, /* updated to point to start of next block */ unsigned int *guard, /* value of guard word */ size_t *size, /* size of user block in bytes */ int *free, /* if true, block is free */ int *heapHole, /* if true, block is a heap hole */ int *bitmap, /* if true, block is a gc bitmap */ unsigned int *firstWord); /* first word of the user block */ /* * Get data describing the heap block pointed at by nextBase (first block is * accessed by nextBase = NIL) nextBase is set to NIL when the last block has * been read (not on the attempt to read the last block) */ #endif /* stats */ #define BITSIZE(bytes) ((bytes)<<3) #define BITSPERWORD BITSIZE(sizeof(int)) #define BITSPERBYTE (BITSPERWORD/BYTESPERWORD) /* * The following constants are all in address units */ /* MAXBYTES should be something outrageously big */ #define MAXBYTES 0x40000000 #define OVERHEAD (FIRSTUSERWORD * BYTESPERWORD) #define HOLEOVERHEAD OVERHEAD #define MINBLOCKSIZE (OVERHEAD + BYTESPERWORD) /* the following constants are tunable */ /* multiple of required block size needing to be free before coalesce done */ #define BINRANGE (BYTESPERWORD * 1) /* see assumptions */ #define NBINS 16 #define MAXBINSIZE (BINRANGE*(NBINS)-1) #define LARGEBLOCK 512 /* * Code macros. */ #define SIZE(block) ((size_t)((block)->size & SIZEMASK)) #define BITSTOWORDS(bits) ((bits+(BITSPERWORD-1))/BITSPERWORD) #define BYTESTOWORDS(bytes) ((bytes+(BYTESPERWORD-1))/BYTESPERWORD) #define ADDBYTES(bp, bytes) (BlockP)((char *)bp + (bytes)) #define ADDBYTESTO(bp, bytes) bp = (BlockP)((char *)bp + (bytes)) #define PTRDIFF(hi, lo) ((char *)hi - (char *)lo) #define FREE(block) (FREEBIT & ((BlockP)block)->size) #define HEAPHOLE(block) (HEAPHOLEBIT & block->size) #ifdef BLOCKS_GUARDED #define INVALID(block) (((BlockP)block)->guard != GUARDCONSTANT) #else #define INVALID(block) (0) #endif #define BADUSERBLOCK(block) (INVALID(ADDBYTES(block,-OVERHEAD)) \ || FREE(ADDBYTES(block,-OVERHEAD))) #endif