diff --git a/data/stoat/whitelist.txt b/data/stoat/whitelist.txt index e3163ee12..904d133e9 100644 --- a/data/stoat/whitelist.txt +++ b/data/stoat/whitelist.txt @@ -216,3 +216,4 @@ LinuxSampler::InstrumentManager::LoadInstrumentInBackground llround llabs clock_gettime +RtLinkedList$vtable3 diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index 4c66c53cb..df622104d 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -1864,9 +1864,9 @@ void CarlaPlugin::idle() #endif } - const CarlaMutexLocker sl(pData->postRtEvents.mutex); + const CarlaMutexLocker sl(pData->postRtEvents.getDataMutex()); - for (RtLinkedList::Itenerator it = pData->postRtEvents.data.begin2(); it.valid(); it.next()) + for (RtLinkedList::Itenerator it = pData->postRtEvents.getDataIterator(); it.valid(); it.next()) { const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback)); CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull); @@ -2032,7 +2032,7 @@ void CarlaPlugin::idle() } } - pData->postRtEvents.data.clear(); + pData->postRtEvents.clearData(); } bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept diff --git a/source/backend/plugin/CarlaPluginInternal.cpp b/source/backend/plugin/CarlaPluginInternal.cpp index 2bf31e5d0..c0028e596 100644 --- a/source/backend/plugin/CarlaPluginInternal.cpp +++ b/source/backend/plugin/CarlaPluginInternal.cpp @@ -501,40 +501,49 @@ void CarlaPlugin::ProtectedData::Latency::recreateBuffers(const uint32_t newChan // ProtectedData::PostRtEvents CarlaPlugin::ProtectedData::PostRtEvents::PostRtEvents() noexcept - : mutex(), - dataPool(128, 128), + : dataPool(128, 128), + dataPendingRT(dataPool), data(dataPool), - dataPendingRT(dataPool) {} + dataMutex(), + dataPendingMutex() {} CarlaPlugin::ProtectedData::PostRtEvents::~PostRtEvents() noexcept { - clear(); + dataMutex.lock(); + data.clear(); + dataMutex.unlock(); + + dataPendingMutex.lock(); + dataPendingRT.clear(); + dataPendingMutex.unlock(); } void CarlaPlugin::ProtectedData::PostRtEvents::appendRT(const PluginPostRtEvent& e) noexcept { - // FIXME - mutex.lock(); + CARLA_SAFE_ASSERT_RETURN(dataPendingMutex.tryLock(),); + dataPendingRT.append(e); - mutex.unlock(); + dataPendingMutex.unlock(); } void CarlaPlugin::ProtectedData::PostRtEvents::trySplice() noexcept { - if (mutex.tryLock()) + if (dataMutex.tryLock()) { if (dataPendingRT.count() > 0) dataPendingRT.moveTo(data, true); - mutex.unlock(); + dataMutex.unlock(); } } -void CarlaPlugin::ProtectedData::PostRtEvents::clear() noexcept +void CarlaPlugin::ProtectedData::PostRtEvents::clearData() noexcept { - mutex.lock(); + const bool tryLockOk(dataMutex.tryLock()); + CARLA_SAFE_ASSERT(! tryLockOk); data.clear(); - dataPendingRT.clear(); - mutex.unlock(); + + if (tryLockOk) + dataMutex.unlock(); } // ----------------------------------------------------------------------- diff --git a/source/backend/plugin/CarlaPluginInternal.hpp b/source/backend/plugin/CarlaPluginInternal.hpp index 5dadd7827..91614214d 100644 --- a/source/backend/plugin/CarlaPluginInternal.hpp +++ b/source/backend/plugin/CarlaPluginInternal.hpp @@ -282,19 +282,34 @@ struct CarlaPlugin::ProtectedData { } latency; - struct PostRtEvents { - CarlaMutex mutex; - RtLinkedList::Pool dataPool; - RtLinkedList data; - RtLinkedList dataPendingRT; - + class PostRtEvents { + public: PostRtEvents() noexcept; ~PostRtEvents() noexcept; void appendRT(const PluginPostRtEvent& event) noexcept; void trySplice() noexcept; - void clear() noexcept; + void clearData() noexcept; + + inline CarlaMutex& getDataMutex() noexcept + { + return dataMutex; + } + + inline RtLinkedList::Itenerator getDataIterator() const noexcept + { + return data.begin2(); + } + + private: + RtLinkedList::Pool dataPool; + RtLinkedList dataPendingRT; + RtLinkedList data; + CarlaMutex dataMutex; + + // TESTING for thread-safety, remove later + CarlaMutex dataPendingMutex; - CARLA_DECLARE_NON_COPY_STRUCT(PostRtEvents) + CARLA_DECLARE_NON_COPY_CLASS(PostRtEvents) } postRtEvents; diff --git a/source/utils/RtLinkedList.hpp b/source/utils/RtLinkedList.hpp index 5d8c86f2f..0d8f91aeb 100644 --- a/source/utils/RtLinkedList.hpp +++ b/source/utils/RtLinkedList.hpp @@ -1,6 +1,6 @@ /* * High-level, real-time safe, templated, C++ doubly-linked list - * Copyright (C) 2013-2014 Filipe Coelho + * Copyright (C) 2013-2018 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -107,6 +107,69 @@ public: RtLinkedList(Pool& memPool) noexcept : fMemPool(memPool) {} +#ifdef STOAT_TEST_BUILD + // overridden for stoat + bool append(const T& value) noexcept + { + if (typename AbstractLinkedList::Data* const data = _allocate()) + return this->_add_internal(data, value, true, &this->fQueue); + return false; + } + + void clear() noexcept + { + if (this->fCount == 0) + return; + + for (typename AbstractLinkedList::ListHead *entry = this->fQueue.next, *entry2 = entry->next; + entry != &this->fQueue; entry = entry2, entry2 = entry->next) + { + typename AbstractLinkedList::Data* const data = list_entry(entry, typename AbstractLinkedList::Data, siblings); + CARLA_SAFE_ASSERT_CONTINUE(data != nullptr); + + this->_deallocate(data); + } + + this->_init(); + } + + T getFirst(T& fallback, const bool removeObj) noexcept + { + CARLA_SAFE_ASSERT_RETURN(this->fCount > 0, fallback); + + typename AbstractLinkedList::ListHead* const entry = this->fQueue.next; + + typename AbstractLinkedList::Data* const data = list_entry(entry, typename AbstractLinkedList::Data, siblings); + CARLA_SAFE_ASSERT_RETURN(data != nullptr, fallback); + + if (! removeObj) + return data->value; + + const T value(data->value); + + _deleteRT(entry, data); + + return value; + } + + void _deleteRT(typename AbstractLinkedList::ListHead* const entry, typename AbstractLinkedList::Data* const data) noexcept + { + CARLA_SAFE_ASSERT_RETURN(entry != nullptr,); + CARLA_SAFE_ASSERT_RETURN(entry->prev != nullptr,); + CARLA_SAFE_ASSERT_RETURN(entry->next != nullptr,); + + --this->fCount; + + entry->next->prev = entry->prev; + entry->prev->next = entry->next; + + entry->next = nullptr; + entry->prev = nullptr; + + _deallocate(data); + } +#endif + bool append_sleepy(const T& value) noexcept { return _add_sleepy(value, true);