kopia lustrzana https://github.com/jameshball/osci-render
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
rodzic
4566dd49e5
commit
6d525b3f0a
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Ładowanie…
Reference in New Issue