@@ -75,7 +75,8 @@ source/tests/CarlaString | |||
source/tests/DGL1 | |||
source/tests/DGL2 | |||
source/tests/Print | |||
source/tests/RtList | |||
source/tests/RtLinkedList | |||
source/tests/RtLinkedListGnu | |||
source/tests/Utils | |||
source/tests/Widgets | |||
@@ -50,7 +50,7 @@ | |||
* | |||
*/ | |||
#define container_of(ptr, type, member) ({ \ | |||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | |||
typeof( ((type *)0)->member ) *__mptr = (ptr); \ | |||
(type *)( (char *)__mptr - offsetof(type, member) );}) | |||
#define container_of_const(ptr, type, member) ({ \ | |||
@@ -304,7 +304,7 @@ static inline void list_splice_tail_init(struct list_head *list, struct list_hea | |||
* @type: the type of the struct this is embedded in. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#if defined(__GNUC__) && ! (defined(BUILD_ANSI_TEST) || defined(QTCREATOR_TEST)) | |||
#if defined(__GNUC__) && ! defined(__STRICT_ANSI__) | |||
# define list_entry(ptr, type, member) \ | |||
container_of(ptr, type, member) | |||
# define list_entry_const(ptr, type, member) \ | |||
@@ -75,9 +75,13 @@ Print: Print.cpp | |||
$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||
# valgrind ./Print | |||
RtList: RtList.cpp ../utils/RtList.hpp ../modules/rtmempool.a | |||
RtLinkedList: RtLinkedList.cpp ../utils/LinkedList.hpp ../utils/RtLinkedList.hpp ../modules/rtmempool.a | |||
$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -lpthread -o $@ | |||
# valgrind ./RtList | |||
valgrind ./RtLinkedList | |||
RtLinkedListGnu: RtLinkedList.cpp ../utils/LinkedList.hpp ../utils/RtLinkedList.hpp ../modules/rtmempool.a | |||
$(CXX) $^ $(BUILD_CXX_FLAGS) -std=gnu++11 $(LINK_FLAGS) -lpthread -o $@ | |||
valgrind ./RtLinkedListGnu | |||
Utils: Utils.cpp | |||
$(CXX) $^ $(BUILD_CXX_FLAGS) $(ANSI_CXX_FLAGS) -std=c++11 -Wzero-as-null-pointer-constant $(LINK_FLAGS) -ldl -lpthread -o $@ | |||
@@ -1,195 +0,0 @@ | |||
/* | |||
* Carla Tests | |||
* Copyright (C) 2013 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 | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#include "RtList.hpp" | |||
#include "CarlaString.hpp" | |||
#include "CarlaMutex.hpp" | |||
const unsigned short MIN_RT_EVENTS = 5; | |||
const unsigned short MAX_RT_EVENTS = 10; | |||
struct MyData { | |||
CarlaString str; | |||
int idStr; | |||
MyData() | |||
: idStr(-1) {} | |||
MyData(int id) | |||
: str(id), | |||
idStr(id) {} | |||
}; | |||
struct PostRtEvents { | |||
CarlaMutex mutex; | |||
RtList<MyData>::Pool dataPool; | |||
RtList<MyData> data; | |||
RtList<MyData> dataPendingRT; | |||
PostRtEvents() | |||
: dataPool(MIN_RT_EVENTS, MAX_RT_EVENTS), | |||
data(dataPool), | |||
dataPendingRT(dataPool) {} | |||
~PostRtEvents() | |||
{ | |||
clear(); | |||
} | |||
void appendRT(const MyData& event) | |||
{ | |||
dataPendingRT.append(event); | |||
} | |||
void clear() | |||
{ | |||
mutex.lock(); | |||
data.clear(); | |||
dataPendingRT.clear(); | |||
mutex.unlock(); | |||
} | |||
void trySplice() | |||
{ | |||
if (mutex.tryLock()) | |||
{ | |||
dataPendingRT.spliceAppend(data); | |||
mutex.unlock(); | |||
} | |||
} | |||
} postRtEvents; | |||
void run5Tests() | |||
{ | |||
unsigned short k = 0; | |||
MyData allMyData[MAX_RT_EVENTS]; | |||
// Make a safe copy of events while clearing them | |||
postRtEvents.mutex.lock(); | |||
while (! postRtEvents.data.isEmpty()) | |||
{ | |||
const MyData& my(postRtEvents.data.getFirst(true)); | |||
allMyData[k++] = my; | |||
} | |||
postRtEvents.mutex.unlock(); | |||
printf("Post-Rt Event Count: %i\n", k); | |||
assert(k == 5); | |||
// data should be empty now | |||
assert(postRtEvents.data.count() == 0); | |||
assert(postRtEvents.data.isEmpty()); | |||
assert(postRtEvents.dataPendingRT.count() == 0); | |||
assert(postRtEvents.dataPendingRT.isEmpty()); | |||
// Handle events now | |||
for (unsigned short i=0; i < k; ++i) | |||
{ | |||
const MyData& my(allMyData[i]); | |||
printf("Got data: %i %s\n", my.idStr, (const char*)my.str); | |||
} | |||
} | |||
int main() | |||
{ | |||
MyData m1(1); | |||
MyData m2(2); | |||
MyData m3(3); | |||
MyData m4(4); | |||
MyData m5(5); | |||
// start | |||
assert(postRtEvents.data.count() == 0); | |||
assert(postRtEvents.data.isEmpty()); | |||
assert(postRtEvents.dataPendingRT.count() == 0); | |||
assert(postRtEvents.dataPendingRT.isEmpty()); | |||
// single append | |||
postRtEvents.appendRT(m1); | |||
postRtEvents.trySplice(); | |||
assert(postRtEvents.data.count() == 1); | |||
assert(postRtEvents.dataPendingRT.count() == 0); | |||
// +3 appends | |||
postRtEvents.appendRT(m2); | |||
postRtEvents.appendRT(m4); | |||
postRtEvents.appendRT(m3); | |||
assert(postRtEvents.data.count() == 1); | |||
assert(postRtEvents.dataPendingRT.count() == 3); | |||
postRtEvents.trySplice(); | |||
assert(postRtEvents.data.count() == 4); | |||
assert(postRtEvents.dataPendingRT.count() == 0); | |||
for (RtList<MyData>::Itenerator it = postRtEvents.data.begin(); it.valid(); it.next()) | |||
{ | |||
MyData& my(*it); | |||
printf("FOR DATA!!!: %i %s\n", my.idStr, (const char*)my.str); | |||
if (my.idStr == 1) | |||
{ | |||
// +1 append at | |||
postRtEvents.dataPendingRT.insertAt(m5, it); | |||
assert(postRtEvents.data.count() == 4); | |||
assert(postRtEvents.dataPendingRT.count() == 1); | |||
postRtEvents.trySplice(); | |||
assert(postRtEvents.data.count() == 5); | |||
assert(postRtEvents.dataPendingRT.count() == 0); | |||
} | |||
} | |||
run5Tests(); | |||
// reset | |||
postRtEvents.clear(); | |||
assert(postRtEvents.data.count() == 0); | |||
assert(postRtEvents.data.isEmpty()); | |||
assert(postRtEvents.dataPendingRT.count() == 0); | |||
assert(postRtEvents.dataPendingRT.isEmpty()); | |||
// test non-rt | |||
const unsigned int CARLA_EVENT_DATA_ATOM = 0x01; | |||
const unsigned int CARLA_EVENT_DATA_MIDI_LL = 0x04; | |||
NonRtList<uint32_t> evIns, evOuts; | |||
evIns.append(CARLA_EVENT_DATA_ATOM); | |||
evOuts.append(CARLA_EVENT_DATA_ATOM); | |||
evOuts.append(CARLA_EVENT_DATA_MIDI_LL); | |||
if (evIns.count() > 0) | |||
{ | |||
for (uint32_t j=0, count=evIns.count(); j < count; ++j) | |||
{ | |||
const uint32_t& type(evIns.getAt(j)); | |||
if (type == CARLA_EVENT_DATA_ATOM) | |||
pass(); | |||
else if (type == CARLA_EVENT_DATA_MIDI_LL) | |||
pass(); | |||
} | |||
} | |||
evIns.clear(); | |||
evOuts.clear(); | |||
return 0; | |||
} |
@@ -1,6 +1,6 @@ | |||
/* | |||
* High-level, templated, C++ doubly-linked list | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2013-2014 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 | |||
@@ -15,8 +15,8 @@ | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#ifndef LIST_HPP_INCLUDED | |||
#define LIST_HPP_INCLUDED | |||
#ifndef LINKED_LIST_HPP_INCLUDED | |||
#define LINKED_LIST_HPP_INCLUDED | |||
#include "CarlaUtils.hpp" | |||
@@ -28,26 +28,26 @@ extern "C" { | |||
// Declare non copyable and prevent heap allocation | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
# define LIST_DECLARATIONS(ClassName) \ | |||
# define LINKED_LIST_DECLARATIONS(ClassName) \ | |||
ClassName(ClassName&) = delete; \ | |||
ClassName(const ClassName&) = delete; \ | |||
ClassName& operator=(const ClassName&) = delete; \ | |||
static void* operator new(size_t) = delete; | |||
#else | |||
# define LIST_DECLARATIONS(ClassName) \ | |||
ClassName(ClassName&); \ | |||
ClassName(const ClassName&); \ | |||
# define LINKED_LIST_DECLARATIONS(ClassName) \ | |||
ClassName(ClassName&); \ | |||
ClassName(const ClassName&); \ | |||
ClassName& operator=(const ClassName&); | |||
#endif | |||
typedef struct list_head k_list_head; | |||
// ----------------------------------------------------------------------- | |||
// Abstract List class | |||
// Abstract Linked List class | |||
// _allocate() and _deallocate are virtual calls provided by subclasses | |||
template<typename T> | |||
class AbstractList | |||
class AbstractLinkedList | |||
{ | |||
protected: | |||
struct Data { | |||
@@ -55,26 +55,26 @@ protected: | |||
k_list_head siblings; | |||
}; | |||
AbstractList() | |||
AbstractLinkedList() | |||
: fDataSize(sizeof(Data)), | |||
fCount(0) | |||
{ | |||
_init(); | |||
} | |||
virtual ~AbstractList() | |||
public: | |||
virtual ~AbstractLinkedList() | |||
{ | |||
CARLA_ASSERT(fCount == 0); | |||
} | |||
public: | |||
class Itenerator { | |||
public: | |||
Itenerator(const k_list_head* queue) | |||
: fEntry(queue->next), | |||
: fData(nullptr), | |||
fEntry(queue->next), | |||
fEntry2(fEntry->next), | |||
fQueue(queue), | |||
fData(nullptr) | |||
fQueue(queue) | |||
{ | |||
CARLA_ASSERT(fEntry != nullptr); | |||
CARLA_ASSERT(fEntry2 != nullptr); | |||
@@ -99,31 +99,13 @@ public: | |||
return fData->value; | |||
} | |||
const T& getConstValue() | |||
{ | |||
fConstData = list_entry_const(fEntry, Data, siblings); | |||
CARLA_ASSERT(fConstData != nullptr); | |||
return fConstData->value; | |||
} | |||
#if 0 | |||
T& operator*() const | |||
{ | |||
return getValue(); | |||
} | |||
#endif | |||
private: | |||
Data* fData; | |||
k_list_head* fEntry; | |||
k_list_head* fEntry2; | |||
const k_list_head* const fQueue; | |||
union { | |||
Data* fData; | |||
const Data* fConstData; | |||
}; | |||
friend class AbstractList; | |||
friend class AbstractLinkedList; | |||
}; | |||
Itenerator begin() const | |||
@@ -151,35 +133,6 @@ public: | |||
_init(); | |||
} | |||
// temporary fix for some const issue in midi-base.hpp | |||
void clear_const() | |||
{ | |||
if (fCount != 0) | |||
{ | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
if (const Data* data = list_entry_const(entry, Data, siblings)) | |||
{ | |||
data->~Data(); | |||
union CData { | |||
const Data* cdata; | |||
Data* data; | |||
}; | |||
CData d; | |||
d.cdata = data; | |||
_deallocate(d.data); | |||
} | |||
} | |||
} | |||
_init(); | |||
} | |||
size_t count() const noexcept | |||
{ | |||
return fCount; | |||
@@ -356,7 +309,7 @@ public: | |||
} | |||
} | |||
void spliceAppend(AbstractList& list, const bool init = true) | |||
void spliceAppend(AbstractLinkedList& list, const bool init = true) | |||
{ | |||
if (init) | |||
{ | |||
@@ -371,7 +324,7 @@ public: | |||
} | |||
} | |||
void spliceInsert(AbstractList& list, const bool init = true) | |||
void spliceInsert(AbstractLinkedList& list, const bool init = true) | |||
{ | |||
if (init) | |||
{ | |||
@@ -429,27 +382,25 @@ private: | |||
return fRetValue; | |||
} | |||
LIST_DECLARATIONS(AbstractList) | |||
LINKED_LIST_DECLARATIONS(AbstractLinkedList) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// List | |||
// LinkedList | |||
template<typename T> | |||
class List : public AbstractList<T> | |||
class LinkedList : public AbstractLinkedList<T> | |||
{ | |||
public: | |||
List() | |||
{ | |||
} | |||
LinkedList() {} | |||
private: | |||
typename AbstractList<T>::Data* _allocate() override | |||
typename AbstractLinkedList<T>::Data* _allocate() override | |||
{ | |||
return (typename AbstractList<T>::Data*)std::malloc(this->fDataSize); | |||
return (typename AbstractLinkedList<T>::Data*)std::malloc(this->fDataSize); | |||
} | |||
void _deallocate(typename AbstractList<T>::Data*& dataPtr) override | |||
void _deallocate(typename AbstractLinkedList<T>::Data*& dataPtr) override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,); | |||
@@ -457,9 +408,9 @@ private: | |||
dataPtr = nullptr; | |||
} | |||
LIST_DECLARATIONS(List) | |||
LINKED_LIST_DECLARATIONS(LinkedList) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
#endif // LIST_HPP_INCLUDED | |||
#endif // LINKED_LIST_HPP_INCLUDED |
@@ -15,20 +15,20 @@ | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#ifndef RT_LIST_HPP_INCLUDED | |||
#define RT_LIST_HPP_INCLUDED | |||
#ifndef RT_LINKED_LIST_HPP_INCLUDED | |||
#define RT_LINKED_LIST_HPP_INCLUDED | |||
#include "List.hpp" | |||
#include "LinkedList.hpp" | |||
extern "C" { | |||
#include "rtmempool/rtmempool.h" | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Realtime safe list | |||
// Realtime safe linkedlist | |||
template<typename T> | |||
class RtList : public AbstractList<T> | |||
class RtLinkedList : public AbstractLinkedList<T> | |||
{ | |||
public: | |||
// ------------------------------------------------------------------- | |||
@@ -39,7 +39,7 @@ public: | |||
public: | |||
Pool(const size_t minPreallocated, const size_t maxPreallocated) | |||
: fHandle(nullptr), | |||
fDataSize(sizeof(typename AbstractList<T>::Data)) | |||
fDataSize(sizeof(typename AbstractLinkedList<T>::Data)) | |||
{ | |||
resize(minPreallocated, maxPreallocated); | |||
} | |||
@@ -96,18 +96,16 @@ public: | |||
}; | |||
// ------------------------------------------------------------------- | |||
// Now the actual rt-list code | |||
// Now the actual rt-linkedlist code | |||
RtList(Pool& memPool) | |||
: fMemPool(memPool) | |||
{ | |||
} | |||
RtLinkedList(Pool& memPool) | |||
: fMemPool(memPool) {} | |||
void append_sleepy(const T& value) | |||
{ | |||
if (typename AbstractList<T>::Data* const data = _allocate_sleepy()) | |||
if (typename AbstractLinkedList<T>::Data* const data = _allocate_sleepy()) | |||
{ | |||
new(data)typename AbstractList<T>::Data(); | |||
new(data)typename AbstractLinkedList<T>::Data(); | |||
data->value = value; | |||
list_add_tail(&data->siblings, &this->fQueue); | |||
++(this->fCount); | |||
@@ -116,9 +114,9 @@ public: | |||
void insert_sleepy(const T& value) | |||
{ | |||
if (typename AbstractList<T>::Data* const data = _allocate_sleepy()) | |||
if (typename AbstractLinkedList<T>::Data* const data = _allocate_sleepy()) | |||
{ | |||
new(data)typename AbstractList<T>::Data(); | |||
new(data)typename AbstractLinkedList<T>::Data(); | |||
data->value = value; | |||
list_add(&data->siblings, &this->fQueue); | |||
++(this->fCount); | |||
@@ -132,34 +130,34 @@ public: | |||
fMemPool.resize(minPreallocated, maxPreallocated); | |||
} | |||
void spliceAppend(RtList& list, const bool init = true) | |||
void spliceAppend(RtLinkedList& list, const bool init = true) | |||
{ | |||
CARLA_ASSERT(fMemPool == list.fMemPool); | |||
AbstractList<T>::spliceAppend(list, init); | |||
AbstractLinkedList<T>::spliceAppend(list, init); | |||
} | |||
void spliceInsert(RtList& list, const bool init = true) | |||
void spliceInsert(RtLinkedList& list, const bool init = true) | |||
{ | |||
CARLA_ASSERT(fMemPool == list.fMemPool); | |||
AbstractList<T>::spliceInsert(list, init); | |||
AbstractLinkedList<T>::spliceInsert(list, init); | |||
} | |||
private: | |||
Pool& fMemPool; | |||
typename AbstractList<T>::Data* _allocate() override | |||
typename AbstractLinkedList<T>::Data* _allocate() override | |||
{ | |||
return (typename AbstractList<T>::Data*)fMemPool.allocate_atomic(); | |||
return (typename AbstractLinkedList<T>::Data*)fMemPool.allocate_atomic(); | |||
} | |||
typename AbstractList<T>::Data* _allocate_sleepy() | |||
typename AbstractLinkedList<T>::Data* _allocate_sleepy() | |||
{ | |||
return (typename AbstractList<T>::Data*)fMemPool.allocate_sleepy(); | |||
return (typename AbstractLinkedList<T>::Data*)fMemPool.allocate_sleepy(); | |||
} | |||
void _deallocate(typename AbstractList<T>::Data*& dataPtr) override | |||
void _deallocate(typename AbstractLinkedList<T>::Data*& dataPtr) override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,); | |||
@@ -167,9 +165,9 @@ private: | |||
dataPtr = nullptr; | |||
} | |||
LIST_DECLARATIONS(RtList) | |||
LINKED_LIST_DECLARATIONS(RtLinkedList) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
#endif // RT_LIST_HPP_INCLUDED | |||
#endif // RT_LINKED_LIST_HPP_INCLUDED |