Skip to content

Commit

Permalink
Fix nasa#991, Add count sem timeout test
Browse files Browse the repository at this point in the history
  • Loading branch information
zanzaben committed May 19, 2021
1 parent 706f0de commit 076164e
Showing 1 changed file with 285 additions and 0 deletions.
285 changes: 285 additions & 0 deletions src/tests/count-sem-timeout-test/count-sem-timeout-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
/*
* NASA Docket No. GSC-18,370-1, and identified as "Operating System Abstraction Layer"
*
* Copyright (c) 2019 United States Government as represented by
* the Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
** Counting Semaphore Test with timeouts
*/
#include <stdio.h>
#include "common_types.h"
#include "osapi.h"
#include "utassert.h"
#include "uttest.h"
#include "utbsp.h"

/* Define setup and check functions for UT assert */
void CountSemTimeoutSetup(void);
void CountSemTimeoutCheck(void);

#define TASK_STACK_SIZE 4096
#define TASK_1_PRIORITY 100
#define TASK_2_PRIORITY 110
#define TASK_3_PRIORITY 120

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_2_timeouts;

uint32 task_3_stack[TASK_STACK_SIZE];
osal_id_t task_3_id;
uint32 task_3_failures;
uint32 task_3_work;
uint32 task_3_timeouts;

osal_id_t count_sem_id;

void task_1(void)
{
uint32 status;

OS_printf("Starting task 1\n");

while (1)
{
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(100);

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");
}

OS_TaskDelay(100);

OS_printf("TASK 1: Giving the counting semaphore 3\n");
status = OS_CountSemGive(count_sem_id);
if (status != OS_SUCCESS)
{
++task_1_failures;
OS_printf("TASK 1: Error calling OS_CountSemGive 3: %d\n", (int)status);
}
else
{
++task_1_work;
OS_printf("TASK 1: Counting Sem Give 3 complete\n");
}
}
}

void task_2(void)
{
uint32 status;

OS_printf("Starting task 2\n");

while (1)
{
OS_TaskDelay(2000);
OS_printf("TASK 2: Waiting on the semaphore\n");
status = OS_CountSemTimedWait(count_sem_id, 5000);
if (status == OS_SUCCESS)
{
++task_2_work;
OS_printf("TASK 2: grabbed Counting Sem\n");
}
else if (status == OS_SEM_TIMEOUT)
{
OS_printf("TASK 2: Timeout on OS_CountSemTimedWait\n");
++task_2_timeouts;
}
else
{
++task_2_failures;
OS_printf("TASK 2: Error calling OS_CountSemTake: %d\n", (int)status);
}
}
}

void task_3(void)
{
uint32 status;

OS_printf("Starting task 3\n");

while (1)
{
OS_TaskDelay(250);
OS_printf("TASK 3: Waiting on the semaphore\n");
status = OS_CountSemTimedWait(count_sem_id, 500);
if (status == OS_SUCCESS)
{
++task_3_work;
OS_printf("TASK 3: grabbed Counting Sem\n");
}
else if (status == OS_SEM_TIMEOUT)
{
OS_printf("TASK 3: Timeout on OS_CountSemTimedWait\n");
++task_3_timeouts;
}
else
{
++task_3_failures;
OS_printf("TASK 3: Error calling OS_CountSemTake: %d\n", (int)status);
}
}
}

void UtTest_Setup(void)
{
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");

/*
* Register the test setup and check routines in UT assert
*/
UtTest_Add(CountSemTimeoutCheck, CountSemTimeoutSetup, NULL, "CountSemTest");
}

void CountSemTimeoutSetup(void)
{
uint32 status;
int i;

task_1_failures = 0;
task_2_failures = 0;
task_3_failures = 0;
task_1_work = 0;
task_2_work = 0;
task_3_work = 0;
task_2_timeouts = 0;
task_3_timeouts = 0;

/*
** 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);

/*
** Take the semaphore so the value is 0 and the next SemTake call should block
*/
for (i = 0; i < 2; i++)
{
status = OS_CountSemTake(count_sem_id);
UtAssert_True(status == OS_SUCCESS, "CountSem1 take Rc=%d", (int)status);
}

/*
** 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);

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);

/*
* Time-limited execution
*/
while (task_1_work < 10)
{
OS_TaskDelay(100);
}

/*
* 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);
}

void CountSemTimeoutCheck(void)
{
uint32 task_2_timeouts_expected = 0;
uint32 task_3_timeouts_expected = 8;

/* 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);

/*
* 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
*/
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));

/*
* Task 2 should never timeout
* Task 3 should timeout 8 times, include a fudge factor of 1 to account for potential scheduling
*/
UtAssert_True(task_2_timeouts == task_2_timeouts_expected, "Task 2 timeout counter = %u",
(unsigned int)task_2_timeouts);
UtAssert_True(task_3_timeouts >= (task_3_timeouts_expected - 1), "Task 3 timeout counter %u >= %u",
(unsigned int)task_3_timeouts, (unsigned int)(task_3_timeouts_expected - 1));
UtAssert_True(task_3_timeouts <= (task_3_timeouts_expected + 1), "Task 3 timeout counter %u <= %u",
(unsigned int)task_3_timeouts, (unsigned int)(task_3_timeouts_expected + 1));

/* 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);
}

0 comments on commit 076164e

Please sign in to comment.