mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-23 16:54:03 +02:00
Experimental fix for a memory leak in the resource manager.
This commit is contained in:
+45
-63
@@ -6361,75 +6361,31 @@ static ma_result ma_resource_manager_data_buffer_uninit_internal(ma_resource_man
|
|||||||
ma_resource_manager_data_buffer_uninit_connector(pDataBuffer->pResourceManager, pDataBuffer);
|
ma_resource_manager_data_buffer_uninit_connector(pDataBuffer->pResourceManager, pDataBuffer);
|
||||||
pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_unknown;
|
pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_unknown;
|
||||||
|
|
||||||
/* Free the node last. */
|
/* With the connector uninitialized we can decrement the ref count of the node and free it if required. */
|
||||||
ma_resource_manager_data_buffer_node_free(pDataBuffer->pResourceManager, pDataBuffer->pNode);
|
ma_resource_manager_data_buffer_bst_lock(pDataBuffer->pResourceManager);
|
||||||
|
{
|
||||||
|
ma_result result;
|
||||||
|
ma_uint32 refCount;
|
||||||
|
|
||||||
return MA_SUCCESS;
|
result = ma_resource_manager_data_buffer_node_decrement_ref(pDataBuffer->pResourceManager, pDataBuffer->pNode, &refCount);
|
||||||
}
|
|
||||||
|
|
||||||
static ma_result ma_resource_manager_data_buffer_uninit_nolock(ma_resource_manager_data_buffer* pDataBuffer)
|
|
||||||
{
|
|
||||||
ma_uint32 result;
|
|
||||||
ma_uint32 refCount;
|
|
||||||
|
|
||||||
MA_ASSERT(pDataBuffer != NULL);
|
|
||||||
|
|
||||||
result = ma_resource_manager_data_buffer_node_decrement_ref(pDataBuffer->pResourceManager, pDataBuffer->pNode, &refCount);
|
|
||||||
if (result != MA_SUCCESS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the reference count has hit zero it means we need to delete the data buffer and it's backing data (so long as it's owned by the resource manager). */
|
|
||||||
if (refCount == 0) {
|
|
||||||
ma_bool32 asyncUninit = MA_TRUE;
|
|
||||||
|
|
||||||
result = ma_resource_manager_data_buffer_node_remove(pDataBuffer->pResourceManager, pDataBuffer->pNode);
|
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
return result; /* An error occurred when trying to remove the data buffer. This should never happen. */
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_SUCCESS) {
|
if (refCount == 0) {
|
||||||
asyncUninit = MA_FALSE;
|
result = ma_resource_manager_data_buffer_node_remove(pDataBuffer->pResourceManager, pDataBuffer->pNode);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The data buffer has been removed from the BST so now we need to delete the underyling data. This needs to be done in a separate thread. We don't
|
|
||||||
want to delete anything if the data is owned by the application. Also, just to be safe, we set the result to MA_UNAVAILABLE.
|
|
||||||
*/
|
|
||||||
c89atomic_exchange_i32(&pDataBuffer->pNode->result, MA_UNAVAILABLE);
|
|
||||||
|
|
||||||
if (asyncUninit == MA_FALSE) {
|
|
||||||
/* The data buffer can be deleted synchronously. */
|
|
||||||
return ma_resource_manager_data_buffer_uninit_internal(pDataBuffer);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will
|
|
||||||
be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event
|
|
||||||
to get processed before returning.
|
|
||||||
*/
|
|
||||||
ma_resource_manager_inline_notification notification;
|
|
||||||
ma_job job;
|
|
||||||
|
|
||||||
result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, ¬ification);
|
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
return result; /* Failed to create the notification. This should rarely, if ever, happen. */
|
return result; /* An error occurred when trying to remove the data buffer. This should never happen. */
|
||||||
}
|
}
|
||||||
|
|
||||||
job = ma_job_init(MA_JOB_FREE_DATA_BUFFER);
|
/* Mark the node as unavailable just to be safe. */
|
||||||
job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer);
|
c89atomic_exchange_i32(&pDataBuffer->pNode->result, MA_UNAVAILABLE);
|
||||||
job.freeDataBuffer.pDataBuffer = pDataBuffer;
|
|
||||||
job.freeDataBuffer.pNotification = ¬ification;
|
|
||||||
|
|
||||||
result = ma_resource_manager_post_job(pDataBuffer->pResourceManager, &job);
|
/* Free the node last. */
|
||||||
if (result != MA_SUCCESS) {
|
ma_resource_manager_data_buffer_node_free(pDataBuffer->pResourceManager, pDataBuffer->pNode);
|
||||||
ma_resource_manager_inline_notification_uninit(¬ification);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ma_resource_manager_inline_notification_wait(¬ification);
|
|
||||||
ma_resource_manager_inline_notification_uninit(¬ification);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ma_resource_manager_data_buffer_bst_unlock(pDataBuffer->pResourceManager);
|
||||||
|
|
||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -6442,11 +6398,37 @@ MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data
|
|||||||
return MA_INVALID_ARGS;
|
return MA_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_resource_manager_data_buffer_bst_lock(pDataBuffer->pResourceManager);
|
if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_SUCCESS) {
|
||||||
{
|
/* The data buffer can be deleted synchronously. */
|
||||||
result = ma_resource_manager_data_buffer_uninit_nolock(pDataBuffer);
|
return ma_resource_manager_data_buffer_uninit_internal(pDataBuffer);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will
|
||||||
|
be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event
|
||||||
|
to get processed before returning.
|
||||||
|
*/
|
||||||
|
ma_resource_manager_inline_notification notification;
|
||||||
|
ma_job job;
|
||||||
|
|
||||||
|
result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, ¬ification);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
return result; /* Failed to create the notification. This should rarely, if ever, happen. */
|
||||||
|
}
|
||||||
|
|
||||||
|
job = ma_job_init(MA_JOB_FREE_DATA_BUFFER);
|
||||||
|
job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer);
|
||||||
|
job.freeDataBuffer.pDataBuffer = pDataBuffer;
|
||||||
|
job.freeDataBuffer.pNotification = ¬ification;
|
||||||
|
|
||||||
|
result = ma_resource_manager_post_job(pDataBuffer->pResourceManager, &job);
|
||||||
|
if (result != MA_SUCCESS) {
|
||||||
|
ma_resource_manager_inline_notification_uninit(¬ification);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_resource_manager_inline_notification_wait(¬ification);
|
||||||
|
ma_resource_manager_inline_notification_uninit(¬ification);
|
||||||
}
|
}
|
||||||
ma_resource_manager_data_buffer_bst_unlock(pDataBuffer->pResourceManager);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user