Add timeout to semaphore acquires, as well as several pre-emptive semaphore releases to try and reduce the scope of deadlocks. i.e. we prefer race conditions to outright crashes/deadlocks

pull/300/head^2
James H Ball 2025-04-26 21:40:15 +01:00
rodzic 4566dd49e5
commit 6d525b3f0a
3 zmienionych plików z 33 dodań i 10 usunięć

Wyświetl plik

@ -51,11 +51,12 @@ void AudioBackgroundThread::write(const OsciPoint& point) {
void AudioBackgroundThread::run() { void AudioBackgroundThread::run() {
while (!threadShouldExit() && shouldBeRunning) { while (!threadShouldExit() && shouldBeRunning) {
consumer->waitUntilFull(); if (consumer->waitUntilFull()) {
if (shouldBeRunning) { if (shouldBeRunning) {
runTask(consumer->getBuffer()); runTask(consumer->getBuffer());
} }
} }
}
} }
void AudioBackgroundThread::setBlockOnAudioThread(bool block) { void AudioBackgroundThread::setBlockOnAudioThread(bool block) {

Wyświetl plik

@ -21,11 +21,14 @@ public:
only the number of permissions and number of available permissions **/ only the number of permissions and number of available permissions **/
Semaphore(const Semaphore& s) : num_permissions(s.num_permissions), avail(s.avail) { } Semaphore(const Semaphore& s) : num_permissions(s.num_permissions), avail(s.avail) { }
void acquire() { bool acquire(std::chrono::milliseconds timeout = std::chrono::milliseconds(200)) {
std::unique_lock<std::mutex> lk(m); std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [this] { return avail > 0; }); bool result = cv.wait_for(lk, timeout, [this] { return avail > 0; });
if (result) {
avail--; avail--;
}
lk.unlock(); lk.unlock();
return result;
} }
void release() { void release() {
@ -61,13 +64,15 @@ public:
// PRODUCER // PRODUCER
// enqueue point // enqueue point
void waitUntilFull() { bool waitUntilFull() {
if (blockOnWrite) { if (blockOnWrite) {
bool writtenSuccessfully = true;
for (int i = 0; i < returnBuffer.size() && blockOnWrite; i++) { for (int i = 0; i < returnBuffer.size() && blockOnWrite; i++) {
queue->wait_dequeue(returnBuffer[i]); writtenSuccessfully = writtenSuccessfully && queue->wait_dequeue_timed(returnBuffer[i], 1000000);
} }
return writtenSuccessfully;
} else { } else {
sema.acquire(); return sema.acquire();
} }
} }

Wyświetl plik

@ -156,6 +156,10 @@ void VisualiserComponent::setFullScreen(bool fullScreen) {
this->fullScreen = fullScreen; this->fullScreen = fullScreen;
hideButtonRow = false; hideButtonRow = false;
setMouseCursor(juce::MouseCursor::PointingHandCursor); setMouseCursor(juce::MouseCursor::PointingHandCursor);
// Release renderingSemaphore to prevent deadlocks during layout changes
renderingSemaphore.release();
resized(); resized();
} }
@ -290,7 +294,10 @@ void VisualiserComponent::runTask(const std::vector<OsciPoint>& points) {
// this just triggers a repaint // this just triggers a repaint
triggerAsyncUpdate(); triggerAsyncUpdate();
// wait for rendering on the OpenGLRenderer thread to complete // wait for rendering on the OpenGLRenderer thread to complete
renderingSemaphore.acquire(); if (!renderingSemaphore.acquire()) {
// If acquire times out, log a message or handle it as appropriate
juce::Logger::writeToLog("Rendering semaphore acquisition timed out");
}
} }
int VisualiserComponent::prepareTask(double sampleRate, int bufferSize) { int VisualiserComponent::prepareTask(double sampleRate, int bufferSize) {
@ -397,6 +404,9 @@ void VisualiserComponent::setRecording(bool recording) {
bool stillRecording = audioRecorder.isRecording(); bool stillRecording = audioRecorder.isRecording();
#endif #endif
// Release renderingSemaphore to prevent deadlock
renderingSemaphore.release();
if (recording) { if (recording) {
#if SOSCI_FEATURES #if SOSCI_FEATURES
recordingVideo = recordingSettings.recordingVideo(); recordingVideo = recordingSettings.recordingVideo();
@ -609,6 +619,10 @@ void VisualiserComponent::popoutWindow() {
} }
#endif #endif
setRecording(false); setRecording(false);
// Release renderingSemaphore to prevent deadlock when creating a child visualizer
renderingSemaphore.release();
auto visualiser = new VisualiserComponent( auto visualiser = new VisualiserComponent(
audioProcessor, audioProcessor,
#if SOSCI_FEATURES #if SOSCI_FEATURES
@ -957,6 +971,9 @@ Texture VisualiserComponent::makeTexture(int width, int height, GLuint textureID
void VisualiserComponent::setResolution(int width) { void VisualiserComponent::setResolution(int width) {
using namespace juce::gl; using namespace juce::gl;
// Release semaphore to prevent deadlocks during texture rebuilding
renderingSemaphore.release();
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
lineTexture = makeTexture(width, width, lineTexture.id); lineTexture = makeTexture(width, width, lineTexture.id);