T_doubleLinkList DoubleLinkListCreate(T_void) { T_doubleLinkListStruct *p_head ; DebugRoutine("DoubleLinkListCreate") ; #ifdef COMPILE_OPTION_DOUBLE_LINK_OUTPUT printf("!A 1 list_%s\n", DebugGetCallerName()) ; #endif p_head = ICreateNode() ; DebugCheck(p_head != NULL) ; if (p_head) { p_head->p_next = p_head ; /* Next is self. */ p_head->p_previous = p_head ; /* Previous is self. */ p_head->p_head = p_head ; /* Self points to self. */ p_head->countOrData.count = 0 ; /* No elements. */ } #ifndef NDEBUG if (G_doOutput==FALSE) { G_doOutput = TRUE ; atexit(IDumpMaxCount) ; } #endif DebugEnd() ; return (T_doubleLinkList) p_head ; }
/** * DoubleLinkListDestroy goes through a list of double link list nodes * and detaches the data with them and then deletes all the nodes. * * NOTE: * The calling routine must realize that this routine does not * deallocate memory attached to a node, it is assumed that the calling * routine will do this. * * @param linkList -- Handle to link list to destroy * *<!-----------------------------------------------------------------------*/ T_void DoubleLinkListDestroy(T_doubleLinkList linkList) { T_doubleLinkListStruct *p_head ; DebugRoutine("DoubleLinkListDestroy") ; DebugCheck(linkList != DOUBLE_LINK_LIST_BAD) ; #ifdef COMPILE_OPTION_DOUBLE_LINK_OUTPUT printf("!F 1 list_%s\n", DebugGetCallerName()) ; #endif /* Get a quick pointer. */ p_head = (T_doubleLinkListStruct *)linkList ; DebugCheck(p_head->tag == DOUBLE_LINK_LIST_TAG) ; /* Remove all items in the list. Hopefully */ /* all attached data is not allocated memory or is being */ /* managed by someone else. */ while (p_head->p_next != p_head) DoubleLinkListRemoveElement((T_doubleLinkListElement)p_head->p_next) ; /* Destroy this element now. */ IDestroyNode(p_head) ; DebugEnd() ; }
/** * DoubleLinkListAddElementBeforeElement adds a new element before * another element in a link list. * * @param element -- handle of element to go before * @param p_data -- Pointer to element data * *<!-----------------------------------------------------------------------*/ T_doubleLinkListElement DoubleLinkListAddElementBeforeElement( T_doubleLinkListElement element, T_void *p_data) { T_doubleLinkListStruct *p_before ; T_doubleLinkListStruct *p_head ; T_doubleLinkListStruct *p_element ; DebugRoutine("DoubleLinkListAddElementBeforeElement") ; DebugCheck(element != DOUBLE_LINK_LIST_ELEMENT_BAD) ; /* Get a quick pointer. */ p_before = (T_doubleLinkListStruct *)element; DebugCheck(p_before->tag == DOUBLE_LINK_LIST_TAG) ; p_head = p_before->p_head ; DebugCheck(p_head != NULL) ; DebugCheck(p_head->tag == DOUBLE_LINK_LIST_TAG) ; DebugCheck(p_head->p_head == p_head) ; if ((p_head) && (p_before)) { /* Create a new element. */ #ifdef COMPILE_OPTION_DOUBLE_LINK_OUTPUT printf("!A 1 node_%s\n", DebugGetCallerName()) ; #endif p_element = ICreateNode() ; DebugCheck(p_element != NULL) ; if (p_element) { /* Attach the data to the element. */ p_element->countOrData.p_data = p_data ; p_element->p_previous = p_before->p_previous ; p_element->p_next = p_before ; p_element->p_head = p_head ; p_before->p_previous->p_next = p_element ; p_before->p_previous = p_element ; p_head->countOrData.count++ ; } } DebugEnd() ; return ((T_doubleLinkListElement)p_element) ; }
T_void *FileLoad(T_byte8 *p_filename, T_word32 *p_size) { T_byte8 *p_data ; T_file file ; DebugRoutine("FileLoad") ; DebugCheck(p_filename != NULL) ; DebugCheck(p_size != NULL) ; /* See how big the file is so we know how much memory to allocate. */ *p_size = FileGetSize(p_filename) ; #ifdef COMPILE_OPTION_FILE_OUTPUT printf("!A 1 file_%s\n", p_filename) ; printf("!A 1 file_r_%s\n", DebugGetCallerName()) ; #endif if (*p_size) { /* Allocate the memory for the file. */ p_data = MemAlloc(*p_size) ; DebugCheck(p_data != NULL) ; /* Make sure we got the memory. */ if (p_data != NULL) { /* If memory was allocated, read in the file into this memory. */ file = FileOpen(p_filename, FILE_MODE_READ) ; FileRead(file, p_data, *p_size) ; FileClose(file) ; } else { /* If memory was not allocated, return with a zero length. */ *p_size = 0 ; } } else { *p_size = 0 ; p_data = NULL ; } DebugEnd() ; /* Return the pointer to the data. */ return p_data ; }
/** * DoubleLinkListRemoveElement removes an element from a link list. * This routine also returns the data that was attached to this element. * * @param element -- removes the element from the list. * * @return Previously attached node data * *<!-----------------------------------------------------------------------*/ T_void *DoubleLinkListRemoveElement(T_doubleLinkListElement element) { T_doubleLinkListStruct *p_node ; T_void *p_data = NULL ; DebugRoutine("DoubleLinkListRemoveElement") ; DebugCheck(element != DOUBLE_LINK_LIST_ELEMENT_BAD) ; /* Get a quick pointer. */ p_node = (T_doubleLinkListStruct *)element; DebugCheck(p_node->tag == DOUBLE_LINK_LIST_TAG) ; /* Make sure we are not trying to delete the head. */ DebugCheck(p_node->p_head != p_node) ; if (p_node) { /* Detach the node from the list. */ p_node->p_next->p_previous = p_node->p_previous ; p_node->p_previous->p_next = p_node->p_next ; /* Get the attached data. */ p_data = p_node->countOrData.p_data ; /* Decrement the count of items on this list. */ p_node->p_head->countOrData.count-- ; /* Release the node from memory. */ #ifdef COMPILE_OPTION_DOUBLE_LINK_OUTPUT printf("!F 1 node_%s\n", DebugGetCallerName()) ; #endif IDestroyNode(p_node) ; } DebugEnd() ; return p_data ; }
/** * DoubleLinkListFreeAndDestroy goes through a linked list and does a * MemFree on each of the data elements and then calls Destroy on the * whole list. * * @param linkList -- Handle to link list to destroy * *<!-----------------------------------------------------------------------*/ T_void DoubleLinkListFreeAndDestroy(T_doubleLinkList *linkList) { T_doubleLinkListStruct *p_head ; T_doubleLinkListStruct *p_at ; T_doubleLinkListStruct *p_next ; DebugRoutine("DoubleLinkListFreeAndDestroy") ; DebugCheck(linkList != DOUBLE_LINK_LIST_BAD) ; #ifdef COMPILE_OPTION_DOUBLE_LINK_OUTPUT printf("!F 1 list_%s\n", DebugGetCallerName()) ; #endif /* Get a quick pointer. */ p_head = (T_doubleLinkListStruct *)(*linkList) ; DebugCheck(p_head->tag == DOUBLE_LINK_LIST_TAG) ; /* Remove all items in the list. Hopefully */ /* all attached data is not allocated memory or is being */ /* managed by someone else. */ if (p_head) { p_at = p_head->p_next ; while ((p_at != p_head) && (p_at != DOUBLE_LINK_LIST_ELEMENT_BAD)) { p_next = p_at->p_next ; if (p_at->countOrData.p_data != NULL) { MemFree(p_at->countOrData.p_data) ; p_at->countOrData.p_data = NULL ; } p_at = p_next ; } } DoubleLinkListDestroy(*linkList) ; linkList = DOUBLE_LINK_LIST_BAD ; DebugEnd() ; }
/** * FindFreeSpace is the routine called by MemAlloc when it just tried * to allocate new memory and could not. This routine is called to free * up space use by discarded memory. If there is memory freed up, this * routine returns with a TRUE, otherwise FALSE. It does this by looking * at the discard list and freeing up the oldest block. It will only * discard one block and then return with a TRUE status. * Also, before the block is freed, it's callback routine is called * to note the block's disappearance. * * NOTE: * A future version might want to free up a certain amount of space * instead of being called several times. However, when you are running * out of memory, this method is probably just as good. * * @return TRUE = memory was freed * FALSE = no more memory can be freed. * *<!-----------------------------------------------------------------------*/ static E_Boolean IMemFindFreeSpace(T_void) { E_Boolean answer = FALSE ; T_memBlockHeader *p_header ; T_word16 pos ; DebugRoutine("IMemFindFreeSpace") ; //printf("Finding free space!\n") ; //fprintf(stderr, "Finding free space!") ; MemCheck(2925) ; //MemDumpDiscarded() ; //_heapmin() ; /* printf("List:\n") ; p_header = P_startOfDiscardList ; while (p_header) { printf(" %p\n", ((T_byte8 *)p_header)+sizeof(T_memBlockHeader)) ; p_header = p_header->p_nextBlock ; } printf("End of list\n\n") ; */ /* Do we have any blocks on the discard list? */ if (P_startOfDiscardList != NULL) { /* Yes, call it's callback routine -- it is about to be */ /* freed from memory. Make sure to pass a pointer to the */ /* true data part (past header) of the memory block. */ p_header = P_startOfDiscardList ; /* Make sure you are freeing a discarded block. */ DebugCheck(strcmp(p_header->blockTag, "DaG") == 0) ; //printf("Discard %p\n", (((T_byte8 *)p_header)+sizeof(T_memBlockHeader))) ; p_header->p_callback(((T_byte8 *)p_header)+sizeof(T_memBlockHeader)) ; /* Make sure you are freeing a discarded block. */ DebugCheck(strcmp(p_header->blockTag, "DaG") == 0) ; /* Now that the block's owner has been notified, we */ /* can continue. */ /* We first need to note the previous block that the next block */ /* is disappearing. */ #if 0 if (p_header->p_nextBlock != NULL) { p_header->p_nextBlock->p_prevBlock = NULL ; /* If there is a previous block, make it the new end. */ P_startOfDiscardList = p_header->p_nextBlock ; } else { /* If there is no previous block, the list is now empty. */ P_endOfDiscardList = P_startOfDiscardList = NULL ; } #endif P_startOfDiscardList = p_header->p_nextBlock ; if (P_startOfDiscardList == NULL) P_endOfDiscardList = NULL ; else p_header->p_nextBlock->p_prevBlock = NULL ; /* Note that the total is now less. */ G_sizeAllocated -= sizeof(T_memBlockHeader) + p_header->size ; #ifdef COMPILE_OPTION_OUTPUT_ALLOCATION printf("!F %d %s\n", p_header->size, DebugGetCallerFile()) ; printf("!F %d %s:%s\n", p_header->size, DebugGetCallerFile(), DebugGetCallerName()) ; #endif #ifndef NDEBUG /* Make sure we didn't roll under. */ DebugCheck(G_sizeAllocated < 0xF0000000) ; #endif #ifdef _MEM_CHECK_FULL_ /* Find the block on the list (if it is there). */ pos = IFindPointer(p_header) ; if (pos == 0xFFFF) { printf("bad attempt to free memory at %p\n", p_header+1) ; DebugCheck(FALSE) ; } /* Remove the block from the alloc list and put on the free list. */ G_blockList[pos] = ((T_memBlockHeader *)((T_word32)G_firstFree)) ; G_firstFree = pos ; #endif #ifndef NDEBUG /* Mark the block as fully freed. */ strcpy(p_header->blockTag, "!!!") ; /* Fill the block with junk. */ memset(((T_byte8 *)p_header)+sizeof(T_memBlockHeader), 0xCE, p_header->size) ; #endif #ifndef NDEBUG memset(p_header, 0xCD, sizeof(T_memBlockHeader) + p_header->size) ; #endif /* Ok, now we can actually free the block. */ free(p_header) ; /* Note that memory *was* freed. */ answer = TRUE ; } DebugCheck(answer < BOOLEAN_UNKNOWN) ; DebugEnd() ; return answer ; }
/** * MemFree frees a block of memory that was previously allocated. * It also checks the integrity of the pointer given to it. If the * pointer is NULL, it crashes. If the pointer does not point to a * block that was allocated, it crashes. * * NOTE: * None that I can think of (except this will definitely slow down * the system a little). * * @param p_data -- Pointer to block to free * Normally we can assume p_data points to data and is not NULL. * *<!-----------------------------------------------------------------------*/ T_void MemFree(T_void *p_data) { T_byte8 *p_bytes ; T_memBlockHeader *p_header ; T_word16 pos ; DebugRoutine("MemFree") ; DebugCheck(p_data != NULL) ; /* Back up from the pointer we are given and try to find the header tag. */ p_bytes = p_data ; p_bytes -= sizeof(T_memBlockHeader) ; p_header = (T_memBlockHeader *)p_bytes ; //printf("Freeing %p, ID: %d, for %s\n", p_data, p_header->blockId, DebugGetCallerName()) ; //printf("free ID: %ld, @ %p, %s\n", p_header->blockId, p_data, DebugGetCallerName()) ; //fflush(stdout) ; #ifdef _MEM_CHECK_FULL_ MemCheck(10210) ; /* Find the block on the list (if it is there). */ pos = IFindPointer(p_header) ; if (pos == 0xFFFF) { printf("bad attempt to free memory at %p\n", p_data) ; DebugCheck(FALSE) ; } /* Remove the block from the alloc list and put on the free list. */ G_blockList[pos] = ((T_memBlockHeader *)((T_word32)G_firstFree)) ; G_firstFree = pos ; #endif //printf("MemFree: %s (%p)\n", ((T_memBlockHeader *)p_bytes)->blockTag, p_data) ; /* Make sure we are freeing one of our blocks. */ DebugCheck(strcmp (((T_memBlockHeader *)p_bytes)->blockTag, "DaG") != 0) ; DebugCheck(strcmp (((T_memBlockHeader *)p_bytes)->blockTag, "TaG") == 0) ; /* Check if the tag is there, or bomb. */ DebugCheck(strcmp(((T_memBlockHeader *)p_bytes)->blockTag, "TaG") == 0) ; strcpy(((T_memBlockHeader *)p_bytes)->blockTag, "!!!"); //#ifndef NDEBUG /* Note that the total is now less. */ G_sizeAllocated -= sizeof(T_memBlockHeader) + p_header->size ; #ifdef COMPILE_OPTION_OUTPUT_ALLOCATION printf("!F %d %s (@0x%08X)\n", p_header->size, DebugGetCallerFile(), p_bytes) ; printf("!F %d %s:%s\n", p_header->size, DebugGetCallerFile(), DebugGetCallerName()) ; #endif #ifndef NDEBUG /* Make sure we didn't roll under. */ DebugCheck(G_sizeAllocated < 0xF0000000) ; #endif #ifndef NDEBUG memset(p_bytes, 0xCD, sizeof(T_memBlockHeader) + p_header->size) ; #endif /* OK, free up the valid block. */ free(p_bytes) ; //puts("OK") ; //printf("FREE: %d \r", FreeMemory()) ; //fflush(stdout) ; /* Cound how many are freed. */ G_deallocCount++ ; DebugEnd() ; }
/** * Currently, this routine is provided more for debugging than an * actual utility. However, this should be the one routine that everyone * calls to allocate memory (no matter what system). * Since we use this for debugging, we will assign a number to each * piece of memory that is allocated and will attach a "tag" at the * beginning to make the system have a way to check if we are later * freeing a block, or just random memory. * Space is also provided to allow the block to be declared as discard- * able. A discardable block needs to be able to be placed on a double * link list and have a call back function (for when the block is actually * discarded). See MemMarkDiscardable for more details. * * NOTE: * I'm sure what the size limitations for this will be, so we had * best stick to 64K or smaller allocations. Note that this routine is * also made for blocks of typically larger than 256 bytes. If you got * alot of small parts, you might want to try doing it a different way. * * @param size -- Amount of memory to allocate * * @return Pointer or NULL to memory block. * *<!-----------------------------------------------------------------------*/ T_void *MemAlloc(T_word32 size) { T_byte8 *p_memory ; T_memBlockHeader *p_header ; E_Boolean memFound ; T_word16 next ; const char *p_name ; long line ; DebugRoutine("MemAlloc") ; DebugGetCaller(&p_name, &line) ; //printf("|%s,%ld\.0\n", p_name, size) ; #ifdef COMPILE_OPTION_OUTPUT_ALLOCATION //printf("!A %d %s\n", size, DebugGetCallerFile()) ; printf("!A %d %s:%s ", size, DebugGetCallerFile(), DebugGetCallerName()) ; #endif /* Allocate memory and room for our tag. */ do { //DebugCheck(_heapchk() == _HEAPOK) ; p_memory = malloc(sizeof(T_memBlockHeader)+size) ; //DebugCheck(_heapchk() == _HEAPOK) ; /* If the memory was not allocated, check to see if */ /* Memory can be allocated. */ if (p_memory == NULL) { /* Check if there are blocks that we can discard. */ if (IMemFindFreeSpace()==TRUE) { /* If there is, note that we have not found memory */ /* so the loop continues trying to allocate. */ memFound = FALSE ; } else { /* If there is not, say we found memory to break */ /* out of the loop (when we actually did not). */ memFound = TRUE ; } } else { memFound = TRUE ; } } while (memFound == FALSE) ; /* Check to see if we actually got the memory. */ if (p_memory != NULL) { /* Initialize the header for this block. */ p_header = (T_memBlockHeader *)p_memory ; #ifdef _MEM_RECORD_ROUTINES_ DebugGetCaller(&p_header->routine, &p_header->line) ; #endif #ifdef _MEM_CHECK_FULL_ /* Place the block on the allocated block list. */ if (G_firstFree == 0xFFFF) { /* Use a fresh block. */ DebugCheck(G_numBlocks < MAX_BLOCK_LIST) ; G_blockList[G_numBlocks++] = p_header ; } else { /* Take one off the free list. */ next = (T_word32)G_blockList[G_firstFree] ; G_blockList[G_firstFree] = p_header ; G_firstFree = next ; } #endif p_header->size = size ; /* Make sure the block has been tagged. */ strcpy((char *)p_header->blockTag, "TaG") ; /* Make sure that the block has an id (for debugging). */ p_header->blockId = G_allocCount++ ; /* Clear out the previous and next pointers. */ p_header->p_nextBlock = p_header->p_prevBlock = NULL ; /* Make sure the callback routine points to no where. */ p_header->p_callback = NULL ; /* Get who called this routine. */ //DebugGetCaller(&p_header->routine, &p_header->line) ; /* Move pointer up past header. That way we can return a pointer to where the information really is. */ p_memory += sizeof(T_memBlockHeader) ; //DebugCheck(_heapchk() == _HEAPOK) ; } //printf("ALLC: %d \r", FreeMemory()) ; //fflush(stdout) ; //printf("alloc %d, ID: %d, @ %p, %s\n", size, p_header->blockId, p_memory, DebugGetCallerName()) ; //fflush(stdout) ; //DebugCheck(p_memory != NULL) ; //#ifndef NDEBUG /* Add to the total amount of memory allocated this size. */ G_sizeAllocated += sizeof(T_memBlockHeader)+size ; /* Is this the biggest it has ever been? */ if (G_sizeAllocated > G_maxSizeAllocated) /* Yes, it is bigger. Store this new maximum. */ G_maxSizeAllocated = G_sizeAllocated ; //#endif DebugEnd() ; #ifndef REAL_MODE if (p_memory==NULL) { /* fail hard! out of memory ! */ GrGraphicsOff(); printf ("Out of memory error, exiting\n"); MemDumpDiscarded() ; exit(-1); } #endif #ifdef COMPILE_OPTION_OUTPUT_ALLOCATION printf("(@0x%08X)\n", p_memory) ; #endif return p_memory ; }