/* * Carla Tests * Copyright (C) 2013-2014 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 * 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 "RtLinkedList.hpp" #include "CarlaString.hpp" #include "CarlaMutex.hpp" const unsigned short MIN_RT_EVENTS = 5; const unsigned short MAX_RT_EVENTS = 12; struct MyData { char str[234]; int id; }; struct PostRtEvents { CarlaMutex mutex; RtLinkedList::Pool dataPool; RtLinkedList data; RtLinkedList dataPendingRT; PostRtEvents() noexcept : dataPool(MIN_RT_EVENTS, MAX_RT_EVENTS), data(dataPool), dataPendingRT(dataPool) {} ~PostRtEvents() noexcept { clear(); } void appendRT(const MyData& event) noexcept { dataPendingRT.append(event); } void clear() noexcept { mutex.lock(); data.clear(); dataPendingRT.clear(); mutex.unlock(); } void trySplice() noexcept { if (mutex.tryLock()) { dataPendingRT.moveTo(data, true); mutex.unlock(); } } } postRtEvents; void run5Tests(); void run5Tests() { ushort k = 0; MyData allMyData[MAX_RT_EVENTS]; // Make a safe copy of events while clearing them postRtEvents.mutex.lock(); while (! postRtEvents.data.isEmpty()) { static MyData kFallback = { { '\0' }, 0 }; const MyData& my(postRtEvents.data.getFirst(kFallback, true)); allMyData[k++] = my; } postRtEvents.mutex.unlock(); carla_stdout("Post-Rt Event Count: %i", 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 (ushort i=0; i < k; ++i) { const MyData& my(allMyData[i]); carla_stdout("Got data: %i %s", my.id, my.str); } // append events past minimum size MyData dummyData = { { '\0' }, 0 }; // 5 initial go ok assert(postRtEvents.dataPendingRT.append(dummyData)); assert(postRtEvents.dataPendingRT.append(dummyData)); assert(postRtEvents.dataPendingRT.append(dummyData)); assert(postRtEvents.dataPendingRT.append(dummyData)); assert(postRtEvents.dataPendingRT.append(dummyData)); // afterwards it fails assert(! postRtEvents.dataPendingRT.append(dummyData)); assert(! postRtEvents.dataPendingRT.append(dummyData)); carla_stdout("here %i", __LINE__); // adding sleepy works assert(postRtEvents.dataPendingRT.append_sleepy(dummyData)); carla_stdout("here %i", __LINE__); // now atomic works too, size was increased assert(postRtEvents.dataPendingRT.append(dummyData)); assert(postRtEvents.dataPendingRT.append(dummyData)); assert(postRtEvents.dataPendingRT.append(dummyData)); assert(postRtEvents.dataPendingRT.append(dummyData)); carla_stdout("here %i", __LINE__); // fails here now assert(! postRtEvents.dataPendingRT.append(dummyData)); carla_stdout("here %i", __LINE__); // adding sleepy still works assert(postRtEvents.dataPendingRT.append_sleepy(dummyData)); carla_stdout("here %i", __LINE__); // now atomic works for 1 more assert(postRtEvents.dataPendingRT.append(dummyData)); assert(! postRtEvents.dataPendingRT.append(dummyData)); carla_stdout("here %i", __LINE__); // and adding sleepy no longer works assert(! postRtEvents.dataPendingRT.append_sleepy(dummyData)); carla_stdout("here %i", __LINE__); // cleanup postRtEvents.trySplice(); postRtEvents.clear(); } int main() { MyData m1; m1.id = 1; std::strcpy(m1.str, "1"); MyData m2; m2.id = 2; std::strcpy(m2.str, "2"); MyData m3; m3.id = 3; std::strcpy(m3.str, "3"); MyData m4; m4.id = 4; std::strcpy(m4.str, "4"); MyData m5; m5.id = 5; std::strcpy(m5.str, "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); assert(postRtEvents.data.count() == 0); assert(postRtEvents.dataPendingRT.count() == 1); 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 (RtLinkedList::Itenerator it = postRtEvents.data.begin2(); it.valid(); it.next()) { static const MyData kFallback = { { '\0' }, 0 }; const MyData& my(it.getValue(kFallback)); carla_stdout("FOR DATA!!!: %i %s", my.id, my.str); if (my.id == 2) { // +1 append postRtEvents.dataPendingRT.insertAt(m5, it); assert(postRtEvents.data.count() == 4); assert(postRtEvents.dataPendingRT.count() == 1); } } #if 0 for (const MyData& my : postRtEvents.data) carla_stdout("FOR DATA!!! NEW AUTO Itenerator!!!: %i %s", my.id, my.str); #endif 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; LinkedList 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 (size_t j=0, count=evIns.count(); j < count; ++j) { const uint32_t& type(evIns.getAt(j, 0)); if (type == CARLA_EVENT_DATA_ATOM) pass(); else if (type == CARLA_EVENT_DATA_MIDI_LL) pass(); } } evIns.clear(); evOuts.clear(); return 0; }