bool SoftwareTimerOrderingTestCase::run_() const { constexpr auto totalSoftwareTimers = totalThreads; for (const auto& phase : priorityTestPhases) { SequenceAsserter sequenceAsserter; using TestSoftwareTimer = decltype(makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(std::declval<SequenceAsserter&>()), std::declval<unsigned int>())); std::array<TestSoftwareTimer, totalSoftwareTimers> softwareTimers {{ makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[0]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[1]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[2]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[3]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[4]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[5]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[6]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[7]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[8]].second)), makeStaticSoftwareTimer(&SequenceAsserter::sequencePoint, std::ref(sequenceAsserter), static_cast<unsigned int>(phase.first[phase.second[9]].second)), }}; waitForNextTick(); for (size_t i = 0; i < softwareTimers.size(); ++i) softwareTimers[i].start(TickClock::duration{maxPhasePriority + 1 - phase.first[phase.second[i]].first}); if (sequenceAsserter.assertSequence(0) == false) return false; for (const auto& softwareTimer : softwareTimers) while(softwareTimer.isRunning()) { } if (sequenceAsserter.assertSequence(totalSoftwareTimers) == false) return false; } return true; }
bool CallOnceOperationsTestCase::run_() const { #if DISTORTOS_CALLONCE_SUPPORTED == 1 || DOXYGEN == 1 const auto contextSwitchCount = statistics::getContextSwitchCount(); SequenceAsserter sequenceAsserter; OnceFlag onceFlag; using TestThread = decltype(makeTestThread(uint8_t{}, sequenceAsserter, SequencePoints{}, onceFlag)); std::array<TestThread, totalThreads> threads {{ makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{0, 12}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{2, 13}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{3, 14}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{4, 15}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{5, 16}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{6, 17}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{7, 18}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{8, 19}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{9, 20}, onceFlag), makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{10, 21}, onceFlag), }}; waitForNextTick(); const auto start = TickClock::now(); for (auto& thread : threads) thread.start(); ThisThread::setPriority(testCasePriority_ - 2); for (auto& thread : threads) thread.join(); if (TickClock::now() - start != sleepForDuration + decltype(sleepForDuration){1}) return false; if (sequenceAsserter.assertSequence(totalThreads * 2 + 2) == false) return false; constexpr auto totalContextSwitches = 2 * totalThreads + 3 + waitForNextTickContextSwitchCount; if (statistics::getContextSwitchCount() - contextSwitchCount != totalContextSwitches) return false; #endif // DISTORTOS_CALLONCE_SUPPORTED == 1 || DOXYGEN == 1 return true; }
bool MutexRecursiveOperationsTestCase::run_() const { using Parameters = std::pair<Mutex::Protocol, uint8_t>; static const Parameters parametersArray[] { Parameters{Mutex::Protocol::none, {}}, Parameters{Mutex::Protocol::priorityProtect, UINT8_MAX}, Parameters{Mutex::Protocol::priorityProtect, testCasePriority_}, Parameters{Mutex::Protocol::priorityInheritance, {}}, }; for (const auto& parameters : parametersArray) { Mutex mutex {Mutex::Type::recursive, parameters.first, parameters.second}; size_t lockCount {}; { // simple lock - must succeed immediately ++lockCount; waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.lock(); if (ret != 0 || start != TickClock::now()) return false; } const auto maxRecursiveLocks = mutex.getMaxRecursiveLocks(); if (maxRecursiveLocks < 4) return false; { // recursive lock - must succeed immediately ++lockCount; waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.lock(); if (ret != 0 || start != TickClock::now()) return false; } { // recursive lock - must succeed immediately ++lockCount; waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.tryLock(); if (ret != 0 || start != TickClock::now()) return false; } { // recursive lock - must succeed immediately ++lockCount; waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.tryLockFor(singleDuration); if (ret != 0 || start != TickClock::now()) return false; } { // recursive lock - must succeed immediately ++lockCount; waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.tryLockUntil(start + singleDuration); if (ret != 0 || start != TickClock::now()) return false; } while (lockCount < maxRecursiveLocks + 1) { // recursive lock - must succeed ++lockCount; const auto ret = mutex.tryLock(); if (ret != 0) return false; } { // excessive recursive lock - must fail with EAGAIN immediately waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.lock(); if (ret != EAGAIN || start != TickClock::now()) return false; } { // excessive recursive lock - must fail with EAGAIN immediately waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.tryLock(); if (ret != EAGAIN || start != TickClock::now()) return false; } { // excessive recursive lock - must fail with EAGAIN immediately waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.tryLockFor(singleDuration); if (ret != EAGAIN || start != TickClock::now()) return false; } { // excessive recursive lock - must fail with EAGAIN immediately waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.tryLockUntil(start + singleDuration); if (ret != EAGAIN || start != TickClock::now()) return false; } { const auto ret = mutexTestTryLockWhenLocked(mutex, testCasePriority_); if (ret != true) return ret; } { const auto ret = mutexTestUnlockFromWrongThread(mutex); if (ret != true) return ret; } { // simple unlock - must succeed immediately --lockCount; waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.unlock(); if (ret != 0 || start != TickClock::now()) return false; } { const auto ret = mutexTestTryLockWhenLocked(mutex, testCasePriority_); if (ret != true) return ret; } while (lockCount > 0) { // simple unlock - must succeed --lockCount; const auto ret = mutex.unlock(); if (ret != 0) return false; } { // excessive unlock - must fail with EPERM immediately waitForNextTick(); const auto start = TickClock::now(); const auto ret = mutex.unlock(); if (ret != EPERM || start != TickClock::now()) return false; } } return true; }