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_rwmutex.cpp
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: 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>
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_RWMUTEX_TEST_TASKS_MAX 5
24#define _STK_RWMUTEX_TEST_TIMEOUT 1000
25#define _STK_RWMUTEX_TEST_SHORT_SLEEP 10
26#define _STK_RWMUTEX_TEST_LONG_SLEEP 100
27#ifdef __ARM_ARCH_6M__
28#define _STK_RWMUTEX_STACK_SIZE 128 // ARM Cortex-M0
29#define STK_TASK
30#else
31#define _STK_RWMUTEX_STACK_SIZE 256
32#define STK_TASK static
33#endif
34
35namespace stk {
36namespace test {
37
41namespace rwmutex {
42
43// Test results storage
44static volatile int32_t g_TestResult = 0;
45static volatile int32_t g_SharedCounter = 0;
46static volatile int32_t g_ReaderCount = 0;
47static volatile int32_t g_WriterCount = 0;
48static volatile int32_t g_MaxConcurrent = 0;
49static volatile bool g_TestComplete = false;
50static volatile int32_t g_InstancesDone = 0;
51
52// Kernel
54
55// Test RWMutex
57
64template <EAccessMode _AccessMode>
65class ConcurrentReadersTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
66{
67 uint8_t m_task_id;
68
69public:
70 ConcurrentReadersTask(uint8_t task_id, int32_t) : m_task_id(task_id)
71 {}
72
73private:
74 void Run()
75 {
76 if (m_task_id == 0)
77 {
78 // Verifier: wait for all readers to complete
81
82 int32_t expected = _STK_RWMUTEX_TEST_TASKS_MAX - 1;
83
84 printf("concurrent readers: max=%d (expected %d)\n",
85 (int)g_MaxConcurrent, (int)expected);
86
87 if (g_MaxConcurrent == expected)
88 g_TestResult = 1;
89 }
90 else
91 {
92 // Reader tasks: acquire read lock and track concurrency
93 g_TestRWMutex.ReadLock();
94 {
95 int32_t current = ++g_ReaderCount;
96
97 // Track maximum concurrent readers
98 if (current > g_MaxConcurrent)
99 g_MaxConcurrent = current;
100
102
104 }
105 g_TestRWMutex.ReadUnlock();
106
108 }
109 }
110};
111
117template <EAccessMode _AccessMode>
118class WriterExclusivityTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
119{
120 uint8_t m_task_id;
122
123public:
124 WriterExclusivityTask(uint8_t task_id, int32_t iterations) : m_task_id(task_id), m_iterations(iterations)
125 {}
126
127private:
128 void Run()
129 {
130 int32_t workload = 0;
131
132 for (int32_t i = 0; i < m_iterations; ++i)
133 {
134 g_TestRWMutex.Lock();
135
136 // Critical section - increment shared counter with deliberate race window
137 int32_t temp = g_SharedCounter;
138 if (++workload % 4 == 0)
139 stk::Delay(1);
140 g_SharedCounter = temp + 1;
141
142 g_TestRWMutex.Unlock();
143
144 stk::Yield();
145 }
146
148
149 if (m_task_id == 0)
150 {
153
154 int32_t expected = _STK_RWMUTEX_TEST_TASKS_MAX * m_iterations;
155
156 printf("writer exclusivity: counter=%d (expected %d)\n",
157 (int)g_SharedCounter, (int)expected);
158
159 if (g_SharedCounter == expected)
160 g_TestResult = 1;
161 }
162 }
163};
164
171template <EAccessMode _AccessMode>
172class WriterStarvationTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
173{
174 uint8_t m_task_id;
175
176public:
177 WriterStarvationTask(uint8_t task_id, int32_t) : m_task_id(task_id)
178 {}
179
180private:
181 void Run()
182 {
183 if (m_task_id == 0)
184 {
185 // Verifier
186 while (!g_TestComplete)
188
189 printf("writer starvation: writer_acquired=%d (expected 1)\n",
190 (int)g_SharedCounter);
191
192 if (g_SharedCounter == 1)
193 g_TestResult = 1;
194 }
195 else
196 if ((m_task_id >= 1) && (m_task_id <= 3))
197 {
198 // Readers: flood with read locks until test completes
199 while (!g_TestComplete)
200 {
201 g_TestRWMutex.ReadLock();
202 stk::Delay(1);
203 g_TestRWMutex.ReadUnlock();
204 }
205 }
206 else
207 if (m_task_id == 4)
208 {
209 // Writer: wait briefly then attempt write lock (should not starve)
211
212 int64_t start = GetTimeNowMs();
213 g_TestRWMutex.Lock();
214 int64_t elapsed = GetTimeNowMs() - start;
215
216 // Verify writer acquired within reasonable time (< 200ms)
217 if (elapsed < 200)
218 g_SharedCounter = 1;
219
220 g_TestRWMutex.Unlock();
221
222 g_TestComplete = true;
223 }
224 }
225};
226
233template <EAccessMode _AccessMode>
234class TimedReadLockTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
235{
236 uint8_t m_task_id;
237
238public:
239 TimedReadLockTask(uint8_t task_id, int32_t) : m_task_id(task_id)
240 {}
241
242private:
243 void Run()
244 {
245 if (m_task_id == 1)
246 {
247 // Writer: hold lock for extended period
248 g_TestRWMutex.Lock();
249 g_SharedCounter = 1; // signal task 2
250 stk::Sleep(200);
251 g_TestRWMutex.Unlock();
252 }
253 else
254 if (m_task_id == 2)
255 {
256 // Wait until writer signals it has the lock
257 while (g_SharedCounter == 0)
258 stk::Yield();
259
261
262 // TimedReadLock(50) must time out
263 int64_t start = GetTimeNowMs();
264 bool acquired = g_TestRWMutex.TimedReadLock(50);
265 int64_t elapsed = GetTimeNowMs() - start;
266
267 if (!acquired && elapsed >= 45 && elapsed <= 65)
268 ++g_SharedCounter; // 2: timed out correctly
269
270 if (acquired)
271 g_TestRWMutex.ReadUnlock();
272
273 // Wait for writer to release, then TimedReadLock(100) should succeed
274 stk::Sleep(250);
275
276 if (g_TestRWMutex.TimedReadLock(100))
277 {
278 ++g_SharedCounter; // 3: acquired after release
279 g_TestRWMutex.ReadUnlock();
280 }
281 }
282 else
283 if (m_task_id == 0)
284 {
286
287 printf("timed read-lock: counter=%d (expected 3)\n", (int)g_SharedCounter);
288
289 if (g_SharedCounter == 3)
290 g_TestResult = 1;
291 }
292 }
293};
294
301template <EAccessMode _AccessMode>
302class TimedWriteLockTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
303{
304 uint8_t m_task_id;
305
306public:
307 TimedWriteLockTask(uint8_t task_id, int32_t) : m_task_id(task_id)
308 {}
309
310private:
311 void Run()
312 {
313 if (m_task_id == 1)
314 {
315 // Reader: hold read lock for extended period
316 g_TestRWMutex.ReadLock();
317 g_SharedCounter = 1; // signal task 2
318 stk::Sleep(200);
319 g_TestRWMutex.ReadUnlock();
320 }
321 else
322 if (m_task_id == 2)
323 {
324 // Wait until reader signals it has the lock
325 while (g_SharedCounter == 0)
326 stk::Yield();
327
329
330 // TimedLock(50) must time out
331 int64_t start = GetTimeNowMs();
332 bool acquired = g_TestRWMutex.TimedLock(50);
333 int64_t elapsed = GetTimeNowMs() - start;
334
335 if (!acquired && elapsed >= 45 && elapsed <= 65)
336 ++g_SharedCounter; // 2: timed out correctly
337
338 if (acquired)
339 g_TestRWMutex.Unlock();
340
341 // Wait for reader to release, then TimedLock(100) should succeed
342 stk::Sleep(250);
343
344 if (g_TestRWMutex.TimedLock(100))
345 {
346 ++g_SharedCounter; // 3: acquired after release
347 g_TestRWMutex.Unlock();
348 }
349 }
350 else
351 if (m_task_id == 0)
352 {
354
355 printf("timed write-lock: counter=%d (expected 3)\n", (int)g_SharedCounter);
356
357 if (g_SharedCounter == 3)
358 g_TestResult = 1;
359 }
360 }
361};
362
368template <EAccessMode _AccessMode>
369class TryReadLockWhileWriterTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
370{
371 uint8_t m_task_id;
372
373public:
374 TryReadLockWhileWriterTask(uint8_t task_id, int32_t) : m_task_id(task_id)
375 {}
376
377private:
378 void Run()
379 {
380 if (m_task_id == 1)
381 {
382 // Writer: hold lock for extended period
383 g_TestRWMutex.Lock();
384 g_SharedCounter = 1; // signal task 2
386 g_TestRWMutex.Unlock();
387 }
388 else
389 if (m_task_id == 2)
390 {
391 // Wait until writer signals it has the lock
392 while (g_SharedCounter == 0)
393 stk::Yield();
394
395 // TryReadLock must fail immediately while writer holds lock
396 int64_t start = GetTimeNowMs();
397 bool acquired = g_TestRWMutex.TryReadLock();
398 int64_t elapsed = GetTimeNowMs() - start;
399
400 if (!acquired && elapsed < _STK_RWMUTEX_TEST_SHORT_SLEEP)
401 ++g_SharedCounter; // 2: correctly failed immediately
402
403 if (acquired)
404 g_TestRWMutex.ReadUnlock();
405
406 // Wait for writer to release
408
409 // TryReadLock must succeed after writer releases
410 if (g_TestRWMutex.TryReadLock())
411 {
412 ++g_SharedCounter; // 3: successfully acquired after release
413 g_TestRWMutex.ReadUnlock();
414 }
415 }
416 else
417 if (m_task_id == 0)
418 {
420
421 printf("try-read while writer: counter=%d (expected 3)\n", (int)g_SharedCounter);
422
423 if (g_SharedCounter == 3)
424 g_TestResult = 1;
425 }
426 }
427};
428
435template <EAccessMode _AccessMode>
436class ReadUnlockWakesWriterTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
437{
438 uint8_t m_task_id;
439
440public:
441 ReadUnlockWakesWriterTask(uint8_t task_id, int32_t) : m_task_id(task_id)
442 {}
443
444private:
445 void Run()
446 {
447 if ((m_task_id == 1) || (m_task_id == 2))
448 {
449 // Readers: acquire read lock and hold
450 g_TestRWMutex.ReadLock();
452
453 // Wait until both readers have acquired
454 while (g_ReaderCount < 2)
455 stk::Yield();
456
458
459 // Release one by one
460 if (--g_ReaderCount == 0)
461 g_SharedCounter = 1; // last reader out
462
463 g_TestRWMutex.ReadUnlock();
464 }
465 else
466 if (m_task_id == 3)
467 {
468 // Writer: wait until readers have acquired, then wait for write lock
469 while (g_ReaderCount < 2)
470 stk::Yield();
471
472 int64_t start = GetTimeNowMs();
473 g_TestRWMutex.Lock();
474 int64_t elapsed = GetTimeNowMs() - start;
475
476 // Verify woken quickly after last reader released (< 50ms)
477 if (g_SharedCounter == 1 && elapsed < 50)
478 ++g_SharedCounter; // 2: woken immediately
479
480 g_TestRWMutex.Unlock();
481 }
482 else
483 if (m_task_id == 0)
484 {
486
487 printf("read-unlock wakes writer: counter=%d (expected 2)\n", (int)g_SharedCounter);
488
489 if (g_SharedCounter == 2)
490 g_TestResult = 1;
491 }
492 }
493};
494
501template <EAccessMode _AccessMode>
502class WriterPriorityTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
503{
504 uint8_t m_task_id;
505
506public:
507 WriterPriorityTask(uint8_t task_id, int32_t) : m_task_id(task_id)
508 {}
509
510private:
511 void Run()
512 {
513 if (m_task_id == 1)
514 {
515 // Reader: hold read lock while writer and second reader queue up
516 g_TestRWMutex.ReadLock();
517 g_SharedCounter = 1; // signal reader is holding
518
520
521 g_TestRWMutex.ReadUnlock();
522 }
523 else
524 if (m_task_id == 2)
525 {
526 // Writer: wait until reader 1 signals, then block on write lock
527 while (g_SharedCounter == 0)
528 stk::Yield();
529
531
532 g_TestRWMutex.Lock();
533 g_WriterCount = 1; // writer acquired first after reader 1 released
534 g_TestRWMutex.Unlock();
535 }
536 else
537 if (m_task_id == 3)
538 {
539 // Reader: wait until writer is waiting, then attempt read lock
540 while (g_SharedCounter == 0)
541 stk::Yield();
542
544
545 g_TestRWMutex.ReadLock();
546
547 // If writer preference is enforced, writer should have acquired first
548 if (g_WriterCount == 1)
549 ++g_SharedCounter; // 2: writer got priority
550
551 g_TestRWMutex.ReadUnlock();
552 }
553 else
554 if (m_task_id == 0)
555 {
557
558 printf("writer priority: counter=%d (expected 2)\n", (int)g_SharedCounter);
559
560 if (g_SharedCounter == 2)
561 g_TestResult = 1;
562 }
563 }
564};
565
572template <EAccessMode _AccessMode>
573class ReaderWriterAlternationTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
574{
575 uint8_t m_task_id;
576
577public:
578 ReaderWriterAlternationTask(uint8_t task_id, int32_t) : m_task_id(task_id)
579 {}
580
581private:
582 void Run()
583 {
584 if ((m_task_id >= 1) && (m_task_id <= 3))
585 {
586 // Phase 1: concurrent readers
587 g_TestRWMutex.ReadLock();
588 {
589 int32_t current = ++g_ReaderCount;
590 if (current > g_MaxConcurrent)
591 g_MaxConcurrent = current;
592 stk::Delay(5);
594 }
595 g_TestRWMutex.ReadUnlock();
596
597 // Wait for writer phase
598 while (g_SharedCounter == 0)
600
601 // Phase 3: concurrent readers again
602 g_TestRWMutex.ReadLock();
603 {
605 stk::Delay(5);
607 }
608 g_TestRWMutex.ReadUnlock();
609
611 }
612 else
613 if (m_task_id == 4)
614 {
615 // Phase 2: exclusive writer
617
618 g_TestRWMutex.Lock();
619 g_SharedCounter = 1; // signal phase 2 complete
620 g_TestRWMutex.Unlock();
621
623 }
624 else
625 if (m_task_id == 0)
626 {
629
630 // Verify concurrent readers were present (phase 1 or 3)
631 printf("reader/writer alternation: max_concurrent=%d (expected >= 2)\n",
632 (int)g_MaxConcurrent);
633
634 if (g_MaxConcurrent >= 2)
635 g_TestResult = 1;
636 }
637 }
638};
639
647template <EAccessMode _AccessMode>
648class StressTestTask : public Task<_STK_RWMUTEX_STACK_SIZE, _AccessMode>
649{
650 uint8_t m_task_id;
652
653public:
654 StressTestTask(uint8_t task_id, int32_t iterations) : m_task_id(task_id), m_iterations(iterations)
655 {}
656
657private:
658 void Run()
659 {
660 for (int32_t i = 0; i < m_iterations; ++i)
661 {
662 if ((i % 2) == 0)
663 {
664 // Reader role: read shared counter
665 g_TestRWMutex.ReadLock();
666 volatile int32_t snapshot = g_SharedCounter;
667 (void)snapshot;
668 g_TestRWMutex.ReadUnlock();
669 }
670 else
671 {
672 // Writer role: increment shared counter
673 g_TestRWMutex.Lock();
675 g_TestRWMutex.Unlock();
676 }
677
678 if ((i % 10) == 0)
679 stk::Delay(1);
680 }
681
683
685 {
688
689 // Expected: number of write operations = tasks * (iterations / 2)
690 int32_t expected = _STK_RWMUTEX_TEST_TASKS_MAX * (m_iterations / 2);
691
692 printf("stress test: counter=%d (expected %d)\n",
693 (int)g_SharedCounter, (int)expected);
694
695 if (g_SharedCounter == expected)
696 g_TestResult = 1;
697 }
698 }
699};
700
701// Helper function to reset test state
702static void ResetTestState()
703{
704 g_TestResult = 0;
705 g_SharedCounter = 0;
706 g_ReaderCount = 0;
707 g_WriterCount = 0;
708 g_MaxConcurrent = 0;
709 g_TestComplete = false;
710 g_InstancesDone = 0;
711}
712
713} // namespace rwmutex
714} // namespace test
715} // namespace stk
716
720static bool NeedsExtendedTasks(const char *test_name)
721{
722 return (strcmp(test_name, "TimedReadLock") != 0) &&
723 (strcmp(test_name, "TimedWriteLock") != 0) &&
724 (strcmp(test_name, "TryReadWhileWriter") != 0);
725}
726
730template <class TaskType>
731static int32_t RunTest(const char *test_name, int32_t param = 0)
732{
733 using namespace stk;
734 using namespace stk::test;
735 using namespace stk::test::rwmutex;
736
737 printf("Test: %s\n", test_name);
738
740
741 // Create tasks based on test type
742 STK_TASK TaskType task0(0, param);
743 STK_TASK TaskType task1(1, param);
744 STK_TASK TaskType task2(2, param);
745 TaskType task3(3, param);
746 TaskType task4(4, param);
747
748 g_Kernel.AddTask(&task0);
749 g_Kernel.AddTask(&task1);
750 g_Kernel.AddTask(&task2);
751
752 if (NeedsExtendedTasks(test_name))
753 {
754 g_Kernel.AddTask(&task3);
755 g_Kernel.AddTask(&task4);
756 }
757
758 g_Kernel.Start();
759
761
762 printf("Result: %s\n", result == TestContext::SUCCESS_EXIT_CODE ? "PASS" : "FAIL");
763 printf("--------------\n");
764
765 return result;
766}
767
771int main(int argc, char **argv)
772{
773 (void)argc;
774 (void)argv;
775
776 using namespace stk::test::rwmutex;
777
779
780 int total_failures = 0, total_success = 0;
781
782 printf("--------------\n");
783
784 g_Kernel.Initialize();
785
786#ifndef __ARM_ARCH_6M__
787
788 // Test 1: Multiple readers can acquire ReadLock() concurrently
790 total_failures++;
791 else
792 total_success++;
793
794 // Test 2: Writers get exclusive access; no lost increments under contention
796 total_failures++;
797 else
798 total_success++;
799
800 // Test 3: Writer preference: writers don't starve under reader flood
802 total_failures++;
803 else
804 total_success++;
805
806 // Test 4: TimedReadLock() times out when writer holds; succeeds after release (tasks 0-2 only)
808 total_failures++;
809 else
810 total_success++;
811
812 // Test 5: TimedLock() times out when reader holds; succeeds after release (tasks 0-2 only)
814 total_failures++;
815 else
816 total_success++;
817
818 // Test 6: TryReadLock() fails during write; succeeds after release (tasks 0-2 only)
820 total_failures++;
821 else
822 total_success++;
823
824 // Test 7: Last reader releasing wakes waiting writer immediately
826 total_failures++;
827 else
828 total_success++;
829
830 // Test 8: New readers blocked when writers are waiting (writer preference)
832 total_failures++;
833 else
834 total_success++;
835
836 // Test 9: Alternating read and write phases with concurrent readers
838 total_failures++;
839 else
840 total_success++;
841
842#endif // __ARM_ARCH_6M__
843
844 // Test 10: Stress test mixing readers and writers under full contention
846 total_failures++;
847 else
848 total_success++;
849
850 int32_t final_result = (total_failures == 0 ? TestContext::SUCCESS_EXIT_CODE : TestContext::DEFAULT_FAILURE_EXIT_CODE);
851
852 printf("##############\n");
853 printf("Total tests: %d\n", total_failures + total_success);
854 printf("Failures: %d\n", total_failures);
855
857 return final_result;
858}
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
Implementation of synchronization primitive: stk::sync::RWMutex.
static int32_t RunTest(const char *test_name, int32_t param=0)
#define STK_TASK
int main(int argc, char **argv)
#define _STK_RWMUTEX_TEST_LONG_SLEEP
static int32_t RunTest(const char *test_name, int32_t param=0)
#define _STK_RWMUTEX_TEST_TASKS_MAX
#define _STK_RWMUTEX_TEST_SHORT_SLEEP
static bool NeedsExtendedTasks(const char *test_name)
#define STK_TEST_DECL_ASSERT
Declare assertion redirector in the source file.
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
void Delay(uint32_t ticks)
Delay calling process by busy-waiting until the deadline expires.
Definition stk_helper.h:342
Namespace of the test inventory.
Namespace of RWMutex test.
static volatile int32_t g_SharedCounter
static volatile int32_t g_InstancesDone
static volatile bool g_TestComplete
static sync::RWMutex g_TestRWMutex
static volatile int32_t g_WriterCount
static volatile int32_t g_ReaderCount
static Kernel< KERNEL_DYNAMIC|KERNEL_SYNC, 5, SwitchStrategyRR, PlatformDefault > g_Kernel
static volatile int32_t g_TestResult
static void ResetTestState()
static volatile int32_t g_MaxConcurrent
Concrete implementation of IKernel.
Definition stk.h:83
Task(const Task &)=delete
Reader-Writer Lock synchronization primitive for non-recursive shared and exclusive access.
Tests that multiple readers can acquire ReadLock() simultaneously.
ConcurrentReadersTask(uint8_t task_id, int32_t)
void Run()
Entry point of the user task.
Tests that writer Lock()/Unlock() provides mutual exclusion.
void Run()
Entry point of the user task.
WriterExclusivityTask(uint8_t task_id, int32_t iterations)
Tests writer preference policy: writers don't starve under reader flood.
void Run()
Entry point of the user task.
WriterStarvationTask(uint8_t task_id, int32_t)
Tests TimedReadLock() timeout behavior.
TimedReadLockTask(uint8_t task_id, int32_t)
void Run()
Entry point of the user task.
Tests TimedLock() timeout behavior for writers.
void Run()
Entry point of the user task.
TimedWriteLockTask(uint8_t task_id, int32_t)
Tests TryReadLock() returns false when writer is active; true after release.
void Run()
Entry point of the user task.
TryReadLockWhileWriterTask(uint8_t task_id, int32_t)
Tests that the last reader releasing wakes a waiting writer immediately.
void Run()
Entry point of the user task.
ReadUnlockWakesWriterTask(uint8_t task_id, int32_t)
Tests writer preference policy: new readers are blocked when writers are waiting.
WriterPriorityTask(uint8_t task_id, int32_t)
void Run()
Entry point of the user task.
Tests alternating read and write phases with multiple concurrent readers.
void Run()
Entry point of the user task.
ReaderWriterAlternationTask(uint8_t task_id, int32_t)
Stress test mixing readers and writers under full five-task contention.
void Run()
Entry point of the user task.
StressTestTask(uint8_t task_id, int32_t iterations)
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.