From 46c65e62e4ee01ba19ac2c6eeb3cf0b941d46a16 Mon Sep 17 00:00:00 2001 From: Jacob Hageman Date: Thu, 28 Dec 2023 21:39:26 +0000 Subject: [PATCH] Fix #1432 #1411, RTEMS semaphore return bugs and functional test update --- src/os/inc/osapi-binsem.h | 1 + src/os/inc/osapi-countsem.h | 1 + src/os/rtems/src/os-impl-binsem.c | 4 +- src/os/rtems/src/os-impl-countsem.c | 4 +- src/tests/bin-sem-test/bin-sem-test.c | 364 ++++++++++------------ src/tests/count-sem-test/count-sem-test.c | 334 ++++++++++---------- 6 files changed, 335 insertions(+), 373 deletions(-) diff --git a/src/os/inc/osapi-binsem.h b/src/os/inc/osapi-binsem.h index 6e92980d8..51f849eb0 100644 --- a/src/os/inc/osapi-binsem.h +++ b/src/os/inc/osapi-binsem.h @@ -193,6 +193,7 @@ int32 OS_BinSemGetIdByName(osal_id_t *sem_id, const char *sem_name); * @retval #OS_SUCCESS @copybrief OS_SUCCESS * @retval #OS_ERR_INVALID_ID if the id passed in is not a valid semaphore * @retval #OS_INVALID_POINTER if the bin_prop pointer is null + * @retval #OS_ERR_NOT_IMPLEMENTED @copybrief OS_ERR_NOT_IMPLEMENTED */ int32 OS_BinSemGetInfo(osal_id_t sem_id, OS_bin_sem_prop_t *bin_prop); diff --git a/src/os/inc/osapi-countsem.h b/src/os/inc/osapi-countsem.h index a700b0d8e..2670f5143 100644 --- a/src/os/inc/osapi-countsem.h +++ b/src/os/inc/osapi-countsem.h @@ -176,6 +176,7 @@ int32 OS_CountSemGetIdByName(osal_id_t *sem_id, const char *sem_name); * @retval #OS_SUCCESS @copybrief OS_SUCCESS * @retval #OS_ERR_INVALID_ID if the id passed in is not a valid semaphore * @retval #OS_INVALID_POINTER if the count_prop pointer is null + * @retval #OS_ERR_NOT_IMPLEMENTED @copybrief OS_ERR_NOT_IMPLEMENTED */ int32 OS_CountSemGetInfo(osal_id_t sem_id, OS_count_sem_prop_t *count_prop); diff --git a/src/os/rtems/src/os-impl-binsem.c b/src/os/rtems/src/os-impl-binsem.c index 187d88fa4..971e5b6d6 100644 --- a/src/os/rtems/src/os-impl-binsem.c +++ b/src/os/rtems/src/os-impl-binsem.c @@ -251,7 +251,7 @@ int32 OS_BinSemTimedWait_Impl(const OS_object_token_t *token, uint32 msecs) status = rtems_semaphore_obtain(impl->id, option_set, TimeInTicks); - if (status == RTEMS_TIMEOUT) + if (status == RTEMS_TIMEOUT || (option_set == RTEMS_NO_WAIT && status == RTEMS_UNSATISFIED)) { return OS_SEM_TIMEOUT; } @@ -275,5 +275,5 @@ int32 OS_BinSemTimedWait_Impl(const OS_object_token_t *token, uint32 msecs) int32 OS_BinSemGetInfo_Impl(const OS_object_token_t *token, OS_bin_sem_prop_t *bin_prop) { /* RTEMS has no API for obtaining the current value of a semaphore */ - return OS_SUCCESS; + return OS_ERR_NOT_IMPLEMENTED; } diff --git a/src/os/rtems/src/os-impl-countsem.c b/src/os/rtems/src/os-impl-countsem.c index 979ec365a..7537f06a9 100644 --- a/src/os/rtems/src/os-impl-countsem.c +++ b/src/os/rtems/src/os-impl-countsem.c @@ -216,7 +216,7 @@ int32 OS_CountSemTimedWait_Impl(const OS_object_token_t *token, uint32 msecs) status = rtems_semaphore_obtain(impl->id, option_set, TimeInTicks); - if (status == RTEMS_TIMEOUT) + if (status == RTEMS_TIMEOUT || (option_set == RTEMS_NO_WAIT && status == RTEMS_UNSATISFIED)) { return OS_SEM_TIMEOUT; } @@ -239,5 +239,5 @@ int32 OS_CountSemTimedWait_Impl(const OS_object_token_t *token, uint32 msecs) int32 OS_CountSemGetInfo_Impl(const OS_object_token_t *token, OS_count_sem_prop_t *count_prop) { /* RTEMS does not provide an API to get the value */ - return OS_SUCCESS; + return OS_ERR_NOT_IMPLEMENTED; } diff --git a/src/tests/bin-sem-test/bin-sem-test.c b/src/tests/bin-sem-test/bin-sem-test.c index c601dd9f6..1bb9c9f28 100644 --- a/src/tests/bin-sem-test/bin-sem-test.c +++ b/src/tests/bin-sem-test/bin-sem-test.c @@ -16,170 +16,202 @@ * limitations under the License. ************************************************************************/ -/* -** Binary semaphore Producer/Consumer test -*/ -#include -#include -#include "common_types.h" +/** + * @file Binary semaphore test + */ #include "osapi.h" #include "utassert.h" #include "uttest.h" -#include "utbsp.h" - -/* Define setup and check functions for UT assert */ -void BinSemSetup(void); -void BinSemCheck(void); - -/* Task 1 */ -#define TASK_1_ID 1 -#define TASK_1_STACK_SIZE 1024 -#define TASK_1_PRIORITY 101 -#define TASK_2_STACK_SIZE 1024 -#define TASK_2_PRIORITY 50 - -#define TIMER_ENTRY 0x001 -#define TIMER_EXIT 0x002 -#define TASK_ENTRY 0x003 -#define TASK_EXIT 0x004 - -uint32 task_1_stack[TASK_1_STACK_SIZE]; -osal_id_t task_1_id; -uint32 task_1_failures; -uint32 task_2_stack[TASK_2_STACK_SIZE]; -osal_id_t task_2_id; -uint32 timer_failures; - -osal_id_t bin_sem_id; - -uint32 timer_counter; -osal_id_t timer_id; -uint32 timer_start = 1000; -uint32 timer_interval = 10000; /* 1000 = 1000 hz, 10000 == 100 hz */ -uint32 timer_accuracy; - -int counter = 0; - -/* - * Note that we should not call "printf" or anything - * like that during a timer callback routine (may be ISR context) - * - * On RTEMS even a call to BinSemGetInfo has very ill effects. - */ -void TimerFunction(osal_id_t local_timer_id) + +#define TASK_STACK_SIZE 1024 + +uint32 task_counter[3]; + +void Test_BinSem_Task0(void) { - int32 status; - OS_bin_sem_prop_t bin_sem_prop; + osal_id_t sem_id; + uint8 i; - memset(&bin_sem_prop, 0, sizeof(bin_sem_prop)); + UtAssert_INT32_EQ(OS_BinSemGetIdByName(&sem_id, "Test_Sem"), OS_SUCCESS); - timer_counter++; + for (i = 0; i < 3; i++) + { + UtAssert_INT32_EQ(OS_BinSemTake(sem_id), OS_SUCCESS); + task_counter[0]++; + } +} + +void Test_BinSem_Task1(void) +{ + osal_id_t sem_id; + uint8 i; + + UtAssert_INT32_EQ(OS_BinSemGetIdByName(&sem_id, "Test_Sem"), OS_SUCCESS); - status = OS_BinSemGive(bin_sem_id); - if (status != OS_SUCCESS) + for (i = 0; i < 3; i++) { - ++timer_failures; + UtAssert_INT32_EQ(OS_BinSemTake(sem_id), OS_SUCCESS); + task_counter[1]++; } +} + +void Test_BinSem_Task2(void) +{ + osal_id_t sem_id; + uint8 i; + UtAssert_INT32_EQ(OS_BinSemGetIdByName(&sem_id, "Test_Sem"), OS_SUCCESS); + + for (i = 0; i < 3; i++) { - status = OS_BinSemGetInfo(bin_sem_id, &bin_sem_prop); - if (status != OS_SUCCESS) - { - ++timer_failures; - } - else if (bin_sem_prop.value > 1) - { - ++timer_failures; - } - else if (bin_sem_prop.value < -1) - { - ++timer_failures; - } + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id, 1000), OS_SUCCESS); + task_counter[2]++; } } -void task_1(void) +void Test_BinSem(void) { - uint32 status; - OS_bin_sem_prop_t bin_sem_prop; - int printf_counter = 0; - memset(&bin_sem_prop, 0, sizeof(bin_sem_prop)); + osal_id_t sem_id[2]; + osal_id_t task_id[3]; + char long_name[OS_MAX_API_NAME + 1]; + OS_bin_sem_prop_t sem_prop; + uint32 test_val; + bool get_info_implemented; + + memset(&sem_prop, 0, sizeof(sem_prop)); + memset(task_counter, 0, sizeof(task_counter)); + + /* Invalid id checks */ + UtAssert_INT32_EQ(OS_BinSemGetInfo(OS_OBJECT_ID_UNDEFINED, &sem_prop), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_BinSemFlush(OS_OBJECT_ID_UNDEFINED), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_BinSemGive(OS_OBJECT_ID_UNDEFINED), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_BinSemTake(OS_OBJECT_ID_UNDEFINED), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_BinSemTimedWait(OS_OBJECT_ID_UNDEFINED, 0), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_BinSemDelete(OS_OBJECT_ID_UNDEFINED), OS_ERR_INVALID_ID); + + /* Null checks */ + UtAssert_INT32_EQ(OS_BinSemCreate(NULL, "Test_Sem", 0, 0), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_BinSemCreate(&sem_id[0], NULL, 0, 0), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_BinSemGetInfo(sem_id[0], NULL), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_BinSemGetIdByName(NULL, "Test_Sem"), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_BinSemGetIdByName(&sem_id[0], NULL), OS_INVALID_POINTER); + + /* Name too long */ + memset(long_name, 'a', sizeof(long_name)); + UtAssert_INT32_EQ(OS_BinSemCreate(&sem_id[0], long_name, 0, 0), OS_ERR_NAME_TOO_LONG); + UtAssert_INT32_EQ(OS_BinSemGetIdByName(&sem_id[0], long_name), OS_ERR_NAME_TOO_LONG); + + /* Valid create and name taken */ + UtAssert_INT32_EQ(OS_BinSemCreate(&sem_id[0], "Test_Sem", 0, 0), OS_SUCCESS); + UtAssert_INT32_EQ(OS_BinSemCreate(&sem_id[1], "Test_Sem", 0, 0), OS_ERR_NAME_TAKEN); + + /* Nonzero create */ + UtAssert_INT32_EQ(OS_BinSemCreate(&sem_id[1], "Test_Sem_Nonzero", 1, 0), OS_SUCCESS); + + /* Check get info implementation */ + get_info_implemented = (OS_BinSemGetInfo(sem_id[0], &sem_prop) != OS_ERR_NOT_IMPLEMENTED); + + /* Validate values */ + if (get_info_implemented) + { + UtAssert_INT32_EQ(OS_BinSemGetInfo(sem_id[0], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + UtAssert_INT32_EQ(OS_BinSemGetInfo(sem_id[1], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 1); + } + + /* Poll and wait timeouts on sem initialized to zero */ + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[0], 1), OS_SEM_TIMEOUT); - OS_printf("Starting task 1\n"); + /* Give twice and take and poll to confirm binary nature (second give response unspecified) */ + UtAssert_INT32_EQ(OS_BinSemGive(sem_id[0]), OS_SUCCESS); + OS_BinSemGive(sem_id[0]); + UtAssert_INT32_EQ(OS_BinSemTake(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); - OS_printf("Delay for 1 second before starting\n"); - OS_TaskDelay(1000); + /* Successful poll and timed wait */ + UtAssert_INT32_EQ(OS_BinSemGive(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[0], 0), OS_SUCCESS); + UtAssert_INT32_EQ(OS_BinSemGive(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[0], 1), OS_SUCCESS); - /* if failures occur, do not loop endlessly */ - while (task_1_failures < 20) + /* Successful poll on sem initialized to nonzero */ + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[1], 0), OS_SUCCESS); + + /* Validate zeros */ + if (get_info_implemented) { - status = OS_BinSemTake(bin_sem_id); - if (status != OS_SUCCESS) - { - OS_printf("TASK 1:Error calling OS_BinSemTake\n"); - ++task_1_failures; - OS_TaskDelay(10); - } - else - { - printf_counter++; - counter++; - - if (printf_counter > 100) - { - OS_printf("TASK 1: counter:%d timer_counter:%d\n", (int)counter, (int)timer_counter); - printf_counter = 0; - } - status = OS_BinSemGetInfo(bin_sem_id, &bin_sem_prop); - if (status != OS_SUCCESS) - { - OS_printf("TASK 1:Error calling OS_BinSemGetInfo\n"); - ++task_1_failures; - } - else if (bin_sem_prop.value > 1) - { - OS_printf("Error: Binary sem value > 1 ( in task):%d !\n", (int)bin_sem_prop.value); - ++task_1_failures; - } - else if (bin_sem_prop.value < -1) - { - OS_printf("Error: Binary sem value < -1 ( in task):%d !\n", (int)bin_sem_prop.value); - ++task_1_failures; - } - } + UtAssert_INT32_EQ(OS_BinSemGetInfo(sem_id[0], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + UtAssert_INT32_EQ(OS_BinSemGetInfo(sem_id[1], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + } + else + { + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[1], 0), OS_SEM_TIMEOUT); } -} -void BinSemCheck(void) -{ - uint32 status; - OS_bin_sem_prop_t bin_sem_prop; + /* Start child task, confirm waiting, delete task, and get sem info to confirm still valid (heritage test) */ + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[0], "Task_0", Test_BinSem_Task0, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(100), 0), + OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_INT32_EQ(OS_TaskDelete(task_id[0]), OS_SUCCESS); + UtAssert_UINT32_EQ(task_counter[0], 0); - memset(&bin_sem_prop, 0, sizeof(bin_sem_prop)); + if (get_info_implemented) + { + UtAssert_INT32_EQ(OS_BinSemGetInfo(sem_id[0], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + } + else + { + UtAssert_INT32_EQ(OS_BinSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); + } - /* Delete the task, which should be pending in OS_BinSemTake() */ - status = OS_TaskDelete(task_1_id); - UtAssert_True(status == OS_SUCCESS, "OS_TaskDelete Rc=%d", (int)status); + /* Start 3 child tasks, give and confirm highest priority task increments, flush and confirm all three */ + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[0], "Task_0", Test_BinSem_Task0, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(100), 0), + OS_SUCCESS); + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[1], "Task_1", Test_BinSem_Task1, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(200), 0), + OS_SUCCESS); + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[2], "Task_2", Test_BinSem_Task2, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(250), 0), + OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0] + task_counter[1] + task_counter[2], 0); + UtAssert_INT32_EQ(OS_BinSemGive(sem_id[0]), OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0], 1); + UtAssert_UINT32_EQ(task_counter[1] + task_counter[2], 0); + UtAssert_INT32_EQ(OS_BinSemFlush(sem_id[0]), OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0], 2); + UtAssert_UINT32_EQ(task_counter[1], 1); + UtAssert_UINT32_EQ(task_counter[2], 1); - status = OS_TimerDelete(timer_id); - UtAssert_True(status == OS_SUCCESS, "OS_TimerDelete Rc=%d", (int)status); + /* Give loop for tasks to complete */ + test_val = 4; + while (test_val < 9) + { + test_val++; + UtAssert_INT32_EQ(OS_BinSemGive(sem_id[0]), OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0] + task_counter[1] + task_counter[2], test_val); + } + /* One more give and confirm nothing increments */ + UtAssert_INT32_EQ(OS_BinSemGive(sem_id[0]), OS_SUCCESS); OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0] + task_counter[1] + task_counter[2], test_val); - /* Confirm that the semaphore itself is still operational after task deletion */ - status = OS_BinSemGive(bin_sem_id); - UtAssert_True(status == OS_SUCCESS, "BinSem give Rc=%d", (int)status); - status = OS_BinSemGetInfo(bin_sem_id, &bin_sem_prop); - UtAssert_True(status == OS_SUCCESS, "BinSem value=%d Rc=%d", (int)bin_sem_prop.value, (int)status); - status = OS_BinSemTake(bin_sem_id); - UtAssert_True(status == OS_SUCCESS, "BinSem take Rc=%d", (int)status); - status = OS_BinSemDelete(bin_sem_id); - UtAssert_True(status == OS_SUCCESS, "BinSem delete Rc=%d", (int)status); - - UtAssert_True(counter < timer_counter, "Task counter (%d) < timer counter (%d)", (int)counter, (int)timer_counter); - UtAssert_True(task_1_failures == 0, "Task 1 failures = %u", (unsigned int)task_1_failures); - UtAssert_True(timer_failures == 0, "Timer failures = %u", (unsigned int)timer_failures); + /* Confirm successful delete of zero and nonzero sem */ + UtAssert_INT32_EQ(OS_BinSemDelete(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_BinSemDelete(sem_id[1]), OS_SUCCESS); } void UtTest_Setup(void) @@ -195,63 +227,5 @@ void UtTest_Setup(void) /* * Register the test setup and check routines in UT assert */ - UtTest_Add(BinSemCheck, BinSemSetup, NULL, "BinSemTest"); -} - -void BinSemSetup(void) -{ - uint32 status; - uint32 accuracy = 0; - OS_bin_sem_prop_t bin_sem_prop; - - memset(&bin_sem_prop, 0, sizeof(bin_sem_prop)); - - /* separate task failure counter because ut-assert is not reentrant */ - task_1_failures = 0; - timer_failures = 0; - - /* - ** Create the binary semaphore - */ - status = OS_BinSemCreate(&bin_sem_id, "BinSem1", 1, 0); - UtAssert_True(status == OS_SUCCESS, "BinSem1 create Id=%lx Rc=%d", OS_ObjectIdToInteger(bin_sem_id), (int)status); - - status = OS_BinSemGetInfo(bin_sem_id, &bin_sem_prop); - UtAssert_True(status == OS_SUCCESS, "BinSem1 value=%d Rc=%d", (int)bin_sem_prop.value, (int)status); - - /* - ** Take the semaphore so the value is 0 and the next SemTake call should block - */ - status = OS_BinSemTake(bin_sem_id); - UtAssert_True(status == OS_SUCCESS, "BinSem1 take Rc=%d", (int)status); - status = OS_BinSemGetInfo(bin_sem_id, &bin_sem_prop); - UtAssert_True(status == OS_SUCCESS, "BinSem1 value=%d Rc=%d", (int)bin_sem_prop.value, (int)status); - - /* - ** Create the "consumer" task. - */ - status = OS_TaskCreate(&task_1_id, "Task 1", task_1, OSAL_STACKPTR_C(task_1_stack), sizeof(task_1_stack), - OSAL_PRIORITY_C(TASK_1_PRIORITY), 0); - UtAssert_True(status == OS_SUCCESS, "Task 1 create Id=%lx Rc=%d", OS_ObjectIdToInteger(task_1_id), (int)status); - - /* - ** Create a timer - */ - status = OS_TimerCreate(&timer_id, "Timer 1", &accuracy, &(TimerFunction)); - UtAssert_True(status == OS_SUCCESS, "Timer 1 create Id=%lx Rc=%d", OS_ObjectIdToInteger(timer_id), (int)status); - UtPrintf("Timer Accuracy = %u microseconds \n", (unsigned int)accuracy); - - /* - ** Start the timer - */ - status = OS_TimerSet(timer_id, timer_start, timer_interval); - UtAssert_True(status == OS_SUCCESS, "Timer 1 set Rc=%d", (int)status); - - /* - * Give the task some time to run - */ - while (timer_counter < 1000) - { - OS_TaskDelay(100); - } + UtTest_Add(Test_BinSem, NULL, NULL, "Test_BinSem"); } diff --git a/src/tests/count-sem-test/count-sem-test.c b/src/tests/count-sem-test/count-sem-test.c index 7398a95eb..929ee2a42 100644 --- a/src/tests/count-sem-test/count-sem-test.c +++ b/src/tests/count-sem-test/count-sem-test.c @@ -16,227 +16,213 @@ * limitations under the License. ************************************************************************/ -/* -** Counting Semaphore Test -*/ -#include -#include "common_types.h" +/** + * @file Counting semaphore test + */ #include "osapi.h" #include "utassert.h" #include "uttest.h" -#include "utbsp.h" -/* Define setup and check functions for UT assert */ -void CountSemSetup(void); -void CountSemCheck(void); +#define TASK_STACK_SIZE 1024 -#define TASK_STACK_SIZE 4096 -#define TASK_1_PRIORITY 100 -#define TASK_2_PRIORITY 110 -#define TASK_3_PRIORITY 120 +uint32 task_counter[3]; -uint32 task_1_stack[TASK_STACK_SIZE]; -osal_id_t task_1_id; -uint32 task_1_failures; -uint32 task_1_work; - -uint32 task_2_stack[TASK_STACK_SIZE]; -osal_id_t task_2_id; -uint32 task_2_failures; -uint32 task_2_work; - -uint32 task_3_stack[TASK_STACK_SIZE]; -osal_id_t task_3_id; -uint32 task_3_failures; -uint32 task_3_work; - -osal_id_t count_sem_id; - -void task_1(void) +void Test_CountSem_Task0(void) { - uint32 status; + osal_id_t sem_id; + uint8 i; - OS_printf("Starting task 1\n"); + UtAssert_INT32_EQ(OS_CountSemGetIdByName(&sem_id, "Test_Sem"), OS_SUCCESS); - while (1) + for (i = 0; i < 3; i++) { - OS_TaskDelay(2000); - - OS_printf("TASK 1: Giving the counting semaphore 1\n"); - status = OS_CountSemGive(count_sem_id); - if (status != OS_SUCCESS) - { - ++task_1_failures; - OS_printf("TASK 1: Error calling OS_CountSemGive 1: %d\n", (int)status); - } - else - { - ++task_1_work; - OS_printf("TASK 1: Counting Sem Give 1 complete\n"); - } - - OS_TaskDelay(500); - - OS_printf("TASK 1: Giving the counting semaphore 2\n"); - status = OS_CountSemGive(count_sem_id); - if (status != OS_SUCCESS) - { - ++task_1_failures; - OS_printf("TASK 1: Error calling OS_CountSemGive 2: %d\n", (int)status); - } - else - { - ++task_1_work; - OS_printf("TASK 1: Counting Sem Give 2 complete\n"); - } + UtAssert_INT32_EQ(OS_CountSemTake(sem_id), OS_SUCCESS); + task_counter[0]++; } } -void task_2(void) +void Test_CountSem_Task1(void) { - uint32 status; + osal_id_t sem_id; + uint8 i; - OS_printf("Starting task 2\n"); + UtAssert_INT32_EQ(OS_CountSemGetIdByName(&sem_id, "Test_Sem"), OS_SUCCESS); - while (1) + for (i = 0; i < 3; i++) { - OS_TaskDelay(1000); - - OS_printf("TASK 2: Waiting on the semaphore\n"); - status = OS_CountSemTake(count_sem_id); - if (status != OS_SUCCESS) - { - ++task_2_failures; - OS_printf("TASK 2: Error calling OS_CountSemTake: %d\n", (int)status); - } - else - { - ++task_2_work; - OS_printf("TASK 2: grabbed Counting Sem\n"); - } + UtAssert_INT32_EQ(OS_CountSemTake(sem_id), OS_SUCCESS); + task_counter[1]++; } } -void task_3(void) +void Test_CountSem_Task2(void) { - uint32 status; + osal_id_t sem_id; + uint8 i; - OS_printf("Starting task 3\n"); + UtAssert_INT32_EQ(OS_CountSemGetIdByName(&sem_id, "Test_Sem"), OS_SUCCESS); - while (1) + for (i = 0; i < 3; i++) { - OS_TaskDelay(1000); - - OS_printf("TASK 3: Waiting on the semaphore\n"); - status = OS_CountSemTake(count_sem_id); - if (status != OS_SUCCESS) - { - ++task_3_failures; - OS_printf("TASK 3: Error calling OS_CountSemTake: %d\n", (int)status); - } - else - { - ++task_3_work; - OS_printf("TASK 3: grabbed Counting Sem\n"); - } + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id, 1000), OS_SUCCESS); + task_counter[2]++; } } -void UtTest_Setup(void) +void Test_CountSem(void) { - if (OS_API_Init() != OS_SUCCESS) + + osal_id_t sem_id[2]; + osal_id_t task_id[3]; + char long_name[OS_MAX_API_NAME + 1]; + OS_count_sem_prop_t sem_prop; + uint32 test_val; + bool get_info_implemented; + + memset(&sem_prop, 0, sizeof(sem_prop)); + memset(task_counter, 0, sizeof(task_counter)); + + /* Invalid id checks */ + UtAssert_INT32_EQ(OS_CountSemGetInfo(OS_OBJECT_ID_UNDEFINED, &sem_prop), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_CountSemGive(OS_OBJECT_ID_UNDEFINED), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_CountSemTake(OS_OBJECT_ID_UNDEFINED), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_CountSemTimedWait(OS_OBJECT_ID_UNDEFINED, 0), OS_ERR_INVALID_ID); + UtAssert_INT32_EQ(OS_CountSemDelete(OS_OBJECT_ID_UNDEFINED), OS_ERR_INVALID_ID); + + /* Null checks */ + UtAssert_INT32_EQ(OS_CountSemCreate(NULL, "Test_Sem", 0, 0), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_CountSemCreate(&sem_id[0], NULL, 0, 0), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_CountSemGetInfo(sem_id[0], NULL), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_CountSemGetIdByName(NULL, "Test_Sem"), OS_INVALID_POINTER); + UtAssert_INT32_EQ(OS_CountSemGetIdByName(&sem_id[0], NULL), OS_INVALID_POINTER); + + /* Name too long */ + memset(long_name, 'a', sizeof(long_name)); + UtAssert_INT32_EQ(OS_CountSemCreate(&sem_id[0], long_name, 0, 0), OS_ERR_NAME_TOO_LONG); + UtAssert_INT32_EQ(OS_CountSemGetIdByName(&sem_id[0], long_name), OS_ERR_NAME_TOO_LONG); + + /* Valid create and name taken */ + UtAssert_INT32_EQ(OS_CountSemCreate(&sem_id[0], "Test_Sem", 0, 0), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemCreate(&sem_id[1], "Test_Sem", 0, 0), OS_ERR_NAME_TAKEN); + + /* Nonzero create */ + UtAssert_INT32_EQ(OS_CountSemCreate(&sem_id[1], "Test_Sem_Nonzero", 2, 0), OS_SUCCESS); + + /* Check get info implementation */ + get_info_implemented = (OS_CountSemGetInfo(sem_id[0], &sem_prop) != OS_ERR_NOT_IMPLEMENTED); + + /* Validate values */ + if (get_info_implemented) { - UtAssert_Abort("OS_API_Init() failed"); + UtAssert_INT32_EQ(OS_CountSemGetInfo(sem_id[0], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + UtAssert_INT32_EQ(OS_CountSemGetInfo(sem_id[1], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 2); } - /* the test should call OS_API_Teardown() before exiting */ - UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); - - /* - * Register the test setup and check routines in UT assert - */ - UtTest_Add(CountSemCheck, CountSemSetup, NULL, "CountSemTest"); -} - -void CountSemSetup(void) -{ - uint32 status; - int i; + /* Poll and wait timeouts on sem initialized to zero */ + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[0], 1), OS_SEM_TIMEOUT); - task_1_failures = 0; - task_2_failures = 0; - task_3_failures = 0; - task_1_work = 0; - task_2_work = 0; - task_3_work = 0; + /* Give, take, and poll to confirm counting nature (second give response unspecified) */ + UtAssert_INT32_EQ(OS_CountSemGive(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemGive(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemGive(sem_id[0]), OS_SUCCESS); + if (get_info_implemented) + { + UtAssert_INT32_EQ(OS_CountSemGetInfo(sem_id[0], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 3); + } + UtAssert_INT32_EQ(OS_CountSemTake(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[0], 0), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[0], 1), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); - /* - ** Create the Counting semaphore - */ - status = OS_CountSemCreate(&count_sem_id, "CountSem1", 2, 0); - UtAssert_True(status == OS_SUCCESS, "CountSem1 create Id=%lx Rc=%d", OS_ObjectIdToInteger(count_sem_id), - (int)status); + /* Successful waits on sem initialized to nonzero */ + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[1], 1), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[1], 0), OS_SUCCESS); - /* - ** Take the semaphore so the value is 0 and the next SemTake call should block - */ - for (i = 0; i < 2; i++) + /* Validate zeros */ + if (get_info_implemented) { - status = OS_CountSemTake(count_sem_id); - UtAssert_True(status == OS_SUCCESS, "CountSem1 take Rc=%d", (int)status); + UtAssert_INT32_EQ(OS_CountSemGetInfo(sem_id[0], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + UtAssert_INT32_EQ(OS_CountSemGetInfo(sem_id[1], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + } + else + { + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[1], 0), OS_SEM_TIMEOUT); } - /* - ** Create the tasks - */ - status = OS_TaskCreate(&task_1_id, "Task 1", task_1, OSAL_STACKPTR_C(task_1_stack), sizeof(task_1_stack), - OSAL_PRIORITY_C(TASK_1_PRIORITY), 0); - UtAssert_True(status == OS_SUCCESS, "Task 1 create Id=%lx Rc=%d", OS_ObjectIdToInteger(task_1_id), (int)status); - - status = OS_TaskCreate(&task_2_id, "Task 2", task_2, OSAL_STACKPTR_C(task_2_stack), sizeof(task_2_stack), - OSAL_PRIORITY_C(TASK_2_PRIORITY), 0); - UtAssert_True(status == OS_SUCCESS, "Task 2 create Id=%lx Rc=%d", OS_ObjectIdToInteger(task_2_id), (int)status); + /* Start child task, confirm waiting, delete task, and get sem info to confirm still valid (heritage test) */ + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[0], "Task_0", Test_CountSem_Task0, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(100), 0), + OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_INT32_EQ(OS_TaskDelete(task_id[0]), OS_SUCCESS); + UtAssert_UINT32_EQ(task_counter[0], 0); - status = OS_TaskCreate(&task_3_id, "Task 3", task_3, OSAL_STACKPTR_C(task_3_stack), sizeof(task_3_stack), - OSAL_PRIORITY_C(TASK_3_PRIORITY), 0); - UtAssert_True(status == OS_SUCCESS, "Task 3 create Id=%lx Rc=%d", OS_ObjectIdToInteger(task_3_id), (int)status); + if (get_info_implemented) + { + UtAssert_INT32_EQ(OS_CountSemGetInfo(sem_id[0], &sem_prop), OS_SUCCESS); + UtAssert_INT32_EQ(sem_prop.value, 0); + } + else + { + UtAssert_INT32_EQ(OS_CountSemTimedWait(sem_id[0], 0), OS_SEM_TIMEOUT); + } - /* - * Time-limited execution - */ - while (task_1_work < 10) + /* Start 3 child tasks, give and confirm highest priority task increments, flush and confirm all three */ + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[0], "Task_0", Test_CountSem_Task0, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(100), 0), + OS_SUCCESS); + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[1], "Task_1", Test_CountSem_Task1, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(200), 0), + OS_SUCCESS); + UtAssert_INT32_EQ( + OS_TaskCreate(&task_id[2], "Task_2", Test_CountSem_Task2, NULL, TASK_STACK_SIZE, OSAL_PRIORITY_C(250), 0), + OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0] + task_counter[1] + task_counter[2], 0); + UtAssert_INT32_EQ(OS_CountSemGive(sem_id[0]), OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0], 1); + UtAssert_UINT32_EQ(task_counter[1] + task_counter[2], 0); + + /* Give loop for tasks to complete */ + test_val = 1; + while (test_val < 9) { + test_val++; + UtAssert_INT32_EQ(OS_CountSemGive(sem_id[0]), OS_SUCCESS); OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0] + task_counter[1] + task_counter[2], test_val); } - /* - * Delete the tasks - */ - status = OS_TaskDelete(task_1_id); - UtAssert_True(status == OS_SUCCESS, "Task 1 delete Rc=%d", (int)status); - status = OS_TaskDelete(task_2_id); - UtAssert_True(status == OS_SUCCESS, "Task 2 delete Rc=%d", (int)status); - status = OS_TaskDelete(task_3_id); - UtAssert_True(status == OS_SUCCESS, "Task 3 delete Rc=%d", (int)status); + /* One more give and confirm nothing increments */ + UtAssert_INT32_EQ(OS_CountSemGive(sem_id[0]), OS_SUCCESS); + OS_TaskDelay(100); + UtAssert_UINT32_EQ(task_counter[0] + task_counter[1] + task_counter[2], test_val); + + /* Confirm successful delete of zero and nonzero sem */ + UtAssert_INT32_EQ(OS_CountSemDelete(sem_id[0]), OS_SUCCESS); + UtAssert_INT32_EQ(OS_CountSemDelete(sem_id[1]), OS_SUCCESS); } -void CountSemCheck(void) +void UtTest_Setup(void) { - /* Task 2 and 3 should have both executed */ - UtAssert_True(task_2_work != 0, "Task 2 work counter = %u", (unsigned int)task_2_work); - UtAssert_True(task_3_work != 0, "Task 3 work counter = %u", (unsigned int)task_3_work); + if (OS_API_Init() != OS_SUCCESS) + { + UtAssert_Abort("OS_API_Init() failed"); + } + + /* the test should call OS_API_Teardown() before exiting */ + UtTest_AddTeardown(OS_API_Teardown, "Cleanup"); /* - * The sum of task 2 and task 3 work (consumer) cannot be greater than task 1 (the producer) - * Add a fudge factor of +/- 2 to help avoid false failures due to scheduling + * Register the test setup and check routines in UT assert */ - UtAssert_True((task_2_work + task_3_work) <= (task_1_work + 2), "Task 2+3 work < %u", - (unsigned int)(task_1_work + 2)); - UtAssert_True((task_2_work + task_3_work) >= (task_1_work - 2), "Task 2+3 work > %u", - (unsigned int)(task_1_work - 2)); - - /* None of the tasks should have any failures in their own counters */ - UtAssert_True(task_1_failures == 0, "Task 1 failures = %u", (unsigned int)task_1_failures); - UtAssert_True(task_2_failures == 0, "Task 2 failures = %u", (unsigned int)task_2_failures); - UtAssert_True(task_3_failures == 0, "Task 3 failures = %u", (unsigned int)task_3_failures); + UtTest_Add(Test_CountSem, NULL, NULL, "Test_CountSem"); }