diff options
author | David Robillard <d@drobilla.net> | 2016-07-31 21:59:21 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2016-07-31 21:59:21 -0400 |
commit | 7c2302651559eda71833c291ddc17f4d590ad95a (patch) | |
tree | 32cc32fe32d36acf0693c0834e2ff97b89eefb0e /libs/ardour/worker.cc | |
parent | ae71e57e2422466716c0ec68ac841d778cf26e94 (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.cc | 30 |
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); } } |