1
0
mirror of synced 2024-11-27 19:10:48 +01:00

Replaced queue with thread-safe version.

This commit is contained in:
doozer 2024-05-25 09:30:42 +10:00
parent 37f7d74c38
commit 1ed2ad182b
4 changed files with 3775 additions and 267 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,192 +0,0 @@
/*
* Filename: dqueue.c
* Date: 13/10/17
* Licence: GNU GPL V3
*
* Library for a generic, dynamically allocated queue
*
* Functions:
* queue_t * queue_init(unsigned int block_num, size_t block_size, size_t element_size); - Initialise the queue data structure and return a pointer to the first element
* void * queue_pop(queue_t * queue); - Pop an element from the front of the queue
* int queue_push(const void * const element, queue_t * queue); - Push an element to the back of the queue
* int queue_debug(const queue_t * const queue); - Dump information about the queue
* void queue_destroy(queue_t * queue); - Destroy the queue data structure
*
* Return/exit codes:
* QUEUE_OK - No error
* SIZE_ERROR - Queue size error (invalid block size or number of elements)
* MEM_ERROR - Memory allocation error
* INDEX_ERROR - Couldn't pop data from the queue
*
* Todo:
*
*/
#include "dqueue.h"
#include <stdio.h>
#include <string.h>
//#define _DEBUG
queue_t * queue_init(unsigned int block_num, size_t block_size, size_t element_width)
{
queue_t * queue;
unsigned int i, j;
#ifdef _DEBUG
printf("queue_init() block_num:%d block_size:%d element_width:%d\r\n",
block_num, block_size, element_width);
#endif
if(block_size == 0)
block_size = DEFAULT_BLOCK;
if(!(queue = (queue_t*)malloc(sizeof(queue_t))))
return NULL;
if((queue->block_size = block_size) <= 0 || (queue->total_blocks = block_num) <= 0 || (queue->element_width = element_width) <= 0) {
queue->status = SIZE_ERROR;
printf("queue_init() SIZE_ERROR\r\n");
return queue;
}
if(!(queue->base_p = (char**)malloc(queue->total_blocks * sizeof(char *)))) {
queue->status = MEM_ERROR;
printf("queue_init() MEM_ERROR\r\n");
return queue;
}
for(i = 0; i < queue->total_blocks; i++) {
if(!(queue->base_p[i] = (char*)malloc(queue->block_size * queue->element_width))) {
fprintf(stderr, "Error: Could not allocate memory!\n");
for(j = 0; j < i; j++)
free(queue->base_p[i]);
free(queue->base_p);
}
}
queue->cur_block = queue->last_block = 0;
queue->cur_block_pos = queue->last_block_pos = 0;
queue->status = QUEUE_OK;
return queue;
}
void queue_destroy(queue_t * queue)
{
while(queue->cur_block < queue->total_blocks)
free(queue->base_p[queue->cur_block++]);
queue->cur_block = 0;
queue->cur_block_pos = 0;
queue->last_block = 0;
queue->last_block_pos = 0;
queue->total_blocks = 0;
queue->block_size = 0;
queue->element_width = 0;
queue->status = 0;
free(queue->base_p);
queue->base_p = NULL;
free(queue);
}
int queue_push(const void * const element, queue_t * queue)
{
memcpy(queue->base_p[queue->last_block] + queue->last_block_pos * queue->element_width, element, queue->element_width);
if(queue->last_block == (queue->total_blocks - queue->cur_block) - 1 && queue->last_block_pos == queue->block_size - 1) {
queue->total_blocks++;
queue->last_block++;
queue->last_block_pos = 0;
if(!(queue->base_p = (char**)realloc(queue->base_p, (queue->total_blocks - queue->cur_block) * sizeof(void *)))) {
fprintf(stderr, "Error: Could not reallocate memory!\n");
queue->status = MEM_ERROR;
queue->total_blocks--;
queue->last_block--;
queue->last_block_pos = queue->block_size - 1;
return MEM_ERROR;
}
if(!(queue->base_p[queue->last_block] = (char*)malloc(queue->block_size * queue->element_width))) {
fprintf(stderr, "Error: Could not allocate memory!\n");
queue->total_blocks--;
queue->last_block--;
queue->last_block_pos = queue->block_size - 1;
queue->status = MEM_ERROR;
return MEM_ERROR;
}
} else if(queue->last_block_pos == queue->block_size - 1) {
queue->last_block++;
queue->last_block_pos = 0;
} else {
queue->last_block_pos++;
}
return QUEUE_OK;
}
void * queue_pop(queue_t * queue)
{
void * data;
if(queue->last_block == queue->cur_block && queue->cur_block_pos == queue->last_block_pos) {
fprintf(stderr, "Error: Queue empty!\n");
queue->status = INDEX_ERROR;
return NULL;
}
if(!(data = malloc(queue->element_width))) {
fprintf(stderr, "Error: Could not allocate memory!\n");
queue->status = MEM_ERROR;
return NULL;
}
if(queue->cur_block_pos == queue->block_size - 1) {
memcpy(data, queue->base_p[queue->cur_block] + queue->cur_block_pos * queue->element_width, queue->element_width);
free(queue->base_p[queue->cur_block]);
queue->cur_block++;
queue->cur_block_pos = 0;
} else {
memcpy(data, queue->base_p[queue->cur_block] + queue->cur_block_pos * queue->element_width, queue->element_width);
queue->cur_block_pos++;
}
return data;
}
int queue_isempty(const queue_t * const queue)
{
int result = 1;
if(queue == NULL) {
printf("Error: Invalid queue pointer!\n");
return MEM_ERROR;
}
result = (queue->total_blocks - queue->cur_block) == queue->total_blocks;
#ifdef _DEBUG
printf("queue_isempty() %i - %i -> %i\r\n",
queue->total_blocks, queue->cur_block, result);
#endif
return result;
}
int queue_debug(const queue_t * const queue)
{
if(queue == NULL) {
printf("Error: Invalid queue pointer!\n");
return MEM_ERROR;
}
if(queue->status == QUEUE_OK)
printf("Queue has %d blocks of size %d and each element is %d bytes wide!\n", (queue->total_blocks - queue->cur_block), (int)queue->block_size, (int)queue->element_width);
else if(queue->status == MEM_ERROR)
printf("Memory error in queue!\n");
else if(queue->status == SIZE_ERROR)
printf("Size error in queue");
return queue->status;
}

View File

@ -1,40 +0,0 @@
#ifndef DQUEUE_H
#define DQUEUE_H
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#define QUEUE_OK 0
#define MEM_ERROR -1 /* Memory allocation error */
#define SIZE_ERROR -2 /* Queue dimension error */
#define INDEX_ERROR -3 /* No data at index */
#define DEFAULT_BLOCK 256 /* By default use 256 bytes per block */
typedef struct {
char ** base_p; /* Base pointer of the queue */
unsigned int cur_block; /* Index of the block containing the first element */
unsigned int cur_block_pos; /* Position of the first element within the block */
unsigned int last_block; /* Index of the block containing the last element */
unsigned int last_block_pos; /* Position of the last element within the block */
unsigned int total_blocks; /* Total number of blocks ever allocated to the queue */
size_t block_size; /* Number of elements in each block */
size_t element_width; /* Size of each element */
int status; /* Status of the queue */
} queue_t;
queue_t * queue_init(unsigned int block_num, size_t block_size, size_t element_size); /* Initialise the queue data structure and return a pointer to the first element */
void * queue_pop(queue_t * queue); /* Pop an element from the front of the queue */
int queue_push(const void * const element, queue_t * queue); /* Push an element to the back of the queue */
int queue_debug(const queue_t * const queue); /* Dump information about the queue */
void queue_destroy(queue_t * queue); /* Destroy the queue data structure */
int queue_isempty(const queue_t * const queue);
#ifdef __cplusplus
}
#endif
#endif // DQUEUE_H

View File

@ -15,7 +15,8 @@
#include "opensegaapi.h"
#include "segaerr.h"
#include "dqueue.h"
// https://github.com/cameron314/concurrentqueue
#include "concurrentqueue.h"
//#define _DEBUG
@ -135,7 +136,7 @@ __inline float FAudioSemitonesToFrequencyRatio(float Semitones)
class FAudio_BufferNotify : public FAudioVoiceCallback {
public:
OPEN_segaapiBuffer_t* buffer = NULL;
queue_t * defers = NULL;
moodycamel::ConcurrentQueue<uint32_t> defers;
FAudioSourceVoice* xaVoice;
FAudio_BufferNotify() {
@ -152,31 +153,29 @@ public:
private:
void SignalBufferEnd()
{
dbgprint("SignalBufferEnd()");
FAudioSourceVoice* returned_voice;
dbgprint("SignalBufferEnd() size = %ld", defers.size_approx());
uint32_t returned_samplerate;
while (!queue_isempty(defers))
{
FAudioVoiceState vs;
while (defers.size_approx() > 0)
{
FAudioVoiceState vs;
FAudioSourceVoice_GetState(xaVoice, &vs, 0);
FAudioSourceVoice_GetState(xaVoice, &vs, 0);
if (vs.BuffersQueued > 0)
{
FAudioSourceVoice_FlushSourceBuffers(xaVoice);
return;
}
if (vs.BuffersQueued > 0)
{
FAudioSourceVoice_FlushSourceBuffers(xaVoice);
return;
}
returned_voice = (FAudioSourceVoice*)queue_pop(defers);
if (returned_voice)
{
dbgprint("SignalBufferEnd: voice = %08x", returned_voice);
FAudioSourceVoice_FlushSourceBuffers(returned_voice);
}
}
if (defers.try_dequeue(returned_samplerate))
{
dbgprint("SignalBufferEnd: samplerate: %d", returned_samplerate);
FAudioSourceVoice_SetSourceSampleRate(xaVoice, returned_samplerate);
}
}
}
static void StaticOnBufferEnd(FAudioVoiceCallback* callback, void*)
{
static_cast<FAudio_BufferNotify*>(callback)->SignalBufferEnd();
@ -221,20 +220,17 @@ struct OPEN_segaapiBuffer_t
FAudio_BufferNotify xaCallback; // buffer end notification
};
void defer_buffer_call(FAudioSourceVoice* voice, queue_t* defers, uint32_t samplerate)
void defer_buffer_call(FAudioSourceVoice* voice, FAudio_BufferNotify* notify, uint32_t samplerate)
{
dbgprint("defer_buffer_call()");
if (voice)
{
FAudioVoiceState vs;
dbgprint("defer_buffer_call: call FAudioSourceVoice_GetState");
FAudioSourceVoice_GetState(voice, &vs, 0);
dbgprint("defer_buffer_call: call complete: %i", vs.BuffersQueued);
if (vs.BuffersQueued > 0)
{
dbgprint("defer_buffer_call: call queue_push voice = %08x", voice);
queue_push((const void*)voice, defers);
dbgprint("defer_buffer_call: call complete");
dbgprint("defer_buffer_call: push samplerate: %d", samplerate);
notify->defers.enqueue(samplerate);
FAudioSourceVoice_FlushSourceBuffers(voice);
@ -497,10 +493,12 @@ static FAudioSubmixVoice* g_submixVoices[6];
static void updateBufferNew(OPEN_segaapiBuffer_t* buffer, unsigned int offset, size_t length)
{
size_t count = 0;
dbgprint("updateBufferNew voice: %08x data: %p size: %d", buffer->xaCallback.xaVoice, buffer->data, buffer->size);
// don't update with pending defers
if (!queue_isempty(buffer->xaCallback.defers))
count = buffer->xaCallback.defers.size_approx();
if (count > 0)
{
dbgprint("updateBufferNew: DEFER!");
return;
@ -573,10 +571,6 @@ extern "C" {
pConfig->dwPriority,
pConfig->dwSampleFormat);
buffer->xaCallback.defers = queue_init(20, 20, sizeof(FAudioSourceVoice*));
if (buffer->xaCallback.defers == NULL)
printf("queue_init failed!\r\n");
buffer->playing = false;
buffer->callback = pCallback;
buffer->synthesizer = dwFlags & OPEN_HABUF_SYNTH_BUFFER;
@ -742,7 +736,7 @@ extern "C" {
OPEN_segaapiBuffer_t* buffer = (OPEN_segaapiBuffer_t*)hHandle;
buffer->sampleRate = dwSampleRate;
defer_buffer_call(buffer->xaCallback.xaVoice, buffer->xaCallback.defers, dwSampleRate);
defer_buffer_call(buffer->xaCallback.xaVoice, &buffer->xaCallback, dwSampleRate);
return OPEN_SEGA_SUCCESS;
}
@ -939,7 +933,6 @@ extern "C" {
OPEN_segaapiBuffer_t* buffer = (OPEN_segaapiBuffer_t*)hHandle;
FAudioVoice_DestroyVoice(buffer->xaCallback.xaVoice);
queue_destroy(buffer->xaCallback.defers);
delete buffer;
return OPEN_SEGA_SUCCESS;
}