From 5726fd92d1d2e405a77fc13b9b9149378a1f7021 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 7 Apr 2020 14:35:28 +0200 Subject: [PATCH 01/11] Replace AtomicGuards by mutexes with try_lock --- src/sfizz/AtomicGuard.h | 114 --------------------------------------- src/sfizz/Defer.h | 22 ++++++++ src/sfizz/EQPool.cpp | 11 ++-- src/sfizz/EQPool.h | 4 +- src/sfizz/FilePool.cpp | 12 ++--- src/sfizz/FilePool.h | 4 +- src/sfizz/FilterPool.cpp | 11 ++-- src/sfizz/FilterPool.h | 4 +- src/sfizz/Synth.cpp | 80 +++++++++------------------ src/sfizz/Synth.h | 21 ++++---- 10 files changed, 75 insertions(+), 208 deletions(-) delete mode 100644 src/sfizz/AtomicGuard.h create mode 100644 src/sfizz/Defer.h diff --git a/src/sfizz/AtomicGuard.h b/src/sfizz/AtomicGuard.h deleted file mode 100644 index 16d1f4dd..00000000 --- a/src/sfizz/AtomicGuard.h +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -/** - * @brief This file contains a pair of RAII helpers that handle some form - * of lock-free mutex-type protection adapter to audio applications where you have 1 priority thread - * that should never block and would rather return silence than wait, and another low-priority - * thread that handles long computations. - * - * @code{.cpp} - * - * // Somewhere in a class... - * std::atomic canEnterCallback; - * std::atomic inCallback; - * - * void functionThatSuspendsCallback() - * { - * AtomicDisabler callbackDisabler { canEnterCallback }; - * - * while (inCallback) { - * std::this_thread::sleep_for(1ms); - * } - * - * // Do your thing. - * } - * - * void callback(int samplesPerBlock) noexcept - * { - * AtomicGuard callbackGuard { inCallback }; - * if (!canEnterCallback) - * return; - * - * // Do your thing. - * } - * @endcode - * There are probably many ways to improve these and probably even debug them. - * The spinlocking itself could be integrated in the constructor, although the - * check for return in the callback could not. - */ -#include - -namespace sfz -{ -/** - * @brief Simple class to set an atomic to true and automatically set it back to false on - * destruction. - * - * You call it like this assuming you need indicate that you are in e.g. a callback - * @code{.cpp} - * void functionToProtect() - * { - * AtomicGuard { guard }; - * - * // Do stuff, the atomic will be set back to false as soon as you're back - * } - * @endcode - * Note that this is not thread-safe at all, in the sense that it is only meant to be - * used with 2 threads along with the AtomicDisabler. One thread uses AtomicGuards, the other - * AtomicDisablers, and no other contending thread can share this pair of atomics. - */ -class AtomicGuard -{ -public: - AtomicGuard() = delete; - AtomicGuard(std::atomic& guard) - : guard(guard) - { - guard = true; - } - ~AtomicGuard() - { - guard = false; - } -private: - std::atomic& guard; -}; - -/** - * @brief Simple class to set an atomic to false and automatically set it back to true on - * destruction. - * - * You call it like this assuming you need to disable e.g. a callback - * @code{.cpp} - * void functionThatDisableAnotherFunction() - * { - * AtomicDisabler { disabler }; - * - * // Do stuff, the atomic will be set back to true as soon as you're back - * } - * @endcode - * Note that this is not thread-safe at all, in the sense that it is only meant to be - * used with 2 threads along with the AtomicGuard. One thread uses AtomicGuards, the other - * AtomicDisabler, and no other contending thread can share this pair of atomics. - */ -class AtomicDisabler -{ -public: - AtomicDisabler() = delete; - AtomicDisabler(std::atomic& allowed) - : allowed(allowed) - { - allowed = false; - } - ~AtomicDisabler() - { - allowed = true; - } -private: - std::atomic& allowed; -}; -} diff --git a/src/sfizz/Defer.h b/src/sfizz/Defer.h new file mode 100644 index 00000000..087ca8d6 --- /dev/null +++ b/src/sfizz/Defer.h @@ -0,0 +1,22 @@ +#pragma once + +// From https://stackoverflow.com/questions/48117908/is-the-a-practical-way-to-emulate-go-language-defer-in-c-or-c-destructors +#include +#include + +template +struct deferred +{ + std::decay_t f; + template + deferred(G&& g) : f{std::forward(g)} {} + ~deferred() { f(); } +}; + +template +deferred(G&&) -> deferred; + +#define CAT_(x, y) x##y +#define CAT(x, y) CAT_(x, y) +#define ANONYMOUS_VAR(x) CAT(x, __LINE__) +#define DEFER deferred ANONYMOUS_VAR(defer_variable) = [&] diff --git a/src/sfizz/EQPool.cpp b/src/sfizz/EQPool.cpp index 515f26ef..574c5fd0 100644 --- a/src/sfizz/EQPool.cpp +++ b/src/sfizz/EQPool.cpp @@ -1,5 +1,5 @@ #include "EQPool.h" -#include "AtomicGuard.h" +#include "Defer.h" #include #include "absl/algorithm/container.h" #include "SIMDHelpers.h" @@ -108,9 +108,9 @@ sfz::EQPool::EQPool(const MidiState& state, int numEQs) sfz::EQHolderPtr sfz::EQPool::getEQ(const EQDescription& description, unsigned numChannels, float velocity) { - AtomicGuard guard { givingOutEQs }; - if (!canGiveOutEQs) + if (!eqGuard.try_lock()) return {}; + DEFER { eqGuard.unlock(); }; auto eq = absl::c_find_if(eqs, [](const EQHolderPtr& holder) { return holder.use_count() == 1; @@ -132,10 +132,7 @@ size_t sfz::EQPool::getActiveEQs() const size_t sfz::EQPool::setnumEQs(size_t numEQs) { - AtomicDisabler disabler { canGiveOutEQs }; - - while(givingOutEQs) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + const std::lock_guard eqLock { eqGuard }; auto eqIterator = eqs.begin(); auto eqSentinel = eqs.rbegin(); diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index 9890c10a..7c70af22 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -4,6 +4,7 @@ #include "MidiState.h" #include #include +#include namespace sfz { @@ -114,8 +115,7 @@ public: */ void setSampleRate(float sampleRate); private: - std::atomic givingOutEQs { false }; - std::atomic canGiveOutEQs { true }; + std::mutex eqGuard; float sampleRate { config::defaultSampleRate }; const MidiState& midiState; std::vector eqs; diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 9b43a2be..0fac5591 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -29,7 +29,7 @@ #include "Config.h" #include "Debug.h" #include "Oversampler.h" -#include "AtomicGuard.h" +#include "Defer.h" #include "absl/types/span.h" #include "absl/strings/match.h" #include "absl/memory/memory.h" @@ -301,10 +301,7 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept void sfz::FilePool::tryToClearPromises() { - AtomicDisabler disabler { canAddPromisesToClear }; - - while (addingPromisesToClear) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + const std::lock_guard promiseLock { promiseGuard }; for (auto& promise: promisesToClear) { if (promise->dataStatus != FilePromise::DataStatus::Wait) @@ -376,10 +373,9 @@ void sfz::FilePool::clear() void sfz::FilePool::cleanupPromises() noexcept { - AtomicGuard guard { addingPromisesToClear }; - - if (!canAddPromisesToClear) + if (!promiseGuard.try_lock()) return; + DEFER { promiseGuard.unlock(); }; // The garbage collection cleared the data from these so we can move them // back to the empty queue diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 450a4c24..50939dbb 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -38,6 +38,7 @@ #include "Logger.h" #include #include +#include namespace sfz { using AudioBufferPtr = std::shared_ptr>; @@ -264,8 +265,7 @@ private: std::vector emptyPromises; std::vector temporaryFilePromises; std::vector promisesToClear; - std::atomic addingPromisesToClear { false }; - std::atomic canAddPromisesToClear { true }; + std::mutex promiseGuard; // Preloaded data absl::flat_hash_map preloadedFiles; diff --git a/src/sfizz/FilterPool.cpp b/src/sfizz/FilterPool.cpp index 062e4e95..74e185f3 100644 --- a/src/sfizz/FilterPool.cpp +++ b/src/sfizz/FilterPool.cpp @@ -1,7 +1,7 @@ #include "FilterPool.h" #include "SIMDHelpers.h" #include "absl/algorithm/container.h" -#include "AtomicGuard.h" +#include "Defer.h" #include #include @@ -109,9 +109,9 @@ sfz::FilterPool::FilterPool(const MidiState& state, int numFilters) sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& description, unsigned numChannels, int noteNumber, float velocity) { - AtomicGuard guard { givingOutFilters }; - if (!canGiveOutFilters) + if (!filterGuard.try_lock()) return {}; + DEFER { filterGuard.unlock(); }; auto filter = absl::c_find_if(filters, [](const FilterHolderPtr& holder) { return holder.use_count() == 1; @@ -133,10 +133,7 @@ size_t sfz::FilterPool::getActiveFilters() const size_t sfz::FilterPool::setNumFilters(size_t numFilters) { - AtomicDisabler disabler { canGiveOutFilters }; - - while(givingOutFilters) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + const std::lock_guard filterLock { filterGuard }; auto filterIterator = filters.begin(); auto filterSentinel = filters.rbegin(); diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index fb1a8aac..25ba0215 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -4,6 +4,7 @@ #include "MidiState.h" #include #include +#include namespace sfz { @@ -118,8 +119,7 @@ public: */ void setSampleRate(float sampleRate); private: - std::atomic givingOutFilters { false }; - std::atomic canGiveOutFilters { true }; + std::mutex filterGuard; float sampleRate { config::defaultSampleRate }; const MidiState& midiState; std::vector filters; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 52dfba4c..884491a0 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -5,7 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Synth.h" -#include "AtomicGuard.h" +#include "Defer.h" #include "Config.h" #include "Debug.h" #include "Macros.h" @@ -28,21 +28,16 @@ sfz::Synth::Synth() sfz::Synth::Synth(int numVoices) { + const std::lock_guard disableCallback { callbackGuard }; parser.setListener(this); - effectFactory.registerStandardEffectTypes(); - effectBuses.reserve(5); // sufficient room for main and fx1-4 - resetVoices(numVoices); } sfz::Synth::~Synth() { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); @@ -128,10 +123,7 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) void sfz::Synth::clear() { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); @@ -327,13 +319,9 @@ void addEndpointsToVelocityCurve(sfz::Region& region) bool sfz::Synth::loadSfzFile(const fs::path& file) { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - clear(); + const std::lock_guard disableCallback { callbackGuard }; parser.parseFile(file); if (parser.getErrorCount() > 0) return false; @@ -508,11 +496,7 @@ void sfz::Synth::setSamplesPerBlock(int samplesPerBlock) noexcept { ASSERT(samplesPerBlock < config::maxBlockSize); - AtomicDisabler callbackDisabler { canEnterCallback }; - - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + const std::lock_guard disableCallback { callbackGuard }; this->samplesPerBlock = samplesPerBlock; for (auto& voice : voices) @@ -528,10 +512,7 @@ void sfz::Synth::setSamplesPerBlock(int samplesPerBlock) noexcept void sfz::Synth::setSampleRate(float sampleRate) noexcept { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + const std::lock_guard disableCallback { callbackGuard }; this->sampleRate = sampleRate; for (auto& voice : voices) @@ -558,10 +539,9 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept if (freeWheeling) resources.filePool.waitForBackgroundLoading(); - - AtomicGuard callbackGuard { inCallback }; - if (!canEnterCallback) + if (!callbackGuard.try_lock()) return; + DEFER { callbackGuard.unlock(); }; size_t numFrames = buffer.getNumFrames(); @@ -655,9 +635,9 @@ void sfz::Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; resources.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity); - AtomicGuard callbackGuard { inCallback }; - if (!canEnterCallback) + if (!callbackGuard.try_lock()) return; + DEFER { callbackGuard.unlock(); }; noteOnDispatch(delay, noteNumber, normalizedVelocity); } @@ -671,9 +651,9 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; resources.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); - AtomicGuard callbackGuard { inCallback }; - if (!canEnterCallback) + if (!callbackGuard.try_lock()) return; + DEFER { callbackGuard.unlock(); }; // FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a // way in sfz to specify that a release trigger should NOT use the note-on velocity? @@ -767,9 +747,9 @@ void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; resources.midiState.ccEvent(delay, ccNumber, normalizedCC); - AtomicGuard callbackGuard { inCallback }; - if (!canEnterCallback) + if (!callbackGuard.try_lock()) return; + DEFER { callbackGuard.unlock(); }; if (ccNumber == config::resetCC) { resetAllControllers(delay); @@ -961,16 +941,12 @@ int sfz::Synth::getNumVoices() const noexcept void sfz::Synth::setNumVoices(int numVoices) noexcept { ASSERT(numVoices > 0); + const std::lock_guard disableCallback { callbackGuard }; resetVoices(numVoices); } void sfz::Synth::resetVoices(int numVoices) { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - voices.clear(); for (int i = 0; i < numVoices; ++i) voices.push_back(absl::make_unique(resources)); @@ -986,10 +962,7 @@ void sfz::Synth::resetVoices(int numVoices) void sfz::Synth::setOversamplingFactor(sfz::Oversampling factor) noexcept { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); @@ -1006,10 +979,7 @@ sfz::Oversampling sfz::Synth::getOversamplingFactor() const noexcept void sfz::Synth::setPreloadSize(uint32_t preloadSize) noexcept { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + const std::lock_guard disableCallback { callbackGuard }; resources.filePool.setPreloadSize(preloadSize); } @@ -1036,11 +1006,12 @@ void sfz::Synth::disableFreeWheeling() noexcept void sfz::Synth::resetAllControllers(int delay) noexcept { - AtomicGuard callbackGuard { inCallback }; - if (!canEnterCallback) - return; - resources.midiState.resetAllControllers(delay); + + if (!callbackGuard.try_lock()) + return; + DEFER { callbackGuard.unlock(); }; + for (auto& voice : voices) { voice->registerPitchWheel(delay, 0); for (int cc = 0; cc < config::numCCs; ++cc) @@ -1086,10 +1057,7 @@ void sfz::Synth::disableLogging() noexcept void sfz::Synth::allSoundOff() noexcept { - AtomicDisabler callbackDisabler { canEnterCallback }; - while (inCallback) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 16017f3a..ada267a3 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -18,6 +18,7 @@ #include "absl/types/span.h" #include #include +#include #include #include #include @@ -206,6 +207,7 @@ public: * @param noteNumber the midi note number * @param velocity the midi note velocity */ + void noteOff(int delay, int noteNumber, uint8_t velocity) noexcept; /** * @brief Send a CC event to the synth @@ -436,13 +438,7 @@ private: * */ void clear(); - /** - * @brief Resets and possibly changes the number of voices (polyphony) in - * the synth. - * - * @param numVoices - */ - void resetVoices(int numVoices); + /** * @brief Helper function to dispatch opcodes * @@ -475,6 +471,13 @@ private: * @param regionOpcodes the opcodes that are specific to the region */ void buildRegion(const std::vector& regionOpcodes); + /** + * @brief Resets and possibly changes the number of voices (polyphony) in + * the synth. + * + * @param numVoices + */ + void resetVoices(int numVoices); fs::file_time_type checkModificationTime(); @@ -526,9 +529,7 @@ private: std::uniform_real_distribution randNoteDistribution { 0, 1 }; unsigned fileTicket { 1 }; - // Atomic guards; must be used with AtomicGuard and AtomicDisabler - std::atomic canEnterCallback { true }; - std::atomic inCallback { false }; + std::mutex callbackGuard; bool freeWheeling { false }; // Singletons passed as references to the voices From 5f9bbbede54989b5400d02e3d6a0f4e4869685b3 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 7 Apr 2020 15:45:38 +0200 Subject: [PATCH 02/11] Use RTSemaphore instead of sleeplocking the background threads --- src/sfizz/FilePool.cpp | 12 ++++++++++-- src/sfizz/FilePool.h | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 0fac5591..981485b4 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -106,6 +106,10 @@ sfz::FilePool::FilePool(sfz::Logger& logger) sfz::FilePool::~FilePool() { quitThread = true; + + for (unsigned i = 0; i < threadPool.size(); ++i) + workerBarrier.post(); + for (auto& thread: threadPool) thread.join(); } @@ -281,8 +285,9 @@ sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) n DBG("[sfizz] Could not enqueue the promise for " << filename << " (queue capacity " << promiseQueue.capacity() << ")"); return {}; } - + workerBarrier.post(); emptyPromises.pop_back(); + return promise; } @@ -330,8 +335,9 @@ void sfz::FilePool::loadingThread() noexcept continue; } + workerBarrier.wait(); + if (!promiseQueue.try_pop(promise)) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } @@ -440,6 +446,8 @@ uint32_t sfz::FilePool::getPreloadSize() const noexcept void sfz::FilePool::emptyFileLoadingQueues() noexcept { emptyQueue = true; + workerBarrier.post(); + while (emptyQueue) std::this_thread::sleep_for(std::chrono::milliseconds(1)); } diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 50939dbb..187cb182 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -27,6 +27,7 @@ #include "Config.h" #include "Defaults.h" #include "LeakDetector.h" +#include "RTSemaphore.h" #include "AudioBuffer.h" #include "AudioSpan.h" #include "SIMDHelpers.h" @@ -260,6 +261,7 @@ private: bool quitThread { false }; bool emptyQueue { false }; std::atomic threadsLoading { 0 }; + RTSemaphore workerBarrier; // File promises data structures along with their guards. std::vector emptyPromises; From becdff5969f30e1410b852eaa4655bd3d5ec78da Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 7 Apr 2020 20:14:55 +0200 Subject: [PATCH 03/11] Stricter c++11 compliance --- src/sfizz/Defer.h | 14 ++++++++------ src/sfizz/EQPool.cpp | 4 ++-- src/sfizz/FilePool.cpp | 4 ++-- src/sfizz/FilterPool.cpp | 4 ++-- src/sfizz/Synth.cpp | 30 +++++++++++++++--------------- 5 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/sfizz/Defer.h b/src/sfizz/Defer.h index 087ca8d6..e88bd21c 100644 --- a/src/sfizz/Defer.h +++ b/src/sfizz/Defer.h @@ -7,16 +7,18 @@ template struct deferred { - std::decay_t f; - template - deferred(G&& g) : f{std::forward(g)} {} + F f; + deferred(F f) : f(f) {} ~deferred() { f(); } }; -template -deferred(G&&) -> deferred; + +template +deferred deferred_func(F f) { + return deferred(f); +} #define CAT_(x, y) x##y #define CAT(x, y) CAT_(x, y) #define ANONYMOUS_VAR(x) CAT(x, __LINE__) -#define DEFER deferred ANONYMOUS_VAR(defer_variable) = [&] +#define DEFER(code) auto ANONYMOUS_VAR(defer_variable) = deferred_func([&] { code ; }) diff --git a/src/sfizz/EQPool.cpp b/src/sfizz/EQPool.cpp index 574c5fd0..ccee55bc 100644 --- a/src/sfizz/EQPool.cpp +++ b/src/sfizz/EQPool.cpp @@ -110,7 +110,7 @@ sfz::EQHolderPtr sfz::EQPool::getEQ(const EQDescription& description, unsigned n { if (!eqGuard.try_lock()) return {}; - DEFER { eqGuard.unlock(); }; + DEFER(eqGuard.unlock()); auto eq = absl::c_find_if(eqs, [](const EQHolderPtr& holder) { return holder.use_count() == 1; @@ -132,7 +132,7 @@ size_t sfz::EQPool::getActiveEQs() const size_t sfz::EQPool::setnumEQs(size_t numEQs) { - const std::lock_guard eqLock { eqGuard }; + const std::lock_guard eqLock { eqGuard }; auto eqIterator = eqs.begin(); auto eqSentinel = eqs.rbegin(); diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 981485b4..fb120c14 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -306,7 +306,7 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept void sfz::FilePool::tryToClearPromises() { - const std::lock_guard promiseLock { promiseGuard }; + const std::lock_guard promiseLock { promiseGuard }; for (auto& promise: promisesToClear) { if (promise->dataStatus != FilePromise::DataStatus::Wait) @@ -381,7 +381,7 @@ void sfz::FilePool::cleanupPromises() noexcept { if (!promiseGuard.try_lock()) return; - DEFER { promiseGuard.unlock(); }; + DEFER(promiseGuard.unlock()); // The garbage collection cleared the data from these so we can move them // back to the empty queue diff --git a/src/sfizz/FilterPool.cpp b/src/sfizz/FilterPool.cpp index 74e185f3..ce18be28 100644 --- a/src/sfizz/FilterPool.cpp +++ b/src/sfizz/FilterPool.cpp @@ -111,7 +111,7 @@ sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& descrip { if (!filterGuard.try_lock()) return {}; - DEFER { filterGuard.unlock(); }; + DEFER(filterGuard.unlock()); auto filter = absl::c_find_if(filters, [](const FilterHolderPtr& holder) { return holder.use_count() == 1; @@ -133,7 +133,7 @@ size_t sfz::FilterPool::getActiveFilters() const size_t sfz::FilterPool::setNumFilters(size_t numFilters) { - const std::lock_guard filterLock { filterGuard }; + const std::lock_guard filterLock { filterGuard }; auto filterIterator = filters.begin(); auto filterSentinel = filters.rbegin(); diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 884491a0..a83743b7 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -28,7 +28,7 @@ sfz::Synth::Synth() sfz::Synth::Synth(int numVoices) { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; parser.setListener(this); effectFactory.registerStandardEffectTypes(); effectBuses.reserve(5); // sufficient room for main and fx1-4 @@ -37,7 +37,7 @@ sfz::Synth::Synth(int numVoices) sfz::Synth::~Synth() { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); @@ -123,7 +123,7 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) void sfz::Synth::clear() { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); @@ -321,7 +321,7 @@ bool sfz::Synth::loadSfzFile(const fs::path& file) { clear(); - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; parser.parseFile(file); if (parser.getErrorCount() > 0) return false; @@ -496,7 +496,7 @@ void sfz::Synth::setSamplesPerBlock(int samplesPerBlock) noexcept { ASSERT(samplesPerBlock < config::maxBlockSize); - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; this->samplesPerBlock = samplesPerBlock; for (auto& voice : voices) @@ -512,7 +512,7 @@ void sfz::Synth::setSamplesPerBlock(int samplesPerBlock) noexcept void sfz::Synth::setSampleRate(float sampleRate) noexcept { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; this->sampleRate = sampleRate; for (auto& voice : voices) @@ -541,7 +541,7 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept if (!callbackGuard.try_lock()) return; - DEFER { callbackGuard.unlock(); }; + DEFER(callbackGuard.unlock()); size_t numFrames = buffer.getNumFrames(); @@ -637,7 +637,7 @@ void sfz::Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept if (!callbackGuard.try_lock()) return; - DEFER { callbackGuard.unlock(); }; + DEFER(callbackGuard.unlock()); noteOnDispatch(delay, noteNumber, normalizedVelocity); } @@ -653,7 +653,7 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept if (!callbackGuard.try_lock()) return; - DEFER { callbackGuard.unlock(); }; + DEFER(callbackGuard.unlock()); // FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a // way in sfz to specify that a release trigger should NOT use the note-on velocity? @@ -749,7 +749,7 @@ void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept if (!callbackGuard.try_lock()) return; - DEFER { callbackGuard.unlock(); }; + DEFER(callbackGuard.unlock()); if (ccNumber == config::resetCC) { resetAllControllers(delay); @@ -941,7 +941,7 @@ int sfz::Synth::getNumVoices() const noexcept void sfz::Synth::setNumVoices(int numVoices) noexcept { ASSERT(numVoices > 0); - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; resetVoices(numVoices); } @@ -962,7 +962,7 @@ void sfz::Synth::resetVoices(int numVoices) void sfz::Synth::setOversamplingFactor(sfz::Oversampling factor) noexcept { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); @@ -979,7 +979,7 @@ sfz::Oversampling sfz::Synth::getOversamplingFactor() const noexcept void sfz::Synth::setPreloadSize(uint32_t preloadSize) noexcept { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; resources.filePool.setPreloadSize(preloadSize); } @@ -1010,7 +1010,7 @@ void sfz::Synth::resetAllControllers(int delay) noexcept if (!callbackGuard.try_lock()) return; - DEFER { callbackGuard.unlock(); }; + DEFER(callbackGuard.unlock()); for (auto& voice : voices) { voice->registerPitchWheel(delay, 0); @@ -1057,7 +1057,7 @@ void sfz::Synth::disableLogging() noexcept void sfz::Synth::allSoundOff() noexcept { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard }; for (auto& voice : voices) voice->reset(); From 758da22bd767d7368bf294e5d7173c91ca6330e4 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 7 Apr 2020 22:42:27 +0200 Subject: [PATCH 04/11] Remove noexcept with RTSemaphores in --- src/sfizz/FilePool.cpp | 12 ++++++++---- src/sfizz/FilePool.h | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index fb120c14..7ccada70 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -108,7 +108,11 @@ sfz::FilePool::~FilePool() quitThread = true; for (unsigned i = 0; i < threadPool.size(); ++i) - workerBarrier.post(); + try { + workerBarrier.post(); + } catch (std::exception e) { + continue; + } for (auto& thread: threadPool) thread.join(); @@ -261,7 +265,7 @@ absl::optional sfz::FilePool::loadFile(const std::string& f } } -sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) noexcept +sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) { if (emptyPromises.empty()) { DBG("[sfizz] No empty promises left to honor the one for " << filename); @@ -322,7 +326,7 @@ void sfz::FilePool::clearingThread() } } -void sfz::FilePool::loadingThread() noexcept +void sfz::FilePool::loadingThread() { FilePromisePtr promise; while (!quitThread) { @@ -443,7 +447,7 @@ uint32_t sfz::FilePool::getPreloadSize() const noexcept return preloadSize; } -void sfz::FilePool::emptyFileLoadingQueues() noexcept +void sfz::FilePool::emptyFileLoadingQueues() { emptyQueue = true; workerBarrier.post(); diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 187cb182..6e997c87 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -207,7 +207,7 @@ public: * @param filename the file to preload * @return FilePromisePtr a file promise */ - FilePromisePtr getFilePromise(const std::string& filename) noexcept; + FilePromisePtr getFilePromise(const std::string& filename); /** * @brief Change the preloading size. This will trigger a full * reload of all samples, so don't call it on the audio thread. @@ -240,7 +240,7 @@ public: * method on the audio thread as it will spinlock. * */ - void emptyFileLoadingQueues() noexcept; + void emptyFileLoadingQueues(); /** * @brief Wait for the background loading to finish for all promises * in the queue. @@ -249,7 +249,7 @@ public: private: Logger& logger; fs::path rootDirectory; - void loadingThread() noexcept; + void loadingThread(); void clearingThread(); void tryToClearPromises(); From 3e010a4ba6c0cf38570d069335ebb82a9d93d471 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 7 Apr 2020 22:49:34 +0200 Subject: [PATCH 05/11] Catch by ref --- src/sfizz/FilePool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 7ccada70..55f57f24 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -110,7 +110,7 @@ sfz::FilePool::~FilePool() for (unsigned i = 0; i < threadPool.size(); ++i) try { workerBarrier.post(); - } catch (std::exception e) { + } catch (std::exception& e) { continue; } From 07b5d7b3d06ae009007e49246fa899c3f6c2b196 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Mon, 13 Apr 2020 00:28:11 +0200 Subject: [PATCH 06/11] Use unique_locks --- src/sfizz/Defer.h | 24 ------------------------ src/sfizz/EQPool.cpp | 6 +++--- src/sfizz/FilePool.cpp | 5 ++--- src/sfizz/FilterPool.cpp | 5 ++--- src/sfizz/Synth.cpp | 21 ++++++++++----------- 5 files changed, 17 insertions(+), 44 deletions(-) delete mode 100644 src/sfizz/Defer.h diff --git a/src/sfizz/Defer.h b/src/sfizz/Defer.h deleted file mode 100644 index e88bd21c..00000000 --- a/src/sfizz/Defer.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -// From https://stackoverflow.com/questions/48117908/is-the-a-practical-way-to-emulate-go-language-defer-in-c-or-c-destructors -#include -#include - -template -struct deferred -{ - F f; - deferred(F f) : f(f) {} - ~deferred() { f(); } -}; - - -template -deferred deferred_func(F f) { - return deferred(f); -} - -#define CAT_(x, y) x##y -#define CAT(x, y) CAT_(x, y) -#define ANONYMOUS_VAR(x) CAT(x, __LINE__) -#define DEFER(code) auto ANONYMOUS_VAR(defer_variable) = deferred_func([&] { code ; }) diff --git a/src/sfizz/EQPool.cpp b/src/sfizz/EQPool.cpp index ccee55bc..94aac145 100644 --- a/src/sfizz/EQPool.cpp +++ b/src/sfizz/EQPool.cpp @@ -1,5 +1,4 @@ #include "EQPool.h" -#include "Defer.h" #include #include "absl/algorithm/container.h" #include "SIMDHelpers.h" @@ -108,9 +107,10 @@ sfz::EQPool::EQPool(const MidiState& state, int numEQs) sfz::EQHolderPtr sfz::EQPool::getEQ(const EQDescription& description, unsigned numChannels, float velocity) { - if (!eqGuard.try_lock()) + const std::unique_lock lock { eqGuard, std::try_to_lock }; + if (!lock.owns_lock()) return {}; - DEFER(eqGuard.unlock()); + auto eq = absl::c_find_if(eqs, [](const EQHolderPtr& holder) { return holder.use_count() == 1; diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 55f57f24..a356dca2 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -29,7 +29,6 @@ #include "Config.h" #include "Debug.h" #include "Oversampler.h" -#include "Defer.h" #include "absl/types/span.h" #include "absl/strings/match.h" #include "absl/memory/memory.h" @@ -383,9 +382,9 @@ void sfz::FilePool::clear() void sfz::FilePool::cleanupPromises() noexcept { - if (!promiseGuard.try_lock()) + const std::unique_lock lock { promiseGuard, std::try_to_lock }; + if (!lock.owns_lock()) return; - DEFER(promiseGuard.unlock()); // The garbage collection cleared the data from these so we can move them // back to the empty queue diff --git a/src/sfizz/FilterPool.cpp b/src/sfizz/FilterPool.cpp index ce18be28..9e4f9091 100644 --- a/src/sfizz/FilterPool.cpp +++ b/src/sfizz/FilterPool.cpp @@ -1,7 +1,6 @@ #include "FilterPool.h" #include "SIMDHelpers.h" #include "absl/algorithm/container.h" -#include "Defer.h" #include #include @@ -109,9 +108,9 @@ sfz::FilterPool::FilterPool(const MidiState& state, int numFilters) sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& description, unsigned numChannels, int noteNumber, float velocity) { - if (!filterGuard.try_lock()) + const std::unique_lock lock { filterGuard, std::try_to_lock }; + if (!lock.owns_lock()) return {}; - DEFER(filterGuard.unlock()); auto filter = absl::c_find_if(filters, [](const FilterHolderPtr& holder) { return holder.use_count() == 1; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index a83743b7..1141624c 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -5,7 +5,6 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Synth.h" -#include "Defer.h" #include "Config.h" #include "Debug.h" #include "Macros.h" @@ -539,9 +538,9 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept if (freeWheeling) resources.filePool.waitForBackgroundLoading(); - if (!callbackGuard.try_lock()) + const std::unique_lock lock { callbackGuard, std::try_to_lock }; + if (!lock.owns_lock()) return; - DEFER(callbackGuard.unlock()); size_t numFrames = buffer.getNumFrames(); @@ -635,9 +634,9 @@ void sfz::Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; resources.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity); - if (!callbackGuard.try_lock()) + const std::unique_lock lock { callbackGuard, std::try_to_lock }; + if (!lock.owns_lock()) return; - DEFER(callbackGuard.unlock()); noteOnDispatch(delay, noteNumber, normalizedVelocity); } @@ -651,9 +650,9 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; resources.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); - if (!callbackGuard.try_lock()) + const std::unique_lock lock { callbackGuard, std::try_to_lock }; + if (!lock.owns_lock()) return; - DEFER(callbackGuard.unlock()); // FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a // way in sfz to specify that a release trigger should NOT use the note-on velocity? @@ -747,9 +746,9 @@ void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; resources.midiState.ccEvent(delay, ccNumber, normalizedCC); - if (!callbackGuard.try_lock()) + const std::unique_lock lock { callbackGuard, std::try_to_lock }; + if (!lock.owns_lock()) return; - DEFER(callbackGuard.unlock()); if (ccNumber == config::resetCC) { resetAllControllers(delay); @@ -1008,9 +1007,9 @@ void sfz::Synth::resetAllControllers(int delay) noexcept { resources.midiState.resetAllControllers(delay); - if (!callbackGuard.try_lock()) + const std::unique_lock lock { callbackGuard, std::try_to_lock }; + if (!lock.owns_lock()) return; - DEFER(callbackGuard.unlock()); for (auto& voice : voices) { voice->registerPitchWheel(delay, 0); From eda78c4604c9b9c36f863ff60cd6b5684a177ac5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 13 Apr 2020 19:14:05 +0200 Subject: [PATCH 07/11] Avoid use of `catch` in the destructor --- src/sfizz/FilePool.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index a356dca2..140beaa0 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -106,12 +106,10 @@ sfz::FilePool::~FilePool() { quitThread = true; - for (unsigned i = 0; i < threadPool.size(); ++i) - try { - workerBarrier.post(); - } catch (std::exception& e) { - continue; - } + for (unsigned i = 0; i < threadPool.size(); ++i) { + std::error_code ec; + workerBarrier.post(ec); + } for (auto& thread: threadPool) thread.join(); From 6d7b70e7c07e1808c5650bb38e3683447c6fec38 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 13 Apr 2020 19:17:10 +0200 Subject: [PATCH 08/11] Add volatile qualifier at some places it should be --- src/sfizz/FilePool.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 6e997c87..6471c75f 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -258,8 +258,8 @@ private: uint32_t preloadSize { config::preloadSize }; Oversampling oversamplingFactor { config::defaultOversamplingFactor }; // Signals - bool quitThread { false }; - bool emptyQueue { false }; + volatile bool quitThread { false }; + volatile bool emptyQueue { false }; std::atomic threadsLoading { 0 }; RTSemaphore workerBarrier; From b494835fdd49dc78e1bd8e0bcede279092118996 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 13 Apr 2020 19:19:10 +0200 Subject: [PATCH 09/11] Remove extra newline [ci skip] --- src/sfizz/Synth.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index ada267a3..6b3d4c37 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -207,7 +207,6 @@ public: * @param noteNumber the midi note number * @param velocity the midi note velocity */ - void noteOff(int delay, int noteNumber, uint8_t velocity) noexcept; /** * @brief Send a CC event to the synth From 7c07df4f660412560926cfb2453abb331df608f2 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Mon, 13 Apr 2020 21:35:36 +0200 Subject: [PATCH 10/11] Add back the noexcepts --- src/sfizz/FilePool.cpp | 20 ++++++++++++++------ src/sfizz/FilePool.h | 6 +++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 140beaa0..c474b634 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -262,7 +262,7 @@ absl::optional sfz::FilePool::loadFile(const std::string& f } } -sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) +sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) noexcept { if (emptyPromises.empty()) { DBG("[sfizz] No empty promises left to honor the one for " << filename); @@ -286,7 +286,11 @@ sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) DBG("[sfizz] Could not enqueue the promise for " << filename << " (queue capacity " << promiseQueue.capacity() << ")"); return {}; } - workerBarrier.post(); + + std::error_code ec; + workerBarrier.post(ec); + ASSERT(!ec); + emptyPromises.pop_back(); return promise; @@ -323,7 +327,7 @@ void sfz::FilePool::clearingThread() } } -void sfz::FilePool::loadingThread() +void sfz::FilePool::loadingThread() noexcept { FilePromisePtr promise; while (!quitThread) { @@ -336,7 +340,9 @@ void sfz::FilePool::loadingThread() continue; } - workerBarrier.wait(); + std::error_code ec; + workerBarrier.wait(ec); + ASSERT(!ec); if (!promiseQueue.try_pop(promise)) { continue; @@ -444,10 +450,12 @@ uint32_t sfz::FilePool::getPreloadSize() const noexcept return preloadSize; } -void sfz::FilePool::emptyFileLoadingQueues() +void sfz::FilePool::emptyFileLoadingQueues() noexcept { emptyQueue = true; - workerBarrier.post(); + std::error_code ec; + workerBarrier.post(ec); + ASSERT(!ec); while (emptyQueue) std::this_thread::sleep_for(std::chrono::milliseconds(1)); diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 6471c75f..c2600ece 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -207,7 +207,7 @@ public: * @param filename the file to preload * @return FilePromisePtr a file promise */ - FilePromisePtr getFilePromise(const std::string& filename); + FilePromisePtr getFilePromise(const std::string& filename) noexcept; /** * @brief Change the preloading size. This will trigger a full * reload of all samples, so don't call it on the audio thread. @@ -240,7 +240,7 @@ public: * method on the audio thread as it will spinlock. * */ - void emptyFileLoadingQueues(); + void emptyFileLoadingQueues() noexcept; /** * @brief Wait for the background loading to finish for all promises * in the queue. @@ -249,7 +249,7 @@ public: private: Logger& logger; fs::path rootDirectory; - void loadingThread(); + void loadingThread() noexcept; void clearingThread(); void tryToClearPromises(); From e274084d2fea576adf07a2323da5f95838ac6341 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Mon, 13 Apr 2020 21:38:22 +0200 Subject: [PATCH 11/11] clang-format step --- src/sfizz/EQPool.cpp | 1 - src/sfizz/RTSemaphore.cpp | 40 +++++++++++++++++++-------------------- src/sfizz/RTSemaphore.h | 18 +++++++++--------- tests/FilesT.cpp | 3 +-- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/sfizz/EQPool.cpp b/src/sfizz/EQPool.cpp index 94aac145..65d5866c 100644 --- a/src/sfizz/EQPool.cpp +++ b/src/sfizz/EQPool.cpp @@ -111,7 +111,6 @@ sfz::EQHolderPtr sfz::EQPool::getEQ(const EQDescription& description, unsigned n if (!lock.owns_lock()) return {}; - auto eq = absl::c_find_if(eqs, [](const EQHolderPtr& holder) { return holder.use_count() == 1; }); diff --git a/src/sfizz/RTSemaphore.cpp b/src/sfizz/RTSemaphore.cpp index 7a3340d5..685166e4 100644 --- a/src/sfizz/RTSemaphore.cpp +++ b/src/sfizz/RTSemaphore.cpp @@ -18,7 +18,7 @@ RTSemaphore::RTSemaphore(unsigned value) good_ = true; } -RTSemaphore::RTSemaphore(std::error_code &ec, unsigned value) noexcept +RTSemaphore::RTSemaphore(std::error_code& ec, unsigned value) noexcept { init(ec, value); good_ = ec ? false : true; @@ -58,7 +58,7 @@ bool RTSemaphore::try_wait() } #if defined(__APPLE__) -void RTSemaphore::init(std::error_code &ec, unsigned value) +void RTSemaphore::init(std::error_code& ec, unsigned value) { ec.clear(); kern_return_t ret = semaphore_create(mach_task_self(), &sem_, SYNC_POLICY_FIFO, value); @@ -66,7 +66,7 @@ void RTSemaphore::init(std::error_code &ec, unsigned value) ec = std::error_code(ret, mach_category()); } -void RTSemaphore::destroy(std::error_code &ec) +void RTSemaphore::destroy(std::error_code& ec) { ec.clear(); kern_return_t ret = semaphore_destroy(mach_task_self(), sem_); @@ -74,7 +74,7 @@ void RTSemaphore::destroy(std::error_code &ec) ec = std::error_code(ret, mach_category()); } -void RTSemaphore::post(std::error_code &ec) noexcept +void RTSemaphore::post(std::error_code& ec) noexcept { ec.clear(); kern_return_t ret = semaphore_signal(sem_); @@ -82,7 +82,7 @@ void RTSemaphore::post(std::error_code &ec) noexcept ec = std::error_code(ret, mach_category()); } -void RTSemaphore::wait(std::error_code &ec) noexcept +void RTSemaphore::wait(std::error_code& ec) noexcept { ec.clear(); do { @@ -99,11 +99,11 @@ void RTSemaphore::wait(std::error_code &ec) noexcept } while (1); } -bool RTSemaphore::try_wait(std::error_code &ec) noexcept +bool RTSemaphore::try_wait(std::error_code& ec) noexcept { ec.clear(); do { - const mach_timespec_t timeout = {0, 0}; + const mach_timespec_t timeout = { 0, 0 }; kern_return_t ret = semaphore_timedwait(sem_, timeout); switch (ret) { case KERN_SUCCESS: @@ -119,18 +119,18 @@ bool RTSemaphore::try_wait(std::error_code &ec) noexcept } while (1); } -const std::error_category &RTSemaphore::mach_category() +const std::error_category& RTSemaphore::mach_category() { class mach_category : public std::error_category { public: - const char *name() const noexcept override + const char* name() const noexcept override { return "kern_return_t"; } std::string message(int condition) const override { - const char *str = mach_error_string(condition); + const char* str = mach_error_string(condition); return str ? str : ""; } }; @@ -139,7 +139,7 @@ const std::error_category &RTSemaphore::mach_category() return cat; } #elif defined(_WIN32) -void RTSemaphore::init(std::error_code &ec, unsigned value) +void RTSemaphore::init(std::error_code& ec, unsigned value) { ec.clear(); sem_ = CreateSemaphore(nullptr, value, LONG_MAX, nullptr); @@ -147,21 +147,21 @@ void RTSemaphore::init(std::error_code &ec, unsigned value) ec = std::error_code(GetLastError(), std::system_category()); } -void RTSemaphore::destroy(std::error_code &ec) +void RTSemaphore::destroy(std::error_code& ec) { ec.clear(); if (CloseHandle(sem_) == 0) ec = std::error_code(GetLastError(), std::system_category()); } -void RTSemaphore::post(std::error_code &ec) noexcept +void RTSemaphore::post(std::error_code& ec) noexcept { ec.clear(); if (ReleaseSemaphore(sem_, 1, nullptr) == 0) ec = std::error_code(GetLastError(), std::system_category()); } -void RTSemaphore::wait(std::error_code &ec) noexcept +void RTSemaphore::wait(std::error_code& ec) noexcept { ec.clear(); DWORD ret = WaitForSingleObject(sem_, INFINITE); @@ -177,7 +177,7 @@ void RTSemaphore::wait(std::error_code &ec) noexcept } } -bool RTSemaphore::try_wait(std::error_code &ec) noexcept +bool RTSemaphore::try_wait(std::error_code& ec) noexcept { ec.clear(); DWORD ret = WaitForSingleObject(sem_, 0); @@ -195,21 +195,21 @@ bool RTSemaphore::try_wait(std::error_code &ec) noexcept } } #else -void RTSemaphore::init(std::error_code &ec, unsigned value) +void RTSemaphore::init(std::error_code& ec, unsigned value) { ec.clear(); if (sem_init(&sem_, 0, value) != 0) ec = std::error_code(errno, std::generic_category()); } -void RTSemaphore::destroy(std::error_code &ec) +void RTSemaphore::destroy(std::error_code& ec) { ec.clear(); if (sem_destroy(&sem_) != 0) ec = std::error_code(errno, std::generic_category()); } -void RTSemaphore::post(std::error_code &ec) noexcept +void RTSemaphore::post(std::error_code& ec) noexcept { ec.clear(); while (sem_post(&sem_) != 0) { @@ -221,7 +221,7 @@ void RTSemaphore::post(std::error_code &ec) noexcept } } -void RTSemaphore::wait(std::error_code &ec) noexcept +void RTSemaphore::wait(std::error_code& ec) noexcept { ec.clear(); while (sem_wait(&sem_) != 0) { @@ -233,7 +233,7 @@ void RTSemaphore::wait(std::error_code &ec) noexcept } } -bool RTSemaphore::try_wait(std::error_code &ec) noexcept +bool RTSemaphore::try_wait(std::error_code& ec) noexcept { ec.clear(); do { diff --git a/src/sfizz/RTSemaphore.h b/src/sfizz/RTSemaphore.h index 4ce01112..c17e5c2a 100644 --- a/src/sfizz/RTSemaphore.h +++ b/src/sfizz/RTSemaphore.h @@ -17,11 +17,11 @@ class RTSemaphore { public: explicit RTSemaphore(unsigned value = 0); - explicit RTSemaphore(std::error_code &ec, unsigned value = 0) noexcept; + explicit RTSemaphore(std::error_code& ec, unsigned value = 0) noexcept; ~RTSemaphore() noexcept; - RTSemaphore(const RTSemaphore &) = delete; - RTSemaphore &operator=(const RTSemaphore &) = delete; + RTSemaphore(const RTSemaphore&) = delete; + RTSemaphore& operator=(const RTSemaphore&) = delete; explicit operator bool() const noexcept { return good_; } @@ -29,18 +29,18 @@ public: void wait(); bool try_wait(); - void post(std::error_code &ec) noexcept; - void wait(std::error_code &ec) noexcept; - bool try_wait(std::error_code &ec) noexcept; + void post(std::error_code& ec) noexcept; + void wait(std::error_code& ec) noexcept; + bool try_wait(std::error_code& ec) noexcept; private: - void init(std::error_code &ec, unsigned value); - void destroy(std::error_code &ec); + void init(std::error_code& ec, unsigned value); + void destroy(std::error_code& ec); private: #if defined(__APPLE__) semaphore_t sem_ {}; - static const std::error_category &mach_category(); + static const std::error_category& mach_category(); #elif defined(_WIN32) HANDLE sem_ {}; #else diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 75941298..2442d8df 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -532,8 +532,7 @@ TEST_CASE("[Files] Looped regions taken from files and possibly overriden") TEST_CASE("[Files] Case sentitiveness") { - const fs::path sfzFilePath = fs::current_path() / - "tests/TestFiles/case_insensitive.sfz"; + const fs::path sfzFilePath = fs::current_path() / "tests/TestFiles/case_insensitive.sfz"; #if defined(_WIN32) const bool caseSensitiveFs = false;