summaryrefslogtreecommitdiff
path: root/libs/ardour/worker.cc
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2016-07-31 21:59:21 -0400
committerDavid Robillard <d@drobilla.net>2016-07-31 21:59:21 -0400
commit7c2302651559eda71833c291ddc17f4d590ad95a (patch)
tree32cc32fe32d36acf0693c0834e2ff97b89eefb0e /libs/ardour/worker.cc
parentae71e57e2422466716c0ec68ac841d778cf26e94 (diff)
Support thread-safe LV2 state restoration
The original LV2 state extension required that run() is suspended during restore(). Ardour violates this rule, which can lead to crashes and other issues. The state extension has been updated to allow restoring state in a thread-safe way by using the worker to enqueue state changes. This commit supports that new specification, i.e. supports dropout-free state restoration properly. However, the bug with old plugins that do not use this facility is still not fixed.
Diffstat (limited to 'libs/ardour/worker.cc')
-rw-r--r--libs/ardour/worker.cc30
1 files changed, 21 insertions, 9 deletions
diff --git a/libs/ardour/worker.cc b/libs/ardour/worker.cc
index 9d6dd09b55..f8a5e44aee 100644
--- a/libs/ardour/worker.cc
+++ b/libs/ardour/worker.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Paul Davis
+ Copyright (C) 2012-2016 Paul Davis
Author: David Robillard
This program is free software; you can redistribute it and/or modify
@@ -27,26 +27,38 @@
namespace ARDOUR {
-Worker::Worker(Workee* workee, uint32_t ring_size)
+Worker::Worker(Workee* workee, uint32_t ring_size, bool threaded)
: _workee(workee)
- , _requests(new RingBuffer<uint8_t>(ring_size))
+ , _requests(threaded ? new RingBuffer<uint8_t>(ring_size) : NULL)
, _responses(new RingBuffer<uint8_t>(ring_size))
, _response((uint8_t*)malloc(ring_size))
- , _sem ("worker_semaphore", 0)
+ , _sem("worker_semaphore", 0)
+ , _thread(NULL)
, _exit(false)
- , _thread (Glib::Threads::Thread::create(sigc::mem_fun(*this, &Worker::run)))
-{}
+ , _synchronous(!threaded)
+{
+ if (threaded) {
+ _thread = Glib::Threads::Thread::create(
+ sigc::mem_fun(*this, &Worker::run));
+ }
+}
Worker::~Worker()
{
_exit = true;
_sem.signal();
- _thread->join();
+ if (_thread) {
+ _thread->join();
+ }
}
bool
Worker::schedule(uint32_t size, const void* data)
{
+ if (_synchronous || !_requests) {
+ _workee->work(*this, size, data);
+ return true;
+ }
if (_requests->write_space() < size + sizeof(size)) {
return false;
}
@@ -124,7 +136,7 @@ Worker::run()
while (true) {
_sem.wait();
if (_exit) {
- if (buf) free(buf);
+ free(buf);
return;
}
@@ -163,7 +175,7 @@ Worker::run()
continue; // TODO: This is probably fatal
}
- _workee->work(size, buf);
+ _workee->work(*this, size, buf);
}
}