mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Fix some bugs when acquiring a data buffer node.
This commit is contained in:
+133
-109
@@ -58768,6 +58768,132 @@ static ma_result ma_resource_manager_data_buffer_node_decode_next_page(ma_resour
|
||||
return result;
|
||||
}
|
||||
|
||||
static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_inline_notification* pInitNotification, ma_resource_manager_data_buffer_node** ppDataBufferNode)
|
||||
{
|
||||
ma_result result;
|
||||
ma_resource_manager_data_buffer_node* pDataBufferNode = NULL;
|
||||
ma_resource_manager_data_buffer_node* pInsertPoint;
|
||||
|
||||
result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, hashedName32, &pInsertPoint);
|
||||
if (result == MA_ALREADY_EXISTS) {
|
||||
/* The node already exists. We just need to increment the reference count. */
|
||||
pDataBufferNode = pInsertPoint;
|
||||
|
||||
result = ma_resource_manager_data_buffer_node_increment_ref(pResourceManager, pDataBufferNode, NULL);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result; /* Should never happen. Failed to increment the reference count. */
|
||||
}
|
||||
|
||||
return MA_ALREADY_EXISTS; /* This is used later on, outside of the critical section, to determine whether or not a synchronous load should happen now. */
|
||||
} else {
|
||||
/*
|
||||
The node does not already exist. We need to post a LOAD_DATA_BUFFER_NODE job here. This
|
||||
needs to be done inside the critical section to ensure an uninitialization of the node
|
||||
does not occur before initialization on another thread.
|
||||
*/
|
||||
pDataBufferNode = (ma_resource_manager_data_buffer_node*)ma_malloc(sizeof(*pDataBufferNode), &pResourceManager->config.allocationCallbacks);
|
||||
if (pDataBufferNode == NULL) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MA_ZERO_OBJECT(pDataBufferNode);
|
||||
pDataBufferNode->hashedName32 = hashedName32;
|
||||
pDataBufferNode->refCount = 1; /* Always set to 1 by default (this is our first reference). */
|
||||
|
||||
if (pExistingData == NULL) {
|
||||
pDataBufferNode->data.type = ma_resource_manager_data_supply_type_unknown; /* <-- We won't know this until we start decoding. */
|
||||
pDataBufferNode->result = MA_BUSY; /* Must be set to MA_BUSY before we leave the critical section, so might as well do it now. */
|
||||
pDataBufferNode->isDataOwnedByResourceManager = MA_TRUE;
|
||||
} else {
|
||||
pDataBufferNode->data = *pExistingData;
|
||||
pDataBufferNode->result = MA_SUCCESS; /* Not loading asynchronously, so just set the status */
|
||||
pDataBufferNode->isDataOwnedByResourceManager = MA_FALSE;
|
||||
}
|
||||
|
||||
result = ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
|
||||
return result; /* Should never happen. Failed to insert the data buffer into the BST. */
|
||||
}
|
||||
|
||||
/*
|
||||
Here is where we'll post the job, but only if we're loading asynchronously. If we're
|
||||
loading synchronously we'll defer loading to a later stage, outside of the critical
|
||||
section.
|
||||
*/
|
||||
if (pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) {
|
||||
/* Loading asynchronously. Post the job. */
|
||||
ma_resource_manager_job job;
|
||||
char* pFilePathCopy = NULL;
|
||||
wchar_t* pFilePathWCopy = NULL;
|
||||
|
||||
/* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */
|
||||
if (pFilePath != NULL) {
|
||||
pFilePathCopy = ma_copy_string(pFilePath, &pResourceManager->config.allocationCallbacks);
|
||||
} else {
|
||||
pFilePathWCopy = ma_copy_string_w(pFilePathW, &pResourceManager->config.allocationCallbacks);
|
||||
}
|
||||
|
||||
if (pFilePathCopy == NULL && pFilePathWCopy == NULL) {
|
||||
ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
|
||||
ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
|
||||
ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification);
|
||||
}
|
||||
|
||||
/* Acquire init and done fences before posting the job. These will be unacquired by the job thread. */
|
||||
if (pInitFence != NULL) { ma_fence_acquire(pInitFence); }
|
||||
if (pDoneFence != NULL) { ma_fence_acquire(pDoneFence); }
|
||||
|
||||
/* We now have everything we need to post the job to the job thread. */
|
||||
job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE);
|
||||
job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
|
||||
job.loadDataBufferNode.pDataBufferNode = pDataBufferNode;
|
||||
job.loadDataBufferNode.pFilePath = pFilePathCopy;
|
||||
job.loadDataBufferNode.pFilePathW = pFilePathWCopy;
|
||||
job.loadDataBufferNode.decode = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE ) != 0;
|
||||
job.loadDataBufferNode.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? pInitNotification : NULL;
|
||||
job.loadDataBufferNode.pDoneNotification = NULL;
|
||||
job.loadDataBufferNode.pInitFence = pInitFence;
|
||||
job.loadDataBufferNode.pDoneFence = pDoneFence;
|
||||
|
||||
result = ma_resource_manager_post_job(pResourceManager, &job);
|
||||
if (result != MA_SUCCESS) {
|
||||
/* Failed to post job. Probably ran out of memory. */
|
||||
ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result));
|
||||
|
||||
/*
|
||||
Fences were acquired before posting the job, but since the job was not able to
|
||||
be posted, we need to make sure we release them so nothing gets stuck waiting.
|
||||
*/
|
||||
if (pInitFence != NULL) { ma_fence_release(pInitFence); }
|
||||
if (pDoneFence != NULL) { ma_fence_release(pDoneFence); }
|
||||
|
||||
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
|
||||
ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification);
|
||||
}
|
||||
|
||||
ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks);
|
||||
ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks);
|
||||
|
||||
ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
|
||||
ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ppDataBufferNode != NULL) {
|
||||
*ppDataBufferNode = pDataBufferNode;
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_resource_manager_data_buffer_node_acquire(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_data_buffer_node** ppDataBufferNode)
|
||||
{
|
||||
ma_result result = MA_SUCCESS;
|
||||
@@ -58810,118 +58936,16 @@ static ma_result ma_resource_manager_data_buffer_node_acquire(ma_resource_manage
|
||||
*/
|
||||
ma_resource_manager_data_buffer_bst_lock(pResourceManager);
|
||||
{
|
||||
ma_resource_manager_data_buffer_node* pInsertPoint;
|
||||
|
||||
result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, hashedName32, &pInsertPoint);
|
||||
if (result == MA_ALREADY_EXISTS) {
|
||||
/* The node already exists. We just need to increment the reference count. */
|
||||
pDataBufferNode = pInsertPoint;
|
||||
|
||||
result = ma_resource_manager_data_buffer_node_increment_ref(pResourceManager, pDataBufferNode, NULL);
|
||||
if (result != MA_SUCCESS) {
|
||||
goto early_exit; /* Should never happen. Failed to increment the reference count. */
|
||||
}
|
||||
|
||||
nodeAlreadyExists = MA_TRUE; /* This is used later on, outside of this critical section, to determine whether or not a synchronous load should happen now. */
|
||||
} else {
|
||||
/*
|
||||
The node does not already exist. We need to post a LOAD_DATA_BUFFER_NODE job here. This
|
||||
needs to be done inside the critical section to ensure an uninitialization of the node
|
||||
does not occur before initialization on another thread.
|
||||
*/
|
||||
pDataBufferNode = (ma_resource_manager_data_buffer_node*)ma_malloc(sizeof(*pDataBufferNode), &pResourceManager->config.allocationCallbacks);
|
||||
if (pDataBufferNode == NULL) {
|
||||
result = MA_OUT_OF_MEMORY;
|
||||
goto early_exit;
|
||||
}
|
||||
|
||||
MA_ZERO_OBJECT(pDataBufferNode);
|
||||
pDataBufferNode->hashedName32 = hashedName32;
|
||||
pDataBufferNode->refCount = 1; /* Always set to 1 by default (this is our first reference). */
|
||||
|
||||
if (pExistingData == NULL) {
|
||||
pDataBufferNode->data.type = ma_resource_manager_data_supply_type_unknown; /* <-- We won't know this until we start decoding. */
|
||||
pDataBufferNode->result = MA_BUSY; /* Must be set to MA_BUSY before we leave the critical section, so might as well do it now. */
|
||||
pDataBufferNode->isDataOwnedByResourceManager = MA_TRUE;
|
||||
} else {
|
||||
pDataBufferNode->data = *pExistingData;
|
||||
pDataBufferNode->result = MA_SUCCESS; /* Not loading asynchronously, so just set the status */
|
||||
pDataBufferNode->isDataOwnedByResourceManager = MA_FALSE;
|
||||
}
|
||||
|
||||
result = ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
|
||||
goto early_exit; /* Should never happen. Failed to insert the data buffer into the BST. */
|
||||
}
|
||||
|
||||
/*
|
||||
Here is where we'll post the job, but only if we're loading asynchronously. If we're
|
||||
loading synchronously we'll defer loading to a later stage, outside of the critical
|
||||
section.
|
||||
*/
|
||||
if (pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) {
|
||||
/* Loading asynchronously. Post the job. */
|
||||
ma_resource_manager_job job;
|
||||
char* pFilePathCopy = NULL;
|
||||
wchar_t* pFilePathWCopy = NULL;
|
||||
|
||||
/* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */
|
||||
if (pFilePath != NULL) {
|
||||
pFilePathCopy = ma_copy_string(pFilePath, &pResourceManager->config.allocationCallbacks);
|
||||
} else {
|
||||
pFilePathWCopy = ma_copy_string_w(pFilePathW, &pResourceManager->config.allocationCallbacks);
|
||||
}
|
||||
|
||||
if (pFilePathCopy == NULL && pFilePathWCopy == NULL) {
|
||||
result = MA_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
|
||||
ma_resource_manager_inline_notification_init(pResourceManager, &initNotification);
|
||||
}
|
||||
|
||||
/* Acquire init and done fences before posting the job. These will be unacquired by the job thread. */
|
||||
if (pInitFence != NULL) { ma_fence_acquire(pInitFence); }
|
||||
if (pDoneFence != NULL) { ma_fence_acquire(pDoneFence); }
|
||||
|
||||
/* We now have everything we need to post the job to the job thread. */
|
||||
job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE);
|
||||
job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
|
||||
job.loadDataBufferNode.pDataBufferNode = pDataBufferNode;
|
||||
job.loadDataBufferNode.pFilePath = pFilePathCopy;
|
||||
job.loadDataBufferNode.pFilePathW = pFilePathWCopy;
|
||||
job.loadDataBufferNode.decode = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE ) != 0;
|
||||
job.loadDataBufferNode.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? &initNotification : NULL;
|
||||
job.loadDataBufferNode.pDoneNotification = NULL;
|
||||
job.loadDataBufferNode.pInitFence = pInitFence;
|
||||
job.loadDataBufferNode.pDoneFence = pDoneFence;
|
||||
|
||||
result = ma_resource_manager_post_job(pResourceManager, &job);
|
||||
if (result != MA_SUCCESS) {
|
||||
/* Failed to post job. Probably ran out of memory. */
|
||||
ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result));
|
||||
|
||||
/*
|
||||
Fences were acquired before posting the job, but since the job was not able to
|
||||
be posted, we need to make sure we release them so nothing gets stuck waiting.
|
||||
*/
|
||||
if (pInitFence != NULL) { ma_fence_release(pInitFence); }
|
||||
if (pDoneFence != NULL) { ma_fence_release(pDoneFence); }
|
||||
|
||||
ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks);
|
||||
ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = ma_resource_manager_data_buffer_node_acquire_critical_section(pResourceManager, pFilePath, pFilePathW, hashedName32, flags, pExistingData, pInitFence, pDoneFence, &initNotification, &pDataBufferNode);
|
||||
}
|
||||
ma_resource_manager_data_buffer_bst_unlock(pResourceManager);
|
||||
|
||||
early_exit:
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
if (result == MA_ALREADY_EXISTS) {
|
||||
nodeAlreadyExists = MA_TRUE;
|
||||
} else {
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user