| @@ -216,3 +216,4 @@ LinuxSampler::InstrumentManager::LoadInstrumentInBackground | |||
| llround | |||
| llabs | |||
| clock_gettime | |||
| RtLinkedList$vtable3 | |||
| @@ -1864,9 +1864,9 @@ void CarlaPlugin::idle() | |||
| #endif | |||
| } | |||
| const CarlaMutexLocker sl(pData->postRtEvents.mutex); | |||
| const CarlaMutexLocker sl(pData->postRtEvents.getDataMutex()); | |||
| for (RtLinkedList<PluginPostRtEvent>::Itenerator it = pData->postRtEvents.data.begin2(); it.valid(); it.next()) | |||
| for (RtLinkedList<PluginPostRtEvent>::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 | |||
| @@ -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(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -282,19 +282,34 @@ struct CarlaPlugin::ProtectedData { | |||
| } latency; | |||
| struct PostRtEvents { | |||
| CarlaMutex mutex; | |||
| RtLinkedList<PluginPostRtEvent>::Pool dataPool; | |||
| RtLinkedList<PluginPostRtEvent> data; | |||
| RtLinkedList<PluginPostRtEvent> 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<PluginPostRtEvent>::Itenerator getDataIterator() const noexcept | |||
| { | |||
| return data.begin2(); | |||
| } | |||
| private: | |||
| RtLinkedList<PluginPostRtEvent>::Pool dataPool; | |||
| RtLinkedList<PluginPostRtEvent> dataPendingRT; | |||
| RtLinkedList<PluginPostRtEvent> data; | |||
| CarlaMutex dataMutex; | |||
| // TESTING for thread-safety, remove later | |||
| CarlaMutex dataPendingMutex; | |||
| CARLA_DECLARE_NON_COPY_STRUCT(PostRtEvents) | |||
| CARLA_DECLARE_NON_COPY_CLASS(PostRtEvents) | |||
| } postRtEvents; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * High-level, real-time safe, templated, C++ doubly-linked list | |||
| * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2013-2018 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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<T>::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<T>::ListHead *entry = this->fQueue.next, *entry2 = entry->next; | |||
| entry != &this->fQueue; entry = entry2, entry2 = entry->next) | |||
| { | |||
| typename AbstractLinkedList<T>::Data* const data = list_entry(entry, typename AbstractLinkedList<T>::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<T>::ListHead* const entry = this->fQueue.next; | |||
| typename AbstractLinkedList<T>::Data* const data = list_entry(entry, typename AbstractLinkedList<T>::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<T>::ListHead* const entry, typename AbstractLinkedList<T>::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); | |||