@@ -216,3 +216,4 @@ LinuxSampler::InstrumentManager::LoadInstrumentInBackground | |||||
llround | llround | ||||
llabs | llabs | ||||
clock_gettime | clock_gettime | ||||
RtLinkedList$vtable3 |
@@ -1864,9 +1864,9 @@ void CarlaPlugin::idle() | |||||
#endif | #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)); | const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback)); | ||||
CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull); | 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 | bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept | ||||
@@ -501,40 +501,49 @@ void CarlaPlugin::ProtectedData::Latency::recreateBuffers(const uint32_t newChan | |||||
// ProtectedData::PostRtEvents | // ProtectedData::PostRtEvents | ||||
CarlaPlugin::ProtectedData::PostRtEvents::PostRtEvents() noexcept | CarlaPlugin::ProtectedData::PostRtEvents::PostRtEvents() noexcept | ||||
: mutex(), | |||||
dataPool(128, 128), | |||||
: dataPool(128, 128), | |||||
dataPendingRT(dataPool), | |||||
data(dataPool), | data(dataPool), | ||||
dataPendingRT(dataPool) {} | |||||
dataMutex(), | |||||
dataPendingMutex() {} | |||||
CarlaPlugin::ProtectedData::PostRtEvents::~PostRtEvents() noexcept | 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 | void CarlaPlugin::ProtectedData::PostRtEvents::appendRT(const PluginPostRtEvent& e) noexcept | ||||
{ | { | ||||
// FIXME | |||||
mutex.lock(); | |||||
CARLA_SAFE_ASSERT_RETURN(dataPendingMutex.tryLock(),); | |||||
dataPendingRT.append(e); | dataPendingRT.append(e); | ||||
mutex.unlock(); | |||||
dataPendingMutex.unlock(); | |||||
} | } | ||||
void CarlaPlugin::ProtectedData::PostRtEvents::trySplice() noexcept | void CarlaPlugin::ProtectedData::PostRtEvents::trySplice() noexcept | ||||
{ | { | ||||
if (mutex.tryLock()) | |||||
if (dataMutex.tryLock()) | |||||
{ | { | ||||
if (dataPendingRT.count() > 0) | if (dataPendingRT.count() > 0) | ||||
dataPendingRT.moveTo(data, true); | 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(); | data.clear(); | ||||
dataPendingRT.clear(); | |||||
mutex.unlock(); | |||||
if (tryLockOk) | |||||
dataMutex.unlock(); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -282,19 +282,34 @@ struct CarlaPlugin::ProtectedData { | |||||
} latency; | } latency; | ||||
struct PostRtEvents { | |||||
CarlaMutex mutex; | |||||
RtLinkedList<PluginPostRtEvent>::Pool dataPool; | |||||
RtLinkedList<PluginPostRtEvent> data; | |||||
RtLinkedList<PluginPostRtEvent> dataPendingRT; | |||||
class PostRtEvents { | |||||
public: | |||||
PostRtEvents() noexcept; | PostRtEvents() noexcept; | ||||
~PostRtEvents() noexcept; | ~PostRtEvents() noexcept; | ||||
void appendRT(const PluginPostRtEvent& event) noexcept; | void appendRT(const PluginPostRtEvent& event) noexcept; | ||||
void trySplice() 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; | } postRtEvents; | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* High-level, real-time safe, templated, C++ doubly-linked list | * 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 | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -107,6 +107,69 @@ public: | |||||
RtLinkedList(Pool& memPool) noexcept | RtLinkedList(Pool& memPool) noexcept | ||||
: fMemPool(memPool) {} | : 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 | bool append_sleepy(const T& value) noexcept | ||||
{ | { | ||||
return _add_sleepy(value, true); | return _add_sleepy(value, true); | ||||