Skip to content

Commit

Permalink
[fiber] Guarantee minimum for durations < 1µs
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Aug 13, 2024
1 parent e75fae5 commit 1319de9
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 16 deletions.
8 changes: 6 additions & 2 deletions src/modm/processing/fiber/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,16 @@ poll_for(std::chrono::duration<Rep, Period> sleep_duration, Function &&condition
std::chrono::duration<Rep, std::milli>>,
modm::chrono::milli_clock, modm::chrono::micro_clock>;

// Ensure the sleep duration is rounded up to the next full clock tick
const auto clock_sleep_duration(
std::chrono::ceil<typename Clock::duration>(sleep_duration));

const auto start = Clock::now();
do {
modm::this_fiber::yield();
if (std::forward<Function>(condition)()) return true;
}
while((Clock::now() - start) <= sleep_duration);
while((Clock::now() - start) < clock_sleep_duration);
return false;
}

Expand Down Expand Up @@ -125,7 +129,7 @@ poll_until(std::chrono::time_point<Clock, Duration> sleep_time, Function &&condi
modm::this_fiber::yield();
if (std::forward<Function>(condition)()) return true;
}
while((Clock::now() - start) <= sleep_duration);
while((Clock::now() - start) < sleep_duration);
return false;
}

Expand Down
67 changes: 53 additions & 14 deletions test/modm/processing/fiber/fiber_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
#include <modm-test/mock/clock.hpp>

using namespace std::chrono_literals;
using test_clock = modm_test::chrono::milli_clock;
using test_clock_ms = modm_test::chrono::milli_clock;
using test_clock_us = modm_test::chrono::micro_clock;

void
FiberTest::setUp()
Expand Down Expand Up @@ -103,7 +104,7 @@ FiberTest::testYieldFromSubroutine()
void
FiberTest::testPollFor()
{
test_clock::setTime(1251);
test_clock_ms::setTime(1251);
TEST_ASSERT_TRUE(modm::this_fiber::poll_for(20ms, []{ return true; }));
// timeout is tested in the SleepFor() test
}
Expand All @@ -112,7 +113,7 @@ FiberTest::testPollFor()
void
FiberTest::testPollUntil()
{
test_clock::setTime(451250);
test_clock_ms::setTime(451250);
TEST_ASSERT_TRUE(modm::this_fiber::poll_until(modm::Clock::now() + 20ms, []{ return true; }));
TEST_ASSERT_TRUE(modm::this_fiber::poll_until(modm::Clock::now() - 20ms, []{ return true; }));
// timeout is tested in the SleepUntil() tests
Expand All @@ -123,33 +124,52 @@ static void
f4()
{
TEST_ASSERT_EQUALS(state++, 0u);
modm::this_fiber::sleep_for(50ms); // goto 1
// yields only once
modm::this_fiber::sleep_for(0s); // goto 1

TEST_ASSERT_EQUALS(state++, 2u);
// rounds up to 1us, not 0us!
modm::this_fiber::sleep_for(100ns); // goto 3

TEST_ASSERT_EQUALS(state++, 5u);
modm::this_fiber::sleep_for(50ms); // goto 6
TEST_ASSERT_EQUALS(state++, 10u);
}

static void
f5()
{
TEST_ASSERT_EQUALS(state++, 1u);
test_clock::increment(10);
TEST_ASSERT_EQUALS(state++, 2u);
modm::this_fiber::yield();
modm::this_fiber::yield(); // goto 2

test_clock::increment(20);
TEST_ASSERT_EQUALS(state++, 3u);
modm::this_fiber::yield();

test_clock::increment(30);
TEST_ASSERT_EQUALS(state++, 4u);
test_clock_us::increment(1);
modm::this_fiber::yield(); // goto 5

TEST_ASSERT_EQUALS(state++, 6u);
test_clock_ms::increment(10);
TEST_ASSERT_EQUALS(state++, 7u);
modm::this_fiber::yield();

test_clock_ms::increment(20);
TEST_ASSERT_EQUALS(state++, 8u);
modm::this_fiber::yield();

test_clock_ms::increment(30);
TEST_ASSERT_EQUALS(state++, 9u);
modm::this_fiber::yield(); // goto 10

TEST_ASSERT_EQUALS(state++, 11u);
}

static void
runSleepFor(uint32_t startTime)
{
test_clock::setTime(startTime);
test_clock_ms::setTime(startTime);
test_clock_us::setTime(startTime);
modm::fiber::Task fiber1(stack1, f4), fiber2(stack2, f5);
modm::fiber::Scheduler::run();
}
Expand All @@ -165,6 +185,25 @@ FiberTest::testSleepFor()

static void
f6()
{
TEST_ASSERT_EQUALS(state++, 1u);
test_clock_ms::increment(10);
TEST_ASSERT_EQUALS(state++, 2u);
modm::this_fiber::yield();

test_clock_ms::increment(20);
TEST_ASSERT_EQUALS(state++, 3u);
modm::this_fiber::yield();

test_clock_ms::increment(30);
TEST_ASSERT_EQUALS(state++, 4u);
modm::this_fiber::yield(); // goto 5

TEST_ASSERT_EQUALS(state++, 6u);
}

static void
f7()
{
TEST_ASSERT_EQUALS(state++, 0u); // goto 1
modm::this_fiber::sleep_until(modm::Clock::now() + 50ms);
Expand All @@ -177,8 +216,8 @@ f6()
static void
runSleepUntil(uint32_t startTime)
{
test_clock::setTime(startTime);
modm::fiber::Task fiber1(stack1, f6), fiber2(stack2, f5);
test_clock_ms::setTime(startTime);
modm::fiber::Task fiber1(stack1, f7), fiber2(stack2, f6);
modm::fiber::Scheduler::run();
}

Expand All @@ -191,7 +230,7 @@ FiberTest::testSleepUntil()
}

static void
f7(modm::fiber::stop_token stoken)
f8(modm::fiber::stop_token stoken)
{
TEST_ASSERT_EQUALS(state++, 0u);
TEST_ASSERT_TRUE(stoken.stop_possible());
Expand All @@ -208,7 +247,7 @@ f7(modm::fiber::stop_token stoken)
void
FiberTest::testStopToken()
{
modm::fiber::Task fiber1(stack1, f7);
modm::fiber::Task fiber1(stack1, f8);
modm::fiber::Task fiber2(stack2, [&](modm::fiber::stop_token stoken)
{
TEST_ASSERT_EQUALS(state++, 1u);
Expand Down

0 comments on commit 1319de9

Please sign in to comment.