SuperTinyKernel™ RTOS 1.05.3
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
test_timerhost.cpp
Go to the documentation of this file.
1/*
2 * SuperTinyKernel™ (STK): Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10#include <stk_config.h>
11#include <stk.h>
12#include <time/stk_time_timer.h>
13#include <assert.h>
14#include <string.h>
15
16#include "stktest_context.h"
17
18using namespace stk;
19using namespace stk::test;
20
22
23#define _STK_TIMER_TEST_TIMEOUT 1000
24#define _STK_TIMER_TEST_SHORT_SLEEP 10
25#define _STK_TIMER_TEST_LONG_SLEEP 100
26#define _STK_TIMER_STACK_SIZE 256 // min stack size required
27#ifdef __ARM_ARCH_6M__
28#define _STK_TIMER_TEST_TASKS_MAX 2
29#define STK_TASK
30#else
31#define _STK_TIMER_TEST_TASKS_MAX 5
32#define STK_TASK static
33#endif
34
35namespace stk {
36namespace test {
37
41namespace timer {
42
43// Test results storage
44static volatile int32_t g_TestResult = 0;
45static volatile int32_t g_SharedCounter = 0;
46static volatile int32_t g_ExpiredCount = 0;
48static volatile int64_t g_ExpiredTime[_STK_TIMER_TEST_TASKS_MAX] = {0};
49
50// Kernel
52
53// TimerHost
55
60{
61 uint8_t m_timer_id;
62
63public:
64 TestTimer(uint8_t timer_id) : m_timer_id(timer_id)
65 {}
66
73};
74
80template <EAccessMode _AccessMode>
81class OneShotTimerTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
82{
83 uint8_t m_task_id;
84
85public:
86 OneShotTimerTask(uint8_t task_id, int32_t) : m_task_id(task_id)
87 {}
88
89private:
90 void Run()
91 {
92 static TestTimer timer(1);
93
94 if (m_task_id == 1)
95 {
96 int64_t start = GetTimeNowMs();
97 g_TimerHost.Start(timer, 50); // 50-tick one-shot
98
99 // Wait until timer fires
100 while (g_ExpiredCount == 0)
102
103 int64_t elapsed = g_ExpiredTime[1] - start;
104
105 if ((g_ExpiredCount == 1) && (elapsed >= 45) && (elapsed <= 65))
106 g_SharedCounter = 1;
107
108 // Wait to confirm it doesn't fire again
110
111 if (g_ExpiredCount == 1 && !timer.IsActive())
112 g_SharedCounter = 2;
113 }
114 else
115 if (m_task_id == 0)
116 {
118
119 printf("one-shot timer: count=%d (expected 1), result=%d (expected 2)\n",
121
122 if (g_SharedCounter == 2)
123 g_TestResult = 1;
124
125 g_TimerHost.Shutdown();
126 }
127 }
128};
129
136template <EAccessMode _AccessMode>
137class PeriodicTimerTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
138{
139 uint8_t m_task_id;
140
141public:
142 PeriodicTimerTask(uint8_t task_id, int32_t) : m_task_id(task_id)
143 {}
144
145private:
146 void Run()
147 {
148 static TestTimer timer(1);
149
150 if (m_task_id == 1)
151 {
152 g_TimerHost.Start(timer, 30, 30); // 30ms initial + 30ms period
153
154 stk::Sleep(150); // let it fire ~5 times
155
156 g_TimerHost.Stop(timer);
157
158 // Stop is asynchronous, therefore wait for a completion
159 int32_t wait = 10;
160 while (timer.IsActive() && wait)
161 {
162 stk::Yield();
163 --wait;
164 }
165
166 // Verify 4-6 firings (150 / 30 ≈ 5)
167 if ((g_ExpiredCount >= 4) && (g_ExpiredCount <= 6) && !timer.IsActive())
168 g_SharedCounter = 1;
169 }
170 else
171 if (m_task_id == 0)
172 {
173 stk::Sleep(150 * 2);
174
175 printf("periodic timer: count=%d (expected 4-6)\n", (int)g_ExpiredCount);
176
177 if (g_SharedCounter == 1)
178 g_TestResult = 1;
179
180 g_TimerHost.Shutdown();
181 }
182 }
183};
184
190template <EAccessMode _AccessMode>
191class MultipleTimersTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
192{
193 uint8_t m_task_id;
194
195public:
196 MultipleTimersTask(uint8_t task_id, int32_t) : m_task_id(task_id)
197 {}
198
199private:
200 void Run()
201 {
202 static TestTimer timer1(1); // 20ms periodic
203 static TestTimer timer2(2); // 35ms periodic
204 static TestTimer timer3(3); // 60ms one-shot
205
206 if (m_task_id == 1)
207 {
208 g_TimerHost.Start(timer1, 20, 20); // ~5 firings in 100ms
209 g_TimerHost.Start(timer2, 35, 35); // ~3 firings in 100ms
210 g_TimerHost.Start(timer3, 60); // 1 firing at 60ms
211
212 stk::Sleep(100);
213
214 g_TimerHost.Stop(timer1);
215 g_TimerHost.Stop(timer2);
216
217 // Verify: timer1 (4-6), timer2 (2-4), timer3 (1)
218 int32_t total = g_ExpiredCount;
219
220 if ((total >= 7) && (total <= 11) && !timer3.IsActive())
221 g_SharedCounter = 1;
222 }
223 else
224 if (m_task_id == 0)
225 {
226 stk::Sleep(150);
227
228 printf("multiple timers: total=%d (expected 7-11)\n", (int)g_ExpiredCount);
229
230 if (g_SharedCounter == 1)
231 g_TestResult = 1;
232
233 g_TimerHost.Shutdown();
234 }
235 }
236};
237
243template <EAccessMode _AccessMode>
244class StopTimerTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
245{
246 uint8_t m_task_id;
247
248public:
249 StopTimerTask(uint8_t task_id, int32_t) : m_task_id(task_id)
250 {}
251
252private:
253 void Run()
254 {
255 static TestTimer timer(1);
256
257 if (m_task_id == 1)
258 {
259 g_TimerHost.Start(timer, 100);
260 stk::Sleep(2); // small delay to ensure Start() processed
261 g_TimerHost.Stop(timer);
262
264
265 if (g_ExpiredCount == 0 && !timer.IsActive())
266 g_SharedCounter = 1;
267 }
268 else
269 if (m_task_id == 0)
270 {
271 stk::Sleep(150);
272
273 printf("stop timer: count=%d (expected 0)\n", (int)g_ExpiredCount);
274
275 if (g_SharedCounter == 1)
276 g_TestResult = 1;
277
278 g_TimerHost.Shutdown();
279 }
280 }
281};
282
289template <EAccessMode _AccessMode>
290class ResetPeriodicTimerTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
291{
292 uint8_t m_task_id;
293
294public:
295 ResetPeriodicTimerTask(uint8_t task_id, int32_t) : m_task_id(task_id)
296 {}
297
298private:
299 void Run()
300 {
301 static TestTimer timer(1);
302
303 if (m_task_id == 1)
304 {
305 g_TimerHost.Start(timer, 40, 40);
306
307 // Wait for first firing
308 while (g_ExpiredCount == 0)
310
311 // Reset: deadline should be now + 40ms
312 int64_t reset_time = GetTimeNowMs();
313 g_TimerHost.Reset(timer);
314
315 // Wait for second firing
316 while (g_ExpiredCount == 1)
318
319 int64_t elapsed = g_ExpiredTime[1] - reset_time;
320
321 g_TimerHost.Stop(timer);
322
323 // Verify second firing occurred ~40ms after Reset()
324 if (g_ExpiredCount == 2 && elapsed >= 35 && elapsed <= 50)
325 g_SharedCounter = 1;
326 }
327 else
328 if (m_task_id == 0)
329 {
330 stk::Sleep(150);
331
332 printf("reset periodic: count=%d (expected 2)\n", (int)g_ExpiredCount);
333
334 if (g_SharedCounter == 1)
335 g_TestResult = 1;
336
337 g_TimerHost.Shutdown();
338 }
339 }
340};
341
348template <EAccessMode _AccessMode>
349class RestartTimerTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
350{
351 uint8_t m_task_id;
352
353public:
354 RestartTimerTask(uint8_t task_id, int32_t) : m_task_id(task_id)
355 {}
356
357private:
358 void Run()
359 {
360 static TestTimer timer(1);
361
362 if (m_task_id == 1)
363 {
364 g_TimerHost.Start(timer, 30, 30); // periodic
365
366 // Wait for first firing
367 while (g_ExpiredCount == 0)
369
370 int32_t count_before_restart = g_ExpiredCount;
371
372 // Restart as one-shot with 50ms delay
373 g_TimerHost.Restart(timer, 50);
374
375 // Restart is asynchronous, wait for command to process
376 stk::Sleep(2);
377
378 int64_t restart_time = GetTimeNowMs();
379
380 // Wait for next firing (count increases beyond count_before_restart)
381 while (g_ExpiredCount <= count_before_restart)
383
384 int64_t elapsed = g_ExpiredTime[1] - restart_time;
385
387
388 // Verify: timer fired after restart, elapsed ~50ms, timer inactive (one-shot)
389 if ((g_ExpiredCount == (count_before_restart + 1)) && (elapsed >= 45) && (elapsed <= 65) && !timer.IsActive())
390 g_SharedCounter = 1;
391 }
392 else
393 if (m_task_id == 0)
394 {
395 stk::Sleep(200);
396
397 printf("restart timer: count=%d (expected 2)\n", (int)g_ExpiredCount);
398
399 if (g_SharedCounter == 1)
400 g_TestResult = 1;
401
402 g_TimerHost.Shutdown();
403 }
404 }
405};
406
412template <EAccessMode _AccessMode>
413class StartOrResetTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
414{
415 uint8_t m_task_id;
416
417public:
418 StartOrResetTask(uint8_t task_id, int32_t) : m_task_id(task_id)
419 {}
420
421private:
422 void Run()
423 {
424 static TestTimer timer(1);
425
426 if (m_task_id == 1)
427 {
428 // Scenario 1: inactive -> starts
429 g_TimerHost.StartOrReset(timer, 40, 40);
430
431 // StartOrReset is asynchronous, wait for command to process
432 int32_t wait = 10;
433 while (!timer.IsActive() && wait)
434 {
435 stk::Yield();
436 --wait;
437 }
438
439 if (!timer.IsActive())
440 {
441 g_SharedCounter = -1; // fail: didn't start
442 return;
443 }
444
445 // Wait for first firing
446 while (g_ExpiredCount == 0)
448
449 // Scenario 2: active periodic -> resets
450 g_TimerHost.StartOrReset(timer, 999, 999); // delay/period ignored for active timer
451
452 // StartOrReset is asynchronous, wait for command to process
453 stk::Sleep(2);
454
455 int64_t reset_time = GetTimeNowMs();
456
457 // Wait for second firing (count increases from 1 to 2)
458 while (g_ExpiredCount == 1)
460
461 int64_t elapsed = g_ExpiredTime[1] - reset_time;
462
463 g_TimerHost.Stop(timer);
464
465 // Verify second firing ~40ms after reset (original period)
466 if ((g_ExpiredCount == 2) && (elapsed >= 35) && (elapsed <= 55))
467 g_SharedCounter = 1;
468 }
469 else
470 if (m_task_id == 0)
471 {
472 stk::Sleep(150);
473
474 printf("start-or-reset: count=%d, result=%d (expected 2, 1)\n",
476
477 if (g_SharedCounter == 1)
478 g_TestResult = 1;
479
480 g_TimerHost.Shutdown();
481 }
482 }
483};
484
491template <EAccessMode _AccessMode>
492class SetPeriodTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
493{
494 uint8_t m_task_id;
495
496public:
497 SetPeriodTask(uint8_t task_id, int32_t) : m_task_id(task_id)
498 {}
499
500private:
501 void Run()
502 {
503 static TestTimer timer(1);
504 int64_t elapsed;
505
506 if (m_task_id == 1)
507 {
508 g_TimerHost.Start(timer, 40, 40);
509
510 // Wait for first firing
511 while (g_ExpiredCount == 0)
513
514 // Change period to 60ms; current deadline unchanged
515 g_TimerHost.SetPeriod(timer, 60);
516
517 // SetPeriod is asynchronous, wait for command to process
518 stk::Sleep(2);
519
520 // Wait for second firing (should occur ~40ms from first, old period)
521 while (g_ExpiredCount == 1)
523
524 int64_t second_time = g_ExpiredTime[1];
525
526 // Wait for third firing (change is still in flight, old period)
527 while (g_ExpiredCount == 2)
529
530 elapsed = g_ExpiredTime[1] - second_time;
531
532 // Verify third firing ~50ms after second (old period)
533 if ((g_ExpiredCount == 3) && (elapsed >= 45) && (elapsed <= 55))
534 g_SharedCounter = 1;
535
536 int64_t third_time = g_ExpiredTime[1];
537
538 // Wait for fourth firing (should occur ~60ms from second, new period)
539 while (g_ExpiredCount == 3)
541
542 elapsed = g_ExpiredTime[1] - third_time;
543
544 g_TimerHost.Stop(timer);
545
546 // Verify third firing ~60ms after second
547 if ((g_ExpiredCount == 4) && (elapsed >= 55) && (elapsed <= 75))
549 }
550 else
551 if (m_task_id == 0)
552 {
553 stk::Sleep(300);
554
555 printf("set-period: count=%d (expected 4)\n", (int)g_ExpiredCount);
556
557 if (g_SharedCounter == 2)
558 g_TestResult = 1;
559
560 g_TimerHost.Shutdown();
561 }
562 }
563};
564
572template <EAccessMode _AccessMode>
573class StressTestTask : public Task<_STK_TIMER_STACK_SIZE, _AccessMode>
574{
575 uint8_t m_task_id;
577
578public:
579 StressTestTask(uint8_t task_id, int32_t iterations) : m_task_id(task_id), m_iterations(iterations)
580 {}
581
582private:
583 void Run()
584 {
585 static TestTimer timer0(0);
586 static TestTimer timer1(1);
587 #if (_STK_TIMER_TEST_TASKS_MAX > 2)
588 static TestTimer timer2(2);
589 static TestTimer timer3(3);
590 static TestTimer timer4(4);
591 #endif
592 static volatile int32_t g_PerTaskCount[5] = {0};
593
594 TestTimer *my_timer = nullptr;
595 switch (m_task_id)
596 {
597 case 0: my_timer = &timer0; break;
598 case 1: my_timer = &timer1; break;
599 #if (_STK_TIMER_TEST_TASKS_MAX > 2)
600 case 2: my_timer = &timer2; break;
601 case 3: my_timer = &timer3; break;
602 case 4: my_timer = &timer4; break;
603 #endif
604 }
605
606 for (int32_t i = 0; i < m_iterations; ++i)
607 {
608 g_LastExpired[m_task_id].Reset();
609
610 // Varying delays: 10 + (task_id * 10) ms -> [10, 20, 30, 40, 50]
611 uint32_t delay = 10 + (m_task_id * 10);
612
613 int32_t before = g_ExpiredCount;
614 g_TimerHost.Start(*my_timer, delay);
615
616 // Wait for this specific timer to fire
617 while (!g_LastExpired[m_task_id].Wait(10)) {}
618
619 int32_t after = g_ExpiredCount;
620
621 // Verify our timer fired (global counter increased)
622 if (after > before)
623 ++g_PerTaskCount[m_task_id];
624
625 g_TimerHost.Stop(*my_timer);
626
627 // Pace to avoid overwhelming command queue
628 if ((i % 5) == 0)
629 stk::Sleep(4);
630 }
631
632 ++g_SharedCounter; // completion count
633
635 {
636 // Last task: wait for all to complete
639
640 // Verify each task's counter
641 bool all_passed = true;
642 for (int32_t t = 0; t < _STK_TIMER_TEST_TASKS_MAX; ++t)
643 {
644 if (g_PerTaskCount[t] != m_iterations)
645 {
646 all_passed = false;
647 break;
648 }
649 }
650
651 printf("stress test: total=%d, per-task counts=[%d,%d,%d,%d,%d] (expected %d each)\n",
652 (int)g_ExpiredCount,
653 (int)g_PerTaskCount[0], (int)g_PerTaskCount[1], (int)g_PerTaskCount[2],
654 (int)g_PerTaskCount[3], (int)g_PerTaskCount[4],
655 (int)m_iterations);
656
657 if (all_passed)
658 g_TestResult = 1;
659
660 g_TimerHost.Shutdown();
661 }
662 }
663};
664
665// Helper function to reset test state
666static void ResetTestState()
667{
668 g_TestResult = 0;
669 g_SharedCounter = 0;
670 g_ExpiredCount = 0;
671
672 for (int32_t i = 0; i < _STK_TIMER_TEST_TASKS_MAX; ++i)
673 g_ExpiredTime[i] = 0;
674
675 for (int32_t i = 0; i < _STK_TIMER_TEST_TASKS_MAX; ++i)
676 g_LastExpired[i].Reset();
677}
678
679} // namespace timer
680} // namespace test
681} // namespace stk
682
683static bool NeedsExtendedTasks(const char *test_name)
684{
685 return (strcmp(test_name, "StressTest") == 0);
686}
687
691template <class TaskType>
692static int32_t RunTest(const char *test_name, int32_t param = 0)
693{
694 using namespace stk;
695 using namespace stk::test;
696 using namespace stk::test::timer;
697
698 printf("Test: %s\n", test_name);
699
701
703
704 // Create tasks based on test type
705 STK_TASK TaskType task0(0, param);
706 STK_TASK TaskType task1(1, param);
707#if (_STK_TIMER_TEST_TASKS_MAX > 2)
708 TaskType task2(2, param);
709 TaskType task3(3, param);
710 TaskType task4(4, param);
711#endif
712
713 g_Kernel.AddTask(&task0);
714 g_Kernel.AddTask(&task1);
715
716#if (_STK_TIMER_TEST_TASKS_MAX > 2)
717 if (NeedsExtendedTasks(test_name))
718 {
719 g_Kernel.AddTask(&task2);
720 g_Kernel.AddTask(&task3);
721 g_Kernel.AddTask(&task4);
722 }
723#endif
724
725 g_Kernel.Start();
726
728
729 printf("Result: %s\n", result == TestContext::SUCCESS_EXIT_CODE ? "PASS" : "FAIL");
730 printf("--------------\n");
731
732 return result;
733}
734
738int main(int argc, char **argv)
739{
740 (void)argc;
741 (void)argv;
742
743 using namespace stk::test::timer;
744
746
747 int total_failures = 0, total_success = 0;
748
749 printf("--------------\n");
750
751 g_Kernel.Initialize();
752
753#ifndef __ARM_ARCH_6M__
754
755 // Test 1: One-shot timer fires exactly once at expected time
757 total_failures++;
758 else
759 total_success++;
760
761 // Test 2: Periodic timer fires repeatedly at regular intervals
763 total_failures++;
764 else
765 total_success++;
766
767 // Test 3: Multiple concurrent timers with different periods fire independently
769 total_failures++;
770 else
771 total_success++;
772
773 // Test 4: Stop() cancels pending timer before it fires
775 total_failures++;
776 else
777 total_success++;
778
779 // Test 5: Reset() reanchors periodic timer's deadline from now
781 total_failures++;
782 else
783 total_success++;
784
785 // Test 6: Restart() atomically stops and re-starts timer
787 total_failures++;
788 else
789 total_success++;
790
791 // Test 7: StartOrReset() starts if inactive, resets if active+periodic
793 total_failures++;
794 else
795 total_success++;
796
797 // Test 8: SetPeriod() changes reload period without affecting current deadline
799 total_failures++;
800 else
801 total_success++;
802
803#endif // __ARM_ARCH_6M__
804
805 // Test 9: Stress test under full five-task contention with varying timer delays
807 total_failures++;
808 else
809 total_success++;
810
811 g_TimerHost.Shutdown();
812
813 int32_t final_result = (total_failures == 0 ? TestContext::SUCCESS_EXIT_CODE : TestContext::DEFAULT_FAILURE_EXIT_CODE);
814
815 printf("##############\n");
816 printf("Total tests: %d\n", total_failures + total_success);
817 printf("Failures: %d\n", total_failures);
818
820 return final_result;
821}
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
Implementation of stk::time::TimerHost, a software timer multiplexer that manages multiple stk::time:...
static int32_t RunTest(const char *test_name, int32_t param=0)
#define STK_TASK
#define STK_TEST_DECL_ASSERT
Declare assertion redirector in the source file.
#define _STK_TIMER_TEST_LONG_SLEEP
int main(int argc, char **argv)
static int32_t RunTest(const char *test_name, int32_t param=0)
#define _STK_TIMER_TEST_SHORT_SLEEP
#define _STK_TIMER_TEST_TASKS_MAX
static bool NeedsExtendedTasks(const char *test_name)
Namespace of STK package.
static int64_t GetTimeNowMs()
Get current time in milliseconds since kernel start.
Definition stk_helper.h:281
void Sleep(uint32_t ticks)
Put calling process into a sleep state.
Definition stk_helper.h:298
void Yield()
Notify scheduler to switch to the next runnable task.
Definition stk_helper.h:331
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:33
Namespace of the test inventory.
Namespace of TimerHost test.
static sync::Event g_LastExpired[5]
static volatile int32_t g_TestResult
static volatile int32_t g_SharedCounter
static time::TimerHost g_TimerHost
static volatile int64_t g_ExpiredTime[5]
static void ResetTestState()
static volatile int32_t g_ExpiredCount
static Kernel< KERNEL_DYNAMIC|KERNEL_SYNC, 5+stk::time::TimerHost::TASK_COUNT, SwitchStrategyRR, PlatformDefault > g_Kernel
Concrete implementation of IKernel.
Definition stk.h:83
Task(const Task &)=delete
Binary synchronization event (signaled / non-signaled) primitive.
Software timer multiplexer that manages multiple Timer instances on top of a small fixed set of kerne...
Abstract base class for a timer managed by TimerHost.
static void ShowTestSuitePrologue()
Show text string as prologue before tests start.
@ DEFAULT_FAILURE_EXIT_CODE
default exit code for exit() to denote failure of the test
@ SUCCESS_EXIT_CODE
exit code for exit() to denote the success of the test
static void ShowTestSuiteEpilogue(int32_t result)
Show text string as epilogue after tests end.
Concrete timer implementation that increments g_ExpiredCount on each expiry.
void OnExpired(time::TimerHost *)
Tests that a one-shot timer fires exactly once at the expected time.
OneShotTimerTask(uint8_t task_id, int32_t)
void Run()
Entry point of the user task.
Tests that a periodic timer fires repeatedly at regular intervals.
PeriodicTimerTask(uint8_t task_id, int32_t)
void Run()
Entry point of the user task.
Tests that multiple concurrent timers with different periods fire independently.
void Run()
Entry point of the user task.
MultipleTimersTask(uint8_t task_id, int32_t)
Tests that Stop() cancels a pending timer before it fires.
StopTimerTask(uint8_t task_id, int32_t)
void Run()
Entry point of the user task.
Tests that Reset() reanchors a periodic timer's deadline from now.
void Run()
Entry point of the user task.
ResetPeriodicTimerTask(uint8_t task_id, int32_t)
Tests that Restart() atomically stops and re-starts a timer.
RestartTimerTask(uint8_t task_id, int32_t)
void Run()
Entry point of the user task.
Tests StartOrReset(): starts if inactive, resets if active+periodic.
void Run()
Entry point of the user task.
StartOrResetTask(uint8_t task_id, int32_t)
Tests SetPeriod(): changes reload period without affecting current deadline.
void Run()
Entry point of the user task.
SetPeriodTask(uint8_t task_id, int32_t)
Stress test of TimerHost under full five-task contention.
StressTestTask(uint8_t task_id, int32_t iterations)
void Run()
Entry point of the user task.