# HG changeset patch # User Eric Wing # Date 1289029049 25200 # Node ID 54aa96ae89122eec181d1592a194db71aa508e33 # Parent bfe90b4f3d876a3812b12abee741b2596684258f Added LinkedList class to project. ALmixer now saves ALmixer_Data instances in a private linked list so when Quit is called, this memory can be cleaned up. This is meant to deal with two problems. First, SDL_sound does something similar which means since I wrap SDL_sound structures, I may be left with dangling pointers if. Second is the obvious auto-cleanup when quiting which is convenient for resetting. diff -r bfe90b4f3d87 -r 54aa96ae8912 ALmixer.c --- a/ALmixer.c Fri Nov 05 20:59:13 2010 -0700 +++ b/ALmixer.c Sat Nov 06 00:37:29 2010 -0700 @@ -62,6 +62,12 @@ */ #include "CircularQueue.h" +/* SDL_sound keeps a private linked list of sounds which get auto-deleted + * on Sound_Quit. This might actually create some leaks for me in certain + * usage patterns. To be safe, I should do the same. + */ +#include "LinkedList.h" + #ifdef ENABLE_ALMIXER_THREADS /* Needed for the Mutex locks (and threads if enabled) */ #ifdef ALMIXER_COMPILE_WITHOUT_SDL @@ -227,6 +233,9 @@ static SDL_Thread* Stream_Thread_global = NULL; #endif +static LinkedList* s_listOfALmixerData = NULL; + + #ifdef __APPLE__ static ALvoid Internal_alcMacOSXMixerOutputRate(const ALdouble sample_rate) @@ -6398,11 +6407,24 @@ Channel_Data_Callback = NULL; Channel_Data_Callback_Userdata = NULL; + /* Allocate memory for linked list of ALmixerData. */ + s_listOfALmixerData = LinkedList_Create(); + if(NULL == s_listOfALmixerData) + { + ALmixer_SetError("Couldn't create linked list"); + alcDestroyContext(context); + alcCloseDevice(dev); + ALmixer_Initialized = 0; + Number_of_Channels_global = 0; + return AL_FALSE; + } + /* Allocate memory for the list of channels */ ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel)); if(NULL == ALmixer_Channel_List) { ALmixer_SetError("Out of Memory for Channel List"); + LinkedList_Free(s_listOfALmixerData); alcDestroyContext(context); alcCloseDevice(dev); ALmixer_Initialized = 0; @@ -6416,6 +6438,7 @@ { ALmixer_SetError("Out of Memory for Source Map List"); free(ALmixer_Channel_List); + LinkedList_Free(s_listOfALmixerData); alcDestroyContext(context); alcCloseDevice(dev); ALmixer_Initialized = 0; @@ -6430,6 +6453,7 @@ ALmixer_SetError("Out of Memory for sources"); free(Source_Map_List); free(ALmixer_Channel_List); + LinkedList_Free(s_listOfALmixerData); alcDestroyContext(context); alcCloseDevice(dev); ALmixer_Initialized = 0; @@ -6446,6 +6470,7 @@ ALmixer_SetError("Couldn't generate sources: %s\n", alGetString(error)); free(ALmixer_Channel_List); free(Source_Map_List); + LinkedList_Free(s_listOfALmixerData); alcDestroyContext(context); alcCloseDevice(dev); ALmixer_Initialized = 0; @@ -6486,6 +6511,9 @@ /* ALmixer_OutputDecoders(); */ + + + #ifdef ENABLE_ALMIXER_THREADS s_simpleLock = SDL_CreateMutex(); if(NULL == s_simpleLock) @@ -6494,6 +6522,7 @@ free(source); free(ALmixer_Channel_List); free(Source_Map_List); + LinkedList_Free(s_listOfALmixerData); alcDestroyContext(context); alcCloseDevice(dev); ALmixer_Initialized = 0; @@ -6510,6 +6539,7 @@ free(source); free(ALmixer_Channel_List); free(Source_Map_List); + LinkedList_Free(s_listOfALmixerData); alcDestroyContext(context); alcCloseDevice(dev); ALmixer_Initialized = 0; @@ -6948,11 +6978,23 @@ Channel_Data_Callback = NULL; Channel_Data_Callback_Userdata = NULL; + /* Allocate memory for linked list of ALmixerData. */ + s_listOfALmixerData = LinkedList_Create(); + if(NULL == s_listOfALmixerData) + { + ALmixer_SetError("Couldn't create linked list"); + ALmixer_Initialized = 0; + Number_of_Channels_global = 0; + return AL_FALSE; + } + + /* Allocate memory for the list of channels */ ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel)); if(NULL == ALmixer_Channel_List) { ALmixer_SetError("Out of Memory for Channel List"); + LinkedList_Free(s_listOfALmixerData); ALmixer_Initialized = 0; Number_of_Channels_global = 0; return AL_FALSE; @@ -6964,6 +7006,7 @@ { ALmixer_SetError("Out of Memory for Source Map List"); free(ALmixer_Channel_List); + LinkedList_Free(s_listOfALmixerData); ALmixer_Initialized = 0; Number_of_Channels_global = 0; return AL_FALSE; @@ -6976,6 +7019,7 @@ ALmixer_SetError("Out of Memory for sources"); free(Source_Map_List); free(ALmixer_Channel_List); + LinkedList_Free(s_listOfALmixerData); ALmixer_Initialized = 0; Number_of_Channels_global = 0; return AL_FALSE; @@ -6990,6 +7034,7 @@ ALmixer_SetError("Couldn't generate sources: %s\n", alGetString(error)); free(ALmixer_Channel_List); free(Source_Map_List); + LinkedList_Free(s_listOfALmixerData); ALmixer_Initialized = 0; Number_of_Channels_global = 0; return AL_FALSE; @@ -7121,6 +7166,17 @@ } alcCloseDevice(dev); + /* Delete the list of ALmixerData's before Sound_Quit deletes + * its own underlying information and I potentially have dangling pointers. + */ + while(LinkedList_Size(s_listOfALmixerData) > 0) + { + ALmixer_Data* almixer_data = LinkedList_PopBack(s_listOfALmixerData); + ALmixer_FreeData(almixer_data); + } + LinkedList_Free(s_listOfALmixerData); + s_listOfALmixerData = NULL; + Sound_Quit(); #ifdef ALMIXER_COMPILE_WITHOUT_SDL @@ -7857,6 +7913,10 @@ return NULL; } + /* Add the ALmixerData to an internal linked list so we can delete it on + * quit and avoid messy dangling issues with Sound_Quit + */ + LinkedList_PushBack(s_listOfALmixerData, ret_data); return ret_data; } @@ -8139,6 +8199,11 @@ } } free(data->buffer); + + LinkedList_Remove(s_listOfALmixerData, + LinkedList_Find(s_listOfALmixerData, data, NULL) + ); + free(data); } diff -r bfe90b4f3d87 -r 54aa96ae8912 CMakeLists.txt --- a/CMakeLists.txt Fri Nov 05 20:59:13 2010 -0700 +++ b/CMakeLists.txt Sat Nov 06 00:37:29 2010 -0700 @@ -62,6 +62,8 @@ ${ALmixer_SOURCE_DIR}/ALmixer.c ${ALmixer_SOURCE_DIR}/CircularQueue.c ${ALmixer_SOURCE_DIR}/CircularQueue.h + ${ALmixer_SOURCE_DIR}/LinkedList.c + ${ALmixer_SOURCE_DIR}/LinkedList.h ) SET(PUBLIC_HEADERS diff -r bfe90b4f3d87 -r 54aa96ae8912 LinkedList.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LinkedList.c Sat Nov 06 00:37:29 2010 -0700 @@ -0,0 +1,306 @@ +#include "LinkedList.h" +#include /* for NULL */ +#include /* for malloc/free */ +#include /* for debugging */ + +struct LinkedListNode +{ + LinkedListNode* nextNode; + LinkedListNode* previousNode; + void* dataPtr; +}; + +struct LinkedList +{ + size_t currentSize; + LinkedListNode* headPtr; + LinkedListNode* tailPtr; +}; + + +LinkedListNode* LinkedListNode_Create() +{ + LinkedListNode* list_node; + list_node = (LinkedListNode*)calloc(1, sizeof(LinkedListNode)); + if(NULL == list_node) + { + /* Very bad, but not sure what to do here. */ + return NULL; + } + + return list_node; +} + + +void LinkedListNode_Free(LinkedListNode* list_node) +{ + if(NULL == list_node) + { + return; + } + free(list_node); +} + + +LinkedList* LinkedList_Create() +{ + LinkedList* linked_list; + linked_list = (LinkedList*)calloc(1, sizeof(LinkedList)); + if(NULL == linked_list) + { + /* Very bad, but not sure what to do here. */ + return NULL; + } + + return linked_list; +} + +void LinkedList_Free(LinkedList* linked_list) +{ + /* Both functions check for NULL */ + LinkedList_Clear(linked_list); + free(linked_list); +} + + +/** + * Returns 1 if successful, 0 if failure. + */ +unsigned int LinkedList_PushFront(LinkedList* linked_list, void* new_item) +{ + LinkedListNode* new_node; + + if(NULL == linked_list) + { + return 0; + } + + new_node = LinkedListNode_Create(); + if(NULL == new_node) + { + return 0; + } + + new_node->dataPtr = new_item; + + if(0 == linked_list->currentSize) + { + linked_list->tailPtr = new_node; + } + else + { + LinkedListNode* head_node = linked_list->headPtr; + new_node->nextNode = head_node; + head_node->previousNode = new_node; + } + + linked_list->headPtr = new_node; + linked_list->currentSize++; + return 1; +} + +unsigned int LinkedList_PushBack(LinkedList* linked_list, void* new_item) +{ + LinkedListNode* new_node; + + if(NULL == linked_list) + { + return 0; + } + + new_node = LinkedListNode_Create(); + if(NULL == new_node) + { + return 0; + } + + new_node->dataPtr = new_item; + + if(0 == linked_list->currentSize) + { + linked_list->headPtr = new_node; + } + else + { + LinkedListNode* tail_node = linked_list->tailPtr; + new_node->previousNode = tail_node; + tail_node->nextNode = new_node; + } + + linked_list->tailPtr = new_node; + linked_list->currentSize++; + return 1; + +} + +void* LinkedList_PopFront(LinkedList* linked_list) +{ + LinkedListNode* head_node; + void* return_data; + + if(NULL == linked_list) + { + return 0; + } + if(0 == linked_list->currentSize) + { + return NULL; + } + + head_node = linked_list->headPtr; + return_data = head_node->dataPtr; + + if(1 == linked_list->currentSize) + { + LinkedList_Clear(linked_list); + } + else + { + LinkedListNode* next_node = head_node->nextNode; + next_node->previousNode = NULL; + LinkedListNode_Free(head_node); + linked_list->headPtr = next_node; + linked_list->currentSize = linked_list->currentSize - 1; + + } + return return_data; +} + +void* LinkedList_PopBack(LinkedList* linked_list) +{ + LinkedListNode* tail_node; + void* return_data; + + if(NULL == linked_list) + { + return NULL; + } + if(0 == linked_list->currentSize) + { + return NULL; + } + + tail_node = linked_list->tailPtr; + return_data = tail_node->dataPtr; + + if(1 == linked_list->currentSize) + { + LinkedList_Clear(linked_list); + } + else + { + LinkedListNode* previous_node = tail_node->previousNode; + previous_node->nextNode = NULL; + LinkedListNode_Free(tail_node); + linked_list->tailPtr = previous_node; + linked_list->currentSize = linked_list->currentSize - 1; + } + return return_data; +} + +size_t LinkedList_Size(LinkedList* linked_list) +{ + if(NULL == linked_list) + { + return 0; + } + return linked_list->currentSize; +} + +void LinkedList_Clear(LinkedList* linked_list) +{ + if(NULL == linked_list) + { + return; + } + + LinkedListNode* current_node = linked_list->headPtr; + LinkedListNode* next_node; + while(NULL != current_node) + { + next_node = current_node->nextNode; + LinkedListNode_Free(current_node); + current_node = next_node; + } + linked_list->headPtr = NULL; + linked_list->tailPtr = NULL; + linked_list->currentSize = 0; +} + +void* LinkedListNode_GetData(LinkedListNode* list_node) +{ + if(NULL == list_node) + { + return NULL; + } + return list_node->dataPtr; +} + +LinkedListNode* LinkedList_Find(LinkedList* linked_list, void* the_data, LinkedListNode* start_node) +{ + LinkedListNode* current_node; + if(NULL == linked_list) + { + return; + } + if(NULL == start_node) + { + start_node = linked_list->headPtr; + } + + for(current_node = start_node; NULL != current_node; current_node = current_node->nextNode) + { + if(current_node->dataPtr == the_data) + { + return current_node; + } + } + return current_node; +} + +/* Make sure your LinkedListNode is actually connected to the + * LinkedList instance you pass. + */ +unsigned int LinkedList_Remove(LinkedList* linked_list, LinkedListNode* list_node) +{ + LinkedListNode* previous_node; + LinkedListNode* next_node; + if(NULL == linked_list) + { + return 0; + } + if(NULL == list_node) + { + return 0; + } + + if(1 == linked_list->currentSize) + { + LinkedList_Clear(linked_list); + } + else if(list_node == linked_list->headPtr) + { + LinkedList_PopFront(linked_list); + } + else if(list_node == linked_list->tailPtr) + { + LinkedList_PopBack(linked_list); + } + else + { + previous_node = list_node->previousNode; + next_node = list_node->nextNode; + + previous_node->nextNode = next_node; + next_node->previousNode = previous_node; + LinkedListNode_Free(list_node); + + linked_list->currentSize = linked_list->currentSize - 1; + } + + return 1; + +} + + + diff -r bfe90b4f3d87 -r 54aa96ae8912 LinkedList.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LinkedList.h Sat Nov 06 00:37:29 2010 -0700 @@ -0,0 +1,45 @@ +#ifndef C_LINKED_LIST_H +#define C_LINKED_LIST_H + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct LinkedListNode LinkedListNode; +typedef struct LinkedList LinkedList; + +LinkedList* LinkedList_Create(); + +void LinkedList_Free(LinkedList* linked_list); + +void* LinkedList_Front(LinkedList* linked_list); +void* LinkedList_Back(LinkedList* linked_list); + +unsigned int LinkedList_PushFront(LinkedList* linked_list, void* new_item); + +unsigned int LinkedList_PushBack(LinkedList* linked_list, void* new_item); + +void* LinkedList_PopFront(LinkedList* linked_list); + +void* LinkedList_PopBack(LinkedList* linked_list); + +size_t LinkedList_Size(LinkedList* linked_list); + +void LinkedList_Clear(LinkedList* linked_list); + +void* LinkedListNode_GetData(LinkedListNode* list_node); + +LinkedListNode* LinkedList_Find(LinkedList* linked_list, void* the_data, LinkedListNode* start_node); + +unsigned int LinkedList_Remove(LinkedList* linked_list, LinkedListNode* list_node); + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif + +#endif /* C_LINKED_LIST_H */ +