/* 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: heap.c * Purpose: provide malloc-style heap allocation in a flex block * Author: NR, IDJ * Status: under development * History: 20-Mar-89 IDJ created * 13-Apr-89 IDJ modified to loop if you can't allocate enough * space in a single increment to flex block. * 14-Apr-89 IDJ applications which repeatedly ask for large * chunks of memory (without doing much in between) will * delay events for other applications. * 5-May-89 IDJ made slot shrink when doing heap_free() * 21-Jun-89 IDJ made shrinking of slot conditional on flag to * heap_init(). * 21-Jun-89 IDJ removed different error codes for failures to * do a heap_alloc. * 7-Dec-89 IDJ No need for this stuff anymore. New malloc does * it all * */ #include "werr.h" #include "heap.h" #include "os.h" #include "flex.h" #include "msgs.h" #include <stdlib.h> #include "h.verintern.messages" #if FALSE static int *Heap; static int heap__initialised=0; static BOOL heap__shrinkflex = TRUE; #define heap__BLOCKSIZE 4096 #define OS_Heap 0x1D void heap__check(void) { if(heap__initialised == 0) werr(TRUE, msgs_lookup(MSGS_Heap5)); } #endif void heap_init(BOOL heap_shrink) { #if FALSE os_regset r; os_error *e; /* is the flex block to be shrunk if poss. on heap free */ heap__shrinkflex = heap_shrink; /* create flex block to be used as heap */ if (!flex_alloc((flex_ptr)&Heap, heap__BLOCKSIZE)) werr (TRUE, msgs_lookup(MSGS_heap1)); /* initialise heap as being in the flex block we just created */ r.r[0] = 0; r.r[1] = (int) Heap; r.r[3] = flex_size((flex_ptr)&Heap); if ((e = os_swix(OS_Heap, &r)) != 0) werr (TRUE, e->errmess); heap__initialised = 1; #endif } void *heap_alloc(unsigned int size) { return (malloc(size)); } /* old implementation of heap stuff */ #if FALSE os_regset r; os_error *e; heap__check(); /* see if we can satisfy request in heap as it is */ r.r[0] = 2; /* claim block from heap manager */ r.r[1] = (int) Heap; r.r[3] = (int)size; while((e = os_swix(OS_Heap, &r)) != 0) { /* see if failure to allocate block */ if (e->errnum == 0x0184 /* HeapFail_Alloc */) { int *oldHeap = Heap; if (flex_extend((flex_ptr)&Heap, flex_size((flex_ptr)&Heap) + heap__BLOCKSIZE)) { if (Heap == oldHeap) /* heap hasn't moved */ { os_error *ext; r.r[0] = 5; r.r[1] = (int)Heap; r.r[3] = (int)heap__BLOCKSIZE; if ((ext = os_swix(OS_Heap, &r)) != 0) werr(TRUE, msgs_lookup(MSGS_heap2), ext->errmess); /*Heap[3] += heap__BLOCKSIZE; Removed - bug fixed in RISCOS */ r.r[0] = 2; /* claim block again */ r.r[1] = (int) Heap; r.r[3] = (int) size; /*e = os_swix(OS_Heap, &r);*/ } else return (void *)0; /* flex has moved the heap */ } else return (void *)0; /* the flex area is full (ie. out of memory) */ } else werr(1, msgs_lookup(MSGS_heap3)); } if (e == 0) return (void *)r.r[2]; else return (void *)0; } #endif void heap_free(void *heapptr) { free(heapptr); } /* old implementation of heap stuff */ #if FALSE os_regset r; os_error *e; static int free_count = 0; int change_flex; heap__check(); if(!heap__shrinkflex) { r.r[0] = 3; /* release block */ r.r[1] = (int) Heap; r.r[2] = (int) heapptr; if((e = os_swix(OS_Heap, &r)) != 0) werr(FALSE, msgs_lookup(MSGS_heap4), e->errmess); } else { /* examine the size of the block being freed */ r.r[0] = 6; r.r[1] = (int)Heap; r.r[2] = (int)heapptr; if((e = os_swix(OS_Heap, &r)) != 0) werr(FALSE, msgs_lookup(MSGS_heap4), e->errmess); /* keep a count of max free space */ free_count += r.r[3]; r.r[0] = 3; /* release block */ r.r[1] = (int) Heap; r.r[2] = (int) heapptr; if((e = os_swix(OS_Heap, &r)) != 0) werr(FALSE, msgs_lookup(MSGS_heap4), e->errmess); r.r[0] = 5; /* extend heap (with neg. increment to shrink) */ r.r[1] = (int)Heap; r.r[3] = -free_count; if((e = os_swix(OS_Heap, &r)) != 0) change_flex = r.r[3]; /* a positive value if failed */ else change_flex = -r.r[3]; /* a negative (preserved) value if ok */ free_count -= change_flex; /* amend count accordingly */ flex_extend((flex_ptr)&Heap, flex_size((flex_ptr)&Heap) - change_flex); } } #endif