Add Atomthreads RTOS source files.

This commit is contained in:
Kelvin Lawson
2010-01-14 01:53:45 +00:00
parent 8521dcfe06
commit 6d599c6729
63 changed files with 16629 additions and 0 deletions

60
tests/atomtests.h Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_TESTS_H
#define __ATOM_TESTS_H
/* Include Atomthreads kernel API */
#include "atom.h"
/* Prerequisite include for ATOMLOG() macro (via printf) */
#include <stdio.h>
/* Logger macro for viewing test results */
#define ATOMLOG printf_P
/*
* String location macro: for platforms which need to place strings in
* alternative locations, e.g. on avr-gcc strings can be placed in
* program space, saving SRAM. On most platforms this can expand to
* empty.
*/
#define _STR(x) PSTR(x)
/* Default thread stack size (in bytes) */
#define TEST_THREAD_STACK_SIZE 128
/* Default thread priority */
#define TEST_THREAD_PRIO 16
/* API for starting each test */
extern uint32_t test_start (void);
#endif /* __ATOM_TESTS_H */

120
tests/kern1.c Normal file
View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_TCB tcb1;
static uint8_t test_thread_stack[TEST_THREAD_STACK_SIZE];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start kernel test.
*
* This tests the handling of bad parameters within the public kernel APIs.
*
* Other than during initialisation, the only API that takes parameters
* which require checking (and that application code might call) is the
* thread create API.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* atomThreadCreate: Pass a bad TCB pointer */
if (atomThreadCreate (NULL, TEST_THREAD_PRIO, test_thread_func, 0,
&test_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Bad TCB check\n"));
failures++;
}
/* atomThreadCreate: Pass a bad entry point */
if (atomThreadCreate (&tcb1, TEST_THREAD_PRIO, NULL, 0,
&test_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Bad entry check\n"));
failures++;
}
/* atomThreadCreate: Pass a bad stack pointer */
if (atomThreadCreate (&tcb1, TEST_THREAD_PRIO, test_thread_func, 0,
NULL) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Bad stack ptr check\n"));
failures++;
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

198
tests/kern2.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
/**
* \b test_start
*
* Start kernel test.
*
* This is a basic test of the thread context-switch functionality. It
* creates twenty local (byte) variables and schedules the thread out
* for one second. If context-switch save/restore is not implemented
* correctly, you might expect one or more of these local variables to
* be corrupted by the time the thread is scheduled back in.
*
* Note that this is a fairly unsophisticated test, and a lot depends on
* how the compiler deals with the variables, as well as what code is
* executed while the thread is scheduled out. It should flag up any
* major problems with the context-switch, however.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint8_t one = 1;
uint8_t two = 2;
uint8_t three = 3;
uint8_t four = 4;
uint8_t five = 5;
uint8_t six = 6;
uint8_t seven = 7;
uint8_t eight = 8;
uint8_t nine = 9;
uint8_t ten = 10;
uint8_t eleven = 11;
uint8_t twelve = 12;
uint8_t thirteen = 13;
uint8_t fourteen = 14;
uint8_t fifteen = 15;
uint8_t sixteen = 16;
uint8_t seventeen = 17;
uint8_t eighteen = 18;
uint8_t nineteen = 19;
uint8_t twenty = 20;
/* Default to zero failures */
failures = 0;
/* Sleep for one second */
atomTimerDelay(SYSTEM_TICKS_PER_SEC);
/* Check all variables contain expected values */
if (one != 1)
{
ATOMLOG (_STR("1(%d)\n"), one);
failures++;
}
if (two != 2)
{
ATOMLOG (_STR("2(%d)\n"), two);
failures++;
}
if (three != 3)
{
ATOMLOG (_STR("3(%d)\n"), three);
failures++;
}
if (four != 4)
{
ATOMLOG (_STR("4(%d)\n"), four);
failures++;
}
if (five != 5)
{
ATOMLOG (_STR("5(%d)\n"), five);
failures++;
}
if (six != 6)
{
ATOMLOG (_STR("6(%d)\n"), six);
failures++;
}
if (seven != 7)
{
ATOMLOG (_STR("7(%d)\n"), seven);
failures++;
}
if (eight != 8)
{
ATOMLOG (_STR("8(%d)\n"), eight);
failures++;
}
if (nine != 9)
{
ATOMLOG (_STR("9(%d)\n"), nine);
failures++;
}
if (ten != 10)
{
ATOMLOG (_STR("10(%d)\n"), ten);
failures++;
}
if (eleven != 11)
{
ATOMLOG (_STR("11(%d)\n"), eleven);
failures++;
}
if (twelve != 12)
{
ATOMLOG (_STR("12(%d)\n"), twelve);
failures++;
}
if (thirteen != 13)
{
ATOMLOG (_STR("13(%d)\n"), thirteen);
failures++;
}
if (fourteen != 14)
{
ATOMLOG (_STR("14(%d)\n"), fourteen);
failures++;
}
if (fifteen != 15)
{
ATOMLOG (_STR("15(%d)\n"), fifteen);
failures++;
}
if (sixteen != 16)
{
ATOMLOG (_STR("16(%d)\n"), sixteen);
failures++;
}
if (seventeen != 17)
{
ATOMLOG (_STR("17(%d)\n"), seventeen);
failures++;
}
if (eighteen != 18)
{
ATOMLOG (_STR("18(%d)\n"), eighteen);
failures++;
}
if (nineteen != 19)
{
ATOMLOG (_STR("19(%d)\n"), nineteen);
failures++;
}
if (twenty != 20)
{
ATOMLOG (_STR("20(%d)\n"), twenty);
failures++;
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}

213
tests/kern3.c Normal file
View File

@@ -0,0 +1,213 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_TCB tcb1, tcb2;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test global data (one per thread) */
static volatile int running_flag[2];
static volatile int sleep_request[2];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start kernel test.
*
* This tests the scheduling of threads at different priorities, and
* preemption of lower priority threads by higher priority threads.
*
* Much of this functionality is already tested implicitly by the
* semaphore, mutex tests etc but we repeat it here within the kernel
* tests for completeness.
*
* Two threads are created at different priorities, with each thread
* setting a running flag whenever it runs. We check that when the
* higher priority thread is ready to run, only the higher priority
* thread's running flag is set (even though the lower priority
* thread should also be setting it at this time). This checks that
* the scheduler is correctly prioritising thread execution.
*
* The test also exercises preemption, by disabling setting of the
* running flag in the higher priority thread for a period. During
* this time the higher priority thread repeatedly sleeps for one
* system tick then wakes up to check the sleep-request flag again.
* Every time the higher priority thread wakes up, it has preempted
* the lower priority thread (which is always running). By ensuring
* that the higher priority thread is able to start running again
* after one of these periods (through checking the running flag)
* we prove that the preemption has worked.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Initialise global data */
running_flag[0] = running_flag[1] = FALSE;
sleep_request[0] = sleep_request[1] = FALSE;
/* Create low priority thread */
if (atomThreadCreate (&tcb1, 253, test_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
ATOMLOG (_STR("Bad thread create\n"));
failures++;
}
/* Create high priority thread */
else if (atomThreadCreate (&tcb2, 252, test_thread_func, 1,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
ATOMLOG (_STR("Bad thread create\n"));
failures++;
}
/* Repeat test a few times */
for (i = 0; i < 8; i++)
{
/* Make the higher priority thread sleep */
sleep_request[1] = TRUE;
/* Sleep a little to make sure the thread sees the sleep request */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Reset the running flag for both threads */
running_flag[0] = running_flag[1] = FALSE;
/* Sleep a little to give any running threads time to set their flag */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check only the low priority thread has run since we reset the flags */
if ((running_flag[0] != TRUE) || (running_flag[1] != FALSE))
{
ATOMLOG (_STR("Lo%d %d/%d\n"), i, running_flag[0], running_flag[1]);
failures++;
break;
}
else
{
/*
* We have confirmed that only the ready thread has been running.
* Now check that if we wake up the high priority thread, the
* low priority one stops running and only the high priority one
* does.
*/
/* Tell the higher priority thread to stop sleeping */
sleep_request[1] = FALSE;
/* Reset the running flag for both threads */
running_flag[0] = running_flag[1] = FALSE;
/* Sleep a little to give any running threads time to set their flag */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check only the high priority thread has run since we reset the flags */
if ((running_flag[1] != TRUE) || (running_flag[0] != FALSE))
{
ATOMLOG (_STR("Hi%d/%d\n"), running_flag[0], running_flag[1]);
failures++;
break;
}
else
{
/*
* We have confirmed that the high priority thread has preempted the
* low priority thread, and remain running while never scheduling
* the lower one back in.
*/
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Thread ID (0 = low prio, 1 = high prio)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
int thread_id;
/* Pull out thread ID */
thread_id = (int)data;
/* Run forever */
while (1)
{
/* If this thread is requested to sleep, sleep until told to stop */
if (sleep_request[thread_id])
{
atomTimerDelay (1);
}
else
{
/* Otherwise set running flag for this thread */
running_flag[thread_id] = TRUE;
}
}
}

241
tests/kern4.c Normal file
View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_TCB tcb1, tcb2, tcb3, tcb4;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test4_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test global data (one per thread) */
static uint32_t volatile last_time;
static int volatile last_thread_id;
static volatile int switch_cnt;
static uint32_t volatile failure_cnt[4];
static int volatile test_started;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start kernel test.
*
* This tests the round-robin timeslicing of same priority threads.
*
* Four threads are created (over and above the main test thread).
* The main test thread sleeps for the duration of the entire test.
* While the test is ongoing, all four threads are running
* continuously at the same priority. They each check that whenever
* the system tick (atomTimeGet()) changes, it has moved on 1 tick
* since the last time the tick was checked, and that the previous
* thread is the one created before itself. In the case of the first
* thread created, the previous thread should be the last thread
* created. This proves that on every tick the four threads get a
* schedule timeslice equally, and in the same order throughout the
* duration of the test.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* Initialise global data */
last_time = 0;
last_thread_id = -1;
failure_cnt[0] = failure_cnt[1] = failure_cnt[2] = failure_cnt[3] = 0;
/* Set test as not started until all threads are ready to go */
test_started = FALSE;
/*
* Create all four threads at the same priority as each other.
* They are given a lower priority than this thread, however,
* to ensure that once this thread wakes up to stop the test it
* can do so without confusing the scheduling tests by having
* a spell in which this thread was run.
*/
if (atomThreadCreate (&tcb1, TEST_THREAD_PRIO + 1, test_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
ATOMLOG (_STR("Bad thread create\n"));
failures++;
}
else if (atomThreadCreate (&tcb2, TEST_THREAD_PRIO + 1, test_thread_func, 1,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
ATOMLOG (_STR("Bad thread create\n"));
failures++;
}
else if (atomThreadCreate (&tcb3, TEST_THREAD_PRIO + 1, test_thread_func, 2,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
ATOMLOG (_STR("Bad thread create\n"));
failures++;
}
else if (atomThreadCreate (&tcb4, TEST_THREAD_PRIO + 1, test_thread_func, 3,
&test4_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
ATOMLOG (_STR("Bad thread create\n"));
failures++;
}
/* Start the test */
test_started = TRUE;
/* Sleep for 5 seconds during test */
atomTimerDelay (5 * SYSTEM_TICKS_PER_SEC);
/* Stop the test */
test_started = FALSE;
/* Sleep for tests to complete */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Count any failures from test threads */
failures += failure_cnt[0] + failure_cnt[1] + failure_cnt[2] + failure_cnt[3];
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Thread ID (0 to 3)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
int thread_id, expected_thread;
int time_error, thread_error;
uint32_t new_time;
CRITICAL_STORE;
/* Pull out thread ID */
thread_id = (int)data;
/* Run forever */
while (1)
{
/* Check if test is currently in operation */
if (test_started)
{
/*
* If the system time has ticked over, check that the currently
* running thread is not the one that was running last tick.
*/
/* Default to no error this time */
time_error = thread_error = FALSE;
/* Do the whole operation with interrupts locked out */
CRITICAL_START();
/* Check if time has ticked over */
new_time = atomTimeGet();
/* Only perform the check if this is not the first thread to run */
if ((last_time != 0) && (last_thread_id != -1))
{
/* Check if the time has ticked over */
if (new_time != last_time)
{
/* Check time only ticked over by 1 */
if ((new_time - last_time) != 1)
{
time_error = 1;
}
/*
* We are expecting the previous thread to be our thread_id
* minus one.
*/
expected_thread = thread_id - 1;
if (expected_thread == -1)
{
expected_thread = 3;
}
/* Check that the last thread was the expected one */
if (last_thread_id != expected_thread)
{
thread_error = TRUE;
}
/* Increment the switch count */
switch_cnt++;
}
}
/* Store the currently-running thread as the last-running */
last_thread_id = thread_id;
last_time = new_time;
/* Finished with the interrupt lockout */
CRITICAL_END();
/* If we got an error above, increment the total failure count */
if (test_started && (thread_error || time_error))
{
failure_cnt[thread_id]++;
ATOMLOG(_STR("T%d\n"), thread_id);
}
}
}
}

331
tests/mutex1.c Normal file
View File

@@ -0,0 +1,331 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atommutex.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_TCB tcb1, tcb2;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test result tracking */
static volatile int g_result;
/* Forward declarations */
static void test1_thread_func (uint32_t data);
static void test2_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* This test exercises the mutex creation and deletion APIs, including
* waking threads blocking on a mutex if the mutex is deleted.
* Deletion wakeups are tested twice: once for a thread which is blocking
* with a timeout and once for a thread which is blocking with no timeout.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint32_t i;
/* Default to zero failures */
failures = 0;
/* Test creation and deletion of mutexes: good values */
for (i = 0; i < 1000; i++)
{
if (atomMutexCreate (&mutex1) == ATOM_OK)
{
if (atomMutexDelete (&mutex1) == ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Error deleting mutex\n"));
failures++;
break;
}
}
else
{
/* Fail */
ATOMLOG (_STR("Error creating mutex\n"));
failures++;
break;
}
}
/* Test creation and deletion of mutexes: creation checks */
if (atomMutexCreate (NULL) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad mutex creation checks\n"));
failures++;
}
/* Test creation and deletion of mutexes: deletion checks */
if (atomMutexDelete (NULL) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad mutex deletion checks\n"));
failures++;
}
/* Test wakeup of threads on mutex deletion (thread blocking with no timeout) */
g_result = 0;
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test mutex\n"));
failures++;
}
/* Take the mutex so that the test thread will block */
else if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex\n"));
failures++;
}
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test1_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
else
{
/*
* We have created a mutex and taken ownership ourselves. We
* want to see that the other thread is woken up if its mutex
* is deleted. This is indicated through g_result being set.
*/
/* Wait for the other thread to start blocking on mutex1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on mutex1 now, delete mutex1 */
if (atomMutexDelete(&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Failed mutex1 delete\n"));
failures++;
}
else
{
/* Mutex1 deleted. The thread should now wake up and set g_result. */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
if (g_result == 0)
{
ATOMLOG (_STR("Notify fail\n"));
failures++;
}
else
{
/* Success */
}
}
}
}
/* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */
g_result = 0;
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test mutex\n"));
failures++;
}
/* Take the mutex so that the test thread will block */
else if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex\n"));
failures++;
}
else if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test2_thread_func, 0,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
else
{
/*
* We have created a mutex and taken ownership ourselves. We
* want to see that the other thread is woken up if its mutex
* is deleted. This is indicated through g_result being set.
*/
/* Wait for the other thread to start blocking on mutex1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on mutex1 now, delete mutex1 */
if (atomMutexDelete(&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Failed mutex1 delete\n"));
failures++;
}
else
{
/* Mutex1 deleted. The thread should now wake up and set g_result. */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
if (g_result == 0)
{
ATOMLOG (_STR("Notify fail\n"));
failures++;
}
else
{
/* Success */
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test1_thread_func
*
* Entry point for test thread 1.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test1_thread_func (uint32_t data)
{
uint8_t status;
/*
* Wait on mutex1 with no timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomMutexGet(&mutex1, 0);
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set g_result to notify success */
g_result = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}
/**
* \b test2_thread_func
*
* Entry point for test thread 2.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test2_thread_func (uint32_t data)
{
uint8_t status;
/*
* Wait on mutex1 with timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomMutexGet(&mutex1, (5 * SYSTEM_TICKS_PER_SEC));
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test2 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set g_result to notify success */
g_result = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

299
tests/mutex2.c Normal file
View File

@@ -0,0 +1,299 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atommutex.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test OS objects */
static ATOM_MUTEX mutex1, mutex2;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test result tracking */
static volatile int g_result, g_owned;
/* Forward declarations */
static void testCallback (POINTER cb_data);
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* This test exercises the atomMutexGet() and atomMutexPut() APIs including
* forcing the various error indications which can be returned from the
* APIs to ensure that handling for these corner cases have been correctly
* implemented.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint8_t status;
ATOM_TIMER timer_cb;
int count;
/* Default to zero failures */
failures = 0;
/* Test parameter checks */
if (atomMutexGet (NULL, 0) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Get param failed\n"));
failures++;
}
if (atomMutexPut (NULL) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Put param failed\n"));
failures++;
}
/* Test atomMutexGet() can not be called from interrupt context */
g_result = 0;
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test mutex1\n"));
failures++;
}
else
{
/* Fill out the timer callback request structure */
timer_cb.cb_func = testCallback;
timer_cb.cb_data = NULL;
timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;
/* Request the timer callback to run in one second */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("Error registering timer\n"));
failures++;
}
/* Wait two seconds for g_result to be set indicating success */
else
{
atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC);
if (g_result != 1)
{
ATOMLOG (_STR("Context check failed\n"));
failures++;
}
}
/* Delete the test mutex */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Mutex1 delete failed\n"));
failures++;
}
}
/* Create mutex1 which will be owned by us */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test mutex 1\n"));
failures++;
}
/* Create mutex2 which will be owned by another thread */
else if (atomMutexCreate (&mutex2) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test mutex 2\n"));
failures++;
}
/* Create a test thread, the sole purpose of which is to own mutex2 */
g_owned = 0;
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
/* Sleep until the test thread owns mutex2 */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
if (g_owned == 0)
{
ATOMLOG (_STR("Thread own fail\n"));
failures++;
}
/* Test wait on mutex with timeout - should timeout while owned by another thread */
if ((status = atomMutexGet (&mutex2, SYSTEM_TICKS_PER_SEC)) != ATOM_TIMEOUT)
{
ATOMLOG (_STR("Get %d\n"), status);
failures++;
}
else
{
/* Success */
}
/* Test wait on mutex with no blocking - should return that owned by another thread */
if ((status = atomMutexGet (&mutex2, -1)) != ATOM_WOULDBLOCK)
{
ATOMLOG (_STR("Wouldblock err %d\n"), status);
failures++;
}
/* Test wait on mutex with no blocking when mutex is available */
if (atomMutexGet (&mutex1, -1) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex1\n"));
failures++;
}
else
{
/* Relinquish ownership of mutex1 */
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error posting mutex\n"));
failures++;
}
}
/* Test for lock count overflows with too many gets */
count = 255;
while (count--)
{
if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error getting mutex1\n"));
failures++;
break;
}
}
/* The lock count should overflow this time */
if (atomMutexGet (&mutex1, 0) != ATOM_ERR_OVF)
{
ATOMLOG (_STR("Error tracking overflow\n"));
failures++;
}
else
{
/* Success */
}
/* Delete the test mutexes */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error deleting mutex1\n"));
failures++;
}
if (atomMutexDelete (&mutex2) != ATOM_OK)
{
ATOMLOG (_STR("Error deleting mutex2\n"));
failures++;
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Attempt an atomMutexGet() on mutex1 from interrupt context.
* Should receive an ATOM_ERR_CONTEXT error. Sets g_result if passes.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
/* Check the return value from atomMutexGet() */
if (atomMutexGet(&mutex1, 0) == ATOM_ERR_CONTEXT)
{
/* Received the error we expected, set g_result to notify success */
g_result = 1;
}
else
{
/* Did not get expected error, don't set g_result signifying fail */
}
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
/*
* Take mutex2 so that main thread can test mutex APIs on a mutex
* which it does not own.
*/
status = atomMutexGet(&mutex2, 0);
if (status != ATOM_OK)
{
ATOMLOG (_STR("Mutex get (%d)\n"), status);
}
else
{
/* We took ownership of mutex2, set g_owned to notify success */
g_owned = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

263
tests/mutex3.c Normal file
View File

@@ -0,0 +1,263 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atommutex.h"
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_TCB tcb1, tcb2, tcb3, tcb4;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test4_thread_stack[TEST_THREAD_STACK_SIZE];
/* Data updated by threads */
static volatile uint8_t wake_cnt;
static volatile uint8_t wake_order[4];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* With multiple threads blocking on a single mutex, this test confirms that
* they are woken in order when the mutex is released. The correct order for
* waking is that the higher priority threads are woken first, followed by the
* lower priority threads. Where multiple threads of the same priority are
* waiting, the threads are woken in FIFO order (the order in which they started
* waiting on the mutex).
*
* To test this we create four threads which all wait on a single mutex.
* One pair of threads are running at high priority, with the other pair at a
* lower priority:
*
* Thread 1: low prio thread A
* Thread 2: low prio thread B
* Thread 3: high prio thread A
* Thread 4: high prio thread B
*
* The threads are forced to start blocking on the same mutex in the
* above order.
*
* We expect to see them woken up in the following order:
* 3, 4, 1, 2
*
* This proves the multiple blocking thread ordering in terms of both
* the priority-queueing and same-priority-FIFO-queueing.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* Create mutex */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test mutex 1\n"));
failures++;
}
/* Take ownership of the mutex so all threads will block to begin with */
else if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Get error\n"));
failures++;
}
/* Start the threads */
else
{
/* Create Thread 1 (lower priority thread A) */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO+1, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the mutex */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 2 (lower priority thread B) */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO+1, test_thread_func, 2,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the mutex */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 3 (higher priority thread A) */
if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 3,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the mutex */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 4 (higher priority thread B) */
if (atomThreadCreate(&tcb4, TEST_THREAD_PRIO, test_thread_func, 4,
&test4_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the mutex */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* All four threads will now be blocking on mutex1 */
/*
* Initialise wake count, used by threads to determine
* what order they were woken in.
*/
wake_cnt = 0;
/*
* Release the mutex. This will wake up one of the threads blocking
* on it. That thread will take ownership of the mutex, and note the
* order at which it was woken, before releasing the mutex. This in
* turn will wake up the next thread blocking on the mutex until all
* four test threads have taken and released the mutex, noting their
* wake order.
*/
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Post fail\n"));
failures++;
}
/* Sleep to give all four threads time to complete */
atomTimerDelay (SYSTEM_TICKS_PER_SEC / 4);
/* All four threads now woken up, check they woke in correct order */
if ((wake_order[0] != 3) && (wake_order[1] != 4)
&& (wake_order[2] != 1) && (wake_order[3] != 2))
{
ATOMLOG (_STR("Bad order %d,%d,%d,%d\n"),
wake_order[0], wake_order[1], wake_order[2], wake_order[3]);
failures++;
}
/* Delete mutex, test finished */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread. The same thread entry point is used for all
* four test threads, with the thread number/ID (1-4) passed as the entry
* point parameter.
*
* @param[in] data Thread number (1,2,3,4)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t thread_id;
/* Thread ID is passed through the function parameter */
thread_id = (uint8_t)data;
/*
* Wait for mutex1 to be posted. At creation of all test threads the mutex
* is owned by the parent thread, so all four threads will block here.
*/
if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Get fail\n"));
}
else
{
/*
* Store our thread ID in the array using the current
* wake_cnt order. The threads are holding ownership
* of a mutex here, which provides protection for this
* global data.
*/
wake_order[wake_cnt++] = thread_id;
/* Release the mutex so that the next thread wakes up */
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Put fail\n"));
}
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

266
tests/mutex4.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atommutex.h"
#include "atomsem.h"
/* Number of test loops for stress-test */
#define NUM_TEST_LOOPS 10000
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_SEM sem1;
static ATOM_TCB tcb1, tcb2, tcb3, tcb4;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test4_thread_stack[TEST_THREAD_STACK_SIZE];
/*
* Global failure count (can be updated by test threads but is
* protected by an interrupt lockout).
*/
static volatile int g_failures;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* Stress-tests mutex Get and Put operations. Four threads are created which are
* continually Getting and Putting the same mutex, with no time delays between
* each Get/Put.
*
* @retval Number of g_failures
*/
uint32_t test_start (void)
{
CRITICAL_STORE;
int finish_cnt;
/* Default to zero g_failures */
g_failures = 0;
/* Create mutex to stress */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating mutex\n"));
g_failures++;
}
/* Create sem to receive thread-finished notification */
else if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating sem\n"));
g_failures++;
}
else
{
/* Take ownership of the mutex to ensure all threads wait for now */
if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex\n"));
g_failures++;
}
/* Create Thread 1 */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 2 */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 2,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 3 */
if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 3,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 4 */
if (atomThreadCreate(&tcb4, TEST_THREAD_PRIO, test_thread_func, 4,
&test4_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Release ownership of the mutex to kick the threads off */
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error putting mutex\n"));
g_failures++;
}
/*
* All four threads will now be performing Gets/Puts on mutex1.
* When they have finished they will post sem1, so we wait
* until sem1 is posted four times.
*/
finish_cnt = 0;
while (1)
{
/*
* Attempt to Get sem1. When we have managed to get
* the semaphore four times, it must have been posted
* by all four threads.
*/
if (atomSemGet (&sem1, 0) == ATOM_OK)
{
/* Increment our count of finished threads */
finish_cnt++;
/* Check if all four threads have now posted sem1 */
if (finish_cnt == 4)
{
break;
}
}
}
/* Delete OS objects, test finished */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
}
/* Log final status */
if (g_failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), g_failures);
}
/* Quit */
return g_failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread. The same thread entry point is used for all
* four test threads.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint32_t loop_cnt;
uint8_t status;
CRITICAL_STORE;
/* Run a Get/Put pair many times */
loop_cnt = NUM_TEST_LOOPS;
while (loop_cnt--)
{
if ((status = atomMutexGet (&mutex1, 0)) != ATOM_OK)
{
/* Error getting mutex, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
break;
}
else if ((status = atomMutexPut (&mutex1)) != ATOM_OK)
{
/* Error putting mutex, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
break;
}
}
/* Post sem1 to notify the main thread we're finished */
if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Sem1 putfail\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

271
tests/mutex5.c Normal file
View File

@@ -0,0 +1,271 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atommutex.h"
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Global shared data protected by mutex */
static volatile int shared_data;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* This tests basic usage of a mutex. Whichever thread holds the
* mutex can modify the global variable "shared_data".
*
* The main thread first takes the mutex, then creates a second
* thread. The second thread should block on the mutex until the
* main thread releases it. The test checks that the global
* "shared_data" is not modified by the second thread until the
* main thread releases the mutex.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Create mutex */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating mutex\n"));
failures++;
}
else
{
/* Initialise the shared_data to zero */
shared_data = 0;
/* Take the mutex to ensure only this thread can modify shared_data */
if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex\n"));
failures++;
}
/* Create second thread */
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/*
* The second thread has now been created and should block on
* the mutex until we release it. We wait a while and check that
* shared_data has not been modified.
*/
for (i = 0; i < 4; i++)
{
/*
* Sleep for a while to give the second thread a chance to
* modify shared_data, thought it shouldn't until we
* release the mutex.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check shared data. The second thread always sets it to one. */
if (shared_data != 0)
{
ATOMLOG (_STR("Shared data modified\n"));
failures++;
break;
}
}
/* Check successful so far */
if (failures == 0)
{
/*
* Release the mutex, which will allow the second thread to
* wake and start modifying shared_data.
*/
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Failed release\n"));
failures++;
}
/*
* Wait a little while then check that shared_data has
* been modified.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
if (shared_data != 1)
{
ATOMLOG (_STR("Expected modify\n"));
failures++;
}
/*
* Release and take the mutex again a few times to ensure
* that the mutex continues to protect shared_data.
*/
for (i = 0; i < 4; i++)
{
/*
* Take the mutex again, to prevent second thread accessing
* shared_data.
*/
if (atomMutexGet (&mutex1, SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Retake %d\n"), i);
failures++;
break;
}
else
{
/*
* Set shared_data to 0 and wait to ensure that the
* second thread doesn't modify it while we have the
* mutex again.
*/
shared_data = 0;
/* Wait a while to give second thread potential to run */
atomTimerDelay(SYSTEM_TICKS_PER_SEC/4);
/*
* Check that shared_data has not been modified while we
* own the mutex.
*/
if (shared_data != 0)
{
/* Thread is still modifying the data */
ATOMLOG (_STR("Still modifying\n"));
failures++;
break;
}
/*
* Release the mutex, which will allow the second thread to
* wake and start modifying shared_data again.
*/
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Failed release\n"));
failures++;
}
}
}
}
/* Delete mutex, test finished */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
/* Repeatedly attempt to get the mutex and set shared_data to 1 */
while (1)
{
/* Block on the mutex */
if ((status = atomMutexGet (&mutex1, 0)) != ATOM_OK)
{
/* Error getting mutex, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
break;
}
/* Got the mutex */
else
{
/* Set shared_data to signify that we think we have the mutex */
shared_data = 1;
/* Release the mutex allowing the main thread to take it again */
if ((status = atomMutexPut (&mutex1)) != ATOM_OK)
{
/* Error putting mutex, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
break;
}
}
}
/* Loop forever - we only reach here on error */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

262
tests/mutex6.c Normal file
View File

@@ -0,0 +1,262 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atommutex.h"
/* Number of times to lock the mutex during test */
#define TEST_LOCK_CNT 250
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Global shared data protected by mutex */
static volatile int shared_data;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* This tests the lock count of a mutex. The mutex object should
* count the number of times a thread has locked the mutex and
* not fully release it for use by another thread until it has
* been released the same number of times it was locked.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Create mutex */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating mutex\n"));
failures++;
}
else
{
/* Initialise the shared_data to zero */
shared_data = 0;
/* Take the mutex several times */
for (i = 0; i < TEST_LOCK_CNT; i++)
{
if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex\n"));
failures++;
break;
}
}
/* Create second thread */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/*
* The second thread has now been created and should block on
* the mutex until we release it. We wait a while and check that
* shared_data has not been modified.
*/
for (i = 0; i < 4; i++)
{
/*
* Sleep for a while to give the second thread a chance to
* modify shared_data, thought it shouldn't until we
* release the mutex enough times.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check shared data. The second thread always sets it to one. */
if (shared_data != 0)
{
ATOMLOG (_STR("Shared data modified\n"));
failures++;
break;
}
}
/* Check successful so far */
if (failures == 0)
{
/*
* Release the mutex TEST_LOCK_CNT-1 times, after which we
* should still own the mutex (until we release one more time).
*/
for (i = 0; i < TEST_LOCK_CNT-1; i++)
{
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Failed release\n"));
failures++;
}
}
/*
* Wait a little while then check that shared_data has
* not been modified (we should still own the mutex).
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
if (shared_data != 0)
{
ATOMLOG (_STR("Expected unmodified\n"));
failures++;
}
/*
* Release the mutex one more time, after which we should no
* longer own the mutex (and wake up the second thread).
*/
if (atomMutexPut (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Failed release\n"));
failures++;
}
/*
* Wait a little while then check that shared_data has
* been modified by the second thread.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
if (shared_data != 1)
{
ATOMLOG (_STR("Expected modified\n"));
failures++;
}
}
/*
* Finally attempt to release the mutex one more time, while
* we no longer own the mutex. Either the second thread will
* have ownership of it, or no thread will have ownership.
* In both cases we expect to get an ownership error when we
* attempt to release it.
*/
if (atomMutexPut (&mutex1) != ATOM_ERR_OWNERSHIP)
{
ATOMLOG (_STR("Failed locked+1 release\n"));
failures++;
}
/* Delete mutex, test finished */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
/* Repeatedly attempt to get the mutex and set shared_data to 1 */
while (1)
{
/* Block on the mutex */
if ((status = atomMutexGet (&mutex1, 0)) != ATOM_OK)
{
/* Error getting mutex, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
break;
}
/* Got the mutex */
else
{
/* Set shared_data to signify that we think we have the mutex */
shared_data = 1;
/* Release the mutex allowing the main thread to take it again */
if ((status = atomMutexPut (&mutex1)) != ATOM_OK)
{
/* Error putting mutex, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
break;
}
}
}
/* Loop forever - we only reach here on error */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

236
tests/mutex7.c Normal file
View File

@@ -0,0 +1,236 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atommutex.h"
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Global shared data */
static volatile int shared_data;
/* Forward declarations */
static void testCallback (POINTER cb_data);
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* This tests the ownership checks of the mutex library. Only threads
* which own a mutex can release it. It should not be possible to
* release a mutex if it is not owned by any thread, is owned by a
* different thread, or at interrupt context. We test here that all
* three cases are trapped.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
ATOM_TIMER timer_cb;
/* Default to zero failures */
failures = 0;
/* Create mutex */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating mutex\n"));
failures++;
}
else
{
/* Initialise the shared_data to zero */
shared_data = 0;
/* Attempt to release the mutex when not owned by any thread */
if (atomMutexPut (&mutex1) != ATOM_ERR_OWNERSHIP)
{
ATOMLOG (_STR("Release error\n"));
failures++;
}
/* Create second thread */
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/*
* The second thread has now been created and should take ownership
* of the mutex. We wait a while and check that shared_data has been
* modified, which proves to us that the thread has taken the mutex.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
if (shared_data != 1)
{
ATOMLOG (_STR("Shared data unmodified\n"));
failures++;
}
/* Check successful so far */
if (failures == 0)
{
/*
* Attempt to release the mutex again now that it is owned
* by another thread.
*/
if (atomMutexPut (&mutex1) != ATOM_ERR_OWNERSHIP)
{
ATOMLOG (_STR("Release error 2\n"));
failures++;
}
/* Finally check that the mutex cannot be released from an ISR */
/* Fill out the timer callback request structure */
timer_cb.cb_func = testCallback;
timer_cb.cb_data = NULL;
timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;
/* Request the timer callback to run in one second */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("Error registering timer\n"));
failures++;
}
/*
* Wait two seconds for shared_date to be set to 2
* indicating success. This happens if the timer
* callback received the expected ownership error
* when attempting to release the mutex.
*/
else
{
atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC);
if (shared_data != 2)
{
ATOMLOG (_STR("Context check failed\n"));
failures++;
}
}
}
/* Delete mutex, test finished */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
/* Block on the mutex */
if ((status = atomMutexGet (&mutex1, 0)) != ATOM_OK)
{
/* Error getting mutex, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
}
/* Got the mutex */
else
{
/* Set shared_data to signify that we think we have the mutex */
shared_data = 1;
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}
/**
* \b testCallback
*
* Attempt an atomMutexPut() on mutex1 from interrupt context.
* Should receive an ATOM_ERR_OWNERSHIP error. Sets shared_data
* to 2 if passes.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
/* Check the return value from atomMutexPut() */
if (atomMutexPut(&mutex1) == ATOM_ERR_OWNERSHIP)
{
/* Received the error we expected, set shared_data to notify success */
shared_data = 2;
}
else
{
/* Did not get expected error, don't set shared_data signifying fail */
}
}

200
tests/mutex8.c Normal file
View File

@@ -0,0 +1,200 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atommutex.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_TCB tcb1, tcb2, tcb3;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test results */
static volatile int pass_flag[3];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* This test verifies the mutex deletion API, by deleting a mutex
* on which multiple threads are blocking, and checking that all three
* are woken up with an appropriate error code.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Initialise pass status for all three threads to FALSE */
for (i = 0; i < 3; i++)
{
pass_flag[i] = FALSE;
}
/* Test wakeup of three threads on mutex deletion */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating mutex\n"));
failures++;
}
else
{
/* Take the mutex to ensure that all three test threads will block */
if (atomMutexGet (&mutex1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex\n"));
failures++;
}
/* Create test thread 1 */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
/* Create test thread 2 */
else if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 1,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
/* Create test thread 3 */
else if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 2,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 3\n"));
failures++;
}
/* Test threads now created */
else
{
/* Wait a while for threads to start blocking on mutex1 */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Delete mutex1 now that all three threads should be blocking */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Delete fail\n"));
failures++;
}
else
{
/* Wait a while for all three threads to wake up */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check that all three threads have passed */
if ((pass_flag[0] != TRUE) || (pass_flag[1] != TRUE) || (pass_flag[2] != TRUE))
{
ATOMLOG (_STR("Thread fail\n"));
failures++;
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test threads.
*
* @param[in] data Thread ID (0-2)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
int thread_id;
/* Pull out the passed thread ID */
thread_id = (int)data;
/*
* Wait on mutex1 with timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomMutexGet(&mutex1, (5 * SYSTEM_TICKS_PER_SEC));
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set pass_flag to notify success */
pass_flag[thread_id] = TRUE;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

187
tests/mutex9.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atommutex.h"
/* Test OS objects */
static ATOM_MUTEX mutex1;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Global shared data protected by mutex */
static volatile int shared_data;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start mutex test.
*
* This tests timeouts on a mutex. We make a thread block with timeout
* on a mutex, and test that sufficient time has actually passed as
* was requested by the timeout parameter.
*
* The main thread creates a second thread which will immediately take
* ownership of the mutex. The test checks that the correct timeout
* occurs when the first thread blocks on the mutex which is already
* owned (by the second thread).
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint32_t start_time, end_time;
/* Default to zero failures */
failures = 0;
/* Create mutex */
if (atomMutexCreate (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating mutex\n"));
failures++;
}
else
{
/* Initialise the shared_data to zero */
shared_data = 0;
/* Create second thread */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/*
* The second thread has now been created and should take ownership
* of the mutex. We wait a while and check that shared_data has been
* modified, which proves to us that the thread has taken the mutex.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
if (shared_data != 1)
{
ATOMLOG (_STR("Shared data unmodified\n"));
failures++;
}
/* Check successful so far */
if (failures == 0)
{
/* Take note of the start time */
start_time = atomTimeGet();
/* Block on the mutex with two second timeout */
if (atomMutexGet (&mutex1, 2 * SYSTEM_TICKS_PER_SEC) != ATOM_TIMEOUT)
{
ATOMLOG (_STR("Failed get\n"));
failures++;
}
/* Take note of the end time */
end_time = atomTimeGet();
/* Now check that two seconds have passed */
if ((end_time < (start_time + (2 * SYSTEM_TICKS_PER_SEC)))
|| (end_time > (start_time + (2 * SYSTEM_TICKS_PER_SEC) + 1)))
{
ATOMLOG (_STR("Bad time\n"));
failures++;
}
}
/* Delete mutex, test finished */
if (atomMutexDelete (&mutex1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
/* Block on the mutex */
if ((status = atomMutexGet (&mutex1, 0)) != ATOM_OK)
{
/* Error getting mutex, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
}
/* Got the mutex */
else
{
/* Set shared_data to signify that we think we have the mutex */
shared_data = 1;
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

158
tests/queue1.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomqueue.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test queue size */
#define QUEUE_ENTRIES 16
/* Test OS objects */
static ATOM_QUEUE queue1;
static uint8_t queue1_storage[QUEUE_ENTRIES];
/**
* \b test_start
*
* Start queue test.
*
* This test exercises the queue creation and deletion APIs.
*
* Testing of deletion while threads are actually blocking in
* queue APIs is tested in queue2.c and queue3.c.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint32_t i;
/* Default to zero failures */
failures = 0;
/* Test creation and deletion of queues: good values */
for (i = 0; i < 1000; i++)
{
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) == ATOM_OK)
{
if (atomQueueDelete (&queue1) == ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Error deleting queue\n"));
failures++;
break;
}
}
else
{
/* Fail */
ATOMLOG (_STR("Error creating queue\n"));
failures++;
break;
}
}
/* Test creation and deletion of queues: creation checks */
if (atomQueueCreate (NULL, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad queue ptr check\n"));
failures++;
}
if (atomQueueCreate (&queue1, NULL, sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad buff ptr check\n"));
failures++;
}
if (atomQueueCreate (&queue1, &queue1_storage[0], 0, QUEUE_ENTRIES) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad size check\n"));
failures++;
}
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), 0) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad entries check\n"));
failures++;
}
/* Test creation and deletion of queues: deletion checks */
if (atomQueueDelete (NULL) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad queue deletion checks\n"));
failures++;
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}

218
tests/queue10.c Normal file
View File

@@ -0,0 +1,218 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomqueue.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test queue size */
#define QUEUE_ENTRIES 8
/* Test OS objects */
static ATOM_QUEUE queue1;
static uint32_t queue1_storage[QUEUE_ENTRIES];
/* Test message values (more values than can fit in an entire 8 message queue) */
uint32_t test_values[] =
{
0x12345678,
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF,
0xF000000F,
0x0F0000F0,
0x00F00F00,
0x000FF000,
0x87654321,
0xABCD0000,
0x0000CDEF
};
/**
* \b test_start
*
* Start queue test.
*
* This tests basic operation of queues.
*
* Messages are posted to and received from the queue and checked
* against expected values. To ensure correct ordering, queue posts
* and receives are done in blocks of different amounts, such that
* there will already be different numbers of messages in the queue
* whenever messages are posted and received.
*
* We test using 4-byte messages.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures, tx_count, rx_count;
uint32_t msg;
/* Default to zero failures */
failures = 0;
/* Create test queue */
if (atomQueueCreate (&queue1, (uint8_t *)&queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test queue\n"));
failures++;
}
else
{
/* Reset tx/rx counts */
tx_count = rx_count = 0;
/* Post 2 messages to the queue */
for (; tx_count < 2; tx_count++)
{
msg = test_values[tx_count];
if (atomQueuePut (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed post\n"));
failures++;
}
}
/* Receive 1 message from the queue */
for (; rx_count < 2; rx_count++)
{
if (atomQueueGet (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed get\n"));
failures++;
}
else if (msg != test_values[rx_count])
{
ATOMLOG (_STR("Val%d\n"), rx_count);
failures++;
}
}
/* Post 3 messages to the queue */
for (; tx_count < 5; tx_count++)
{
msg = test_values[tx_count];
if (atomQueuePut (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed post\n"));
failures++;
}
}
/* Receive 2 messages from the queue */
for (; rx_count < 3; rx_count++)
{
if (atomQueueGet (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed get\n"));
failures++;
}
else if (msg != test_values[rx_count])
{
ATOMLOG (_STR("Val%d\n"), rx_count);
failures++;
}
}
/* Post 5 messages to the queue */
for (; tx_count < 10; tx_count++)
{
msg = test_values[tx_count];
if (atomQueuePut (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed post\n"));
failures++;
}
}
/* Receive 3 messages from the queue */
for (; rx_count < 6; rx_count++)
{
if (atomQueueGet (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed get\n"));
failures++;
}
else if (msg != test_values[rx_count])
{
ATOMLOG (_STR("Val%d\n"), rx_count);
failures++;
}
}
/* Post 2 messages to the queue */
for (; tx_count < 12; tx_count++)
{
msg = test_values[tx_count];
if (atomQueuePut (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed post\n"));
failures++;
}
}
/* Receive 6 messages from the queue */
for (; rx_count < 12; rx_count++)
{
if (atomQueueGet (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed get\n"));
failures++;
}
else if (msg != test_values[rx_count])
{
ATOMLOG (_STR("Val%d\n"), rx_count);
failures++;
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}

277
tests/queue2.c Normal file
View File

@@ -0,0 +1,277 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomqueue.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test queue size */
#define QUEUE_ENTRIES 16
/* Test OS objects */
static ATOM_QUEUE queue1;
static ATOM_TCB tcb1, tcb2;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t queue1_storage[QUEUE_ENTRIES];
/* Test result tracking */
static volatile int g_result;
/* Forward declarations */
static void test1_thread_func (uint32_t data);
static void test2_thread_func (uint32_t data);
/**
* \b test_start
*
* Start queue test.
*
* This test exercises queue deletion, waking threads blocking on a queue
* in atomQueueGet() if the queue is deleted.
*
* Deletion wakeups are tested twice: once for a thread which is blocking
* in atomQueueGet() with a timeout and once for a thread which is
* blocking in atomQueueGet() with no timeout.
*
* Deletion of threads blocking in atomQueuePut() are tested in queue3.c.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* Test wakeup of threads on queue deletion (thread blocking with no timeout) */
g_result = 0;
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test queue\n"));
failures++;
}
/* Create a test thread that will block because the queue is empty */
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test1_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
else
{
/*
* We have created an empty queue. We want to see that the other
* thread is woken up if its queue is deleted. This is indicated
* through g_result being set.
*/
/* Wait for the other thread to start blocking on queue1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on queue1 now, delete queue1 */
if (atomQueueDelete(&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Failed queue1 delete\n"));
failures++;
}
else
{
/* Queue1 deleted. The thread should now wake up and set g_result. */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
if (g_result == 0)
{
ATOMLOG (_STR("Notify fail\n"));
failures++;
}
else
{
/* Success */
}
}
}
}
/* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */
g_result = 0;
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test queue\n"));
failures++;
}
/* Create a test thread that will block because the queue is empty */
else if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test2_thread_func, 0,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
else
{
/*
* We have created an empty queue. We want to see that the other
* thread is woken up if its queue is deleted. This is indicated
* through g_result being set.
*/
/* Wait for the other thread to start blocking on queue1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on queue1 now, delete queue1 */
if (atomQueueDelete(&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Failed queue1 delete\n"));
failures++;
}
else
{
/* Queue1 deleted. The thread should now wake up and set g_result. */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
if (g_result == 0)
{
ATOMLOG (_STR("Notify fail\n"));
failures++;
}
else
{
/* Success */
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test1_thread_func
*
* Entry point for test thread 1.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test1_thread_func (uint32_t data)
{
uint8_t status, msg;
/*
* Wait on queue1 with no timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomQueueGet(&queue1, 0, &msg);
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set g_result to notify success */
g_result = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}
/**
* \b test2_thread_func
*
* Entry point for test thread 2.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test2_thread_func (uint32_t data)
{
uint8_t status, msg;
/*
* Wait on queue1 with timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomQueueGet(&queue1, (5 * SYSTEM_TICKS_PER_SEC), &msg);
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test2 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set g_result to notify success */
g_result = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

317
tests/queue3.c Normal file
View File

@@ -0,0 +1,317 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomqueue.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test queue size */
#define QUEUE_ENTRIES 16
/* Test OS objects */
static ATOM_QUEUE queue1;
static ATOM_TCB tcb1, tcb2;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t queue1_storage[QUEUE_ENTRIES];
/* Test result tracking */
static volatile int g_result;
/* Forward declarations */
static void test1_thread_func (uint32_t data);
static void test2_thread_func (uint32_t data);
/**
* \b test_start
*
* Start queue test.
*
* This test exercises queue deletion, waking threads blocking on a queue
* in atomQueuePut() if the queue is deleted.
*
* Deletion wakeups are tested twice: once for a thread which is blocking
* in atomQueuePut() with a timeout and once for a thread which is
* blocking in atomQueuePut() with no timeout.
*
* Deletion of threads blocking in atomQueueGet() are tested in queue2.c.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures, i;
uint8_t msg;
/* Default to zero failures */
failures = 0;
/* Set a test value for posting to the queue */
msg = 0x66;
/* Test wakeup of threads on queue deletion (thread blocking with no timeout) */
g_result = 0;
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test queue\n"));
failures++;
}
/* Successful queue creation */
else
{
/* Fill up all entries */
for (i = 0; i < QUEUE_ENTRIES; i++)
{
if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK)
{
ATOMLOG (_STR("Error filling queue\n"));
failures++;
}
}
/* Create a test thread that will block because the queue is full */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test1_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
else
{
/*
* We have created and filled a queue. We want to see that the other
* thread is woken up if its queue is deleted. This is indicated
* through g_result being set.
*/
/* Wait for the other thread to start blocking on queue1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on queue1 now, delete queue1 */
if (atomQueueDelete(&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Failed queue1 delete\n"));
failures++;
}
else
{
/* Queue1 deleted. The thread should now wake up and set g_result. */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
if (g_result == 0)
{
ATOMLOG (_STR("Notify fail\n"));
failures++;
}
else
{
/* Success */
}
}
}
}
}
/* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */
g_result = 0;
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test queue\n"));
failures++;
}
/* Successful queue creation */
else
{
/* Fill up all entries */
for (i = 0; i < QUEUE_ENTRIES; i++)
{
if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK)
{
ATOMLOG (_STR("Error filling queue\n"));
failures++;
}
}
/* Create a test thread that will block because the queue is full */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test2_thread_func, 0,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
else
{
/*
* We have created and filled a queue. We want to see that the other
* thread is woken up if its queue is deleted. This is indicated
* through g_result being set.
*/
/* Wait for the other thread to start blocking on queue1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on queue1 now, delete queue1 */
if (atomQueueDelete(&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Failed queue1 delete\n"));
failures++;
}
else
{
/* Queue1 deleted. The thread should now wake up and set g_result. */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
if (g_result == 0)
{
ATOMLOG (_STR("Notify fail\n"));
failures++;
}
else
{
/* Success */
}
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test1_thread_func
*
* Entry point for test thread 1.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test1_thread_func (uint32_t data)
{
uint8_t status, msg;
/* Set a test value for posting to the queue */
msg = 0x66;
/*
* Post to queue1 with no timeout. The queue should be full so
* we are expecting to block. We should then be woken up by the
* main thread while blocking.
*/
status = atomQueuePut(&queue1, 0, &msg);
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set g_result to notify success */
g_result = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}
/**
* \b test2_thread_func
*
* Entry point for test thread 2.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test2_thread_func (uint32_t data)
{
uint8_t status, msg;
/* Set a test value for posting to the queue */
msg = 0x66;
/*
* Post to queue1 with timeout. The queue should be full so
* we are expecting to block. We should then be woken up by the
* main thread while blocking.
*/
status = atomQueuePut(&queue1, (5 * SYSTEM_TICKS_PER_SEC), &msg);
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test2 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set g_result to notify success */
g_result = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

293
tests/queue4.c Normal file
View File

@@ -0,0 +1,293 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomqueue.h"
#include "atomtests.h"
#include "atomuser.h"
/* Number of queue entries */
#define QUEUE_ENTRIES 8
/* Test OS objects */
static ATOM_QUEUE queue1, queue2;
static uint8_t queue1_storage[QUEUE_ENTRIES];
static uint8_t queue2_storage[QUEUE_ENTRIES];
/* Test result tracking */
static volatile int g_result;
/* Forward declarations */
static void testCallbackGet (POINTER cb_data);
static void testCallbackPut (POINTER cb_data);
/**
* \b test_start
*
* Start queue test.
*
* This test exercises the atomQueueGet() and atomQueuePut() APIs
* particularly forcing the various error indications which can be
* returned from the APIs to ensure that handling for these corner
* cases has been correctly implemented.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint8_t msg;
ATOM_TIMER timer_cb;
int count;
/* Default to zero failures */
failures = 0;
/* Create two test queues: queue1 is empty, queue2 is full */
/* Empty queue1 creation */
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Queue1 create\n"));
failures++;
}
/* Full queue2 creation */
if (atomQueueCreate (&queue2, &queue2_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Queue2 create\n"));
failures++;
}
else
{
/* Fill the queue */
msg = 0x66;
for (count = 0; count < QUEUE_ENTRIES; count++)
{
/* Add one message at a time */
if (atomQueuePut (&queue2, 0, &msg) != ATOM_OK)
{
ATOMLOG (_STR("Queue2 put\n"));
failures++;
}
}
}
/* Test parameter checks */
if (atomQueueGet (NULL, 0, &msg) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Get queue param failed\n"));
failures++;
}
if (atomQueueGet (&queue1, 0, NULL) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Get msg param failed\n"));
failures++;
}
if (atomQueuePut (NULL, 0, &msg) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Put queue param failed\n"));
failures++;
}
if (atomQueuePut (&queue1, 0, NULL) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Put msg param failed\n"));
failures++;
}
/* Test atomQueueGet() can not be called from interrupt context */
g_result = 0;
/* Fill out the timer callback request structure */
timer_cb.cb_func = testCallbackGet;
timer_cb.cb_data = NULL;
timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;
/* Request the timer callback to run in one second */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("Error registering timer\n"));
failures++;
}
/* Wait two seconds for g_result to be set indicating success */
else
{
atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC);
if (g_result != 1)
{
ATOMLOG (_STR("Get context check failed\n"));
failures++;
}
}
/* Test atomQueuePut() can not be called from interrupt context */
g_result = 0;
/* Fill out the timer callback request structure */
timer_cb.cb_func = testCallbackPut;
timer_cb.cb_data = NULL;
timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;
/* Request the timer callback to run in one second */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("Error registering timer\n"));
failures++;
}
/* Wait two seconds for g_result to be set indicating success */
else
{
atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC);
if (g_result != 1)
{
ATOMLOG (_STR("Put context check failed\n"));
failures++;
}
}
/* Test ATOM_TIMEOUT is returned for Get/Put calls with timeout */
/* Attempt atomQueueGet() on empty queue to force timeout */
if (atomQueueGet (&queue1, SYSTEM_TICKS_PER_SEC, &msg) != ATOM_TIMEOUT)
{
ATOMLOG (_STR("Timeout q1 failed\n"));
failures++;
}
/* Attempt atomQueuePut() on full queue to force timeout */
msg = 0x66;
if (atomQueuePut (&queue2, SYSTEM_TICKS_PER_SEC, &msg) != ATOM_TIMEOUT)
{
ATOMLOG (_STR("Timeout q2 failed\n"));
failures++;
}
/* Test ATOM_WOULDBLOCK is returned for Get/Put calls with -1 timeout */
/* Attempt atomQueueGet() on empty queue to force block */
if (atomQueueGet (&queue1, -1, &msg) != ATOM_WOULDBLOCK)
{
ATOMLOG (_STR("Timeout q1 failed\n"));
failures++;
}
/* Attempt atomQueuePut() on full queue to force block */
msg = 0x66;
if (atomQueuePut (&queue2, -1, &msg) != ATOM_WOULDBLOCK)
{
ATOMLOG (_STR("Timeout q2 failed\n"));
failures++;
}
/* Delete the test queues */
if (atomQueueDelete (&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Error deleting q1\n"));
failures++;
}
if (atomQueueDelete (&queue2) != ATOM_OK)
{
ATOMLOG (_STR("Error deleting q2\n"));
failures++;
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallbackGet
*
* Attempt an atomQueueGet() on (empty) queue1 from interrupt context.
* Should receive an ATOM_ERR_CONTEXT error. Sets g_result if passes.
*
* @param[in] cb_data Not used
*/
static void testCallbackGet (POINTER cb_data)
{
uint8_t msg;
/* Check the return value from atomQueueGet() */
if (atomQueueGet(&queue1, 0, &msg) == ATOM_ERR_CONTEXT)
{
/* Received the error we expected, set g_result to notify success */
g_result = 1;
}
else
{
/* Did not get expected error, don't set g_result signifying fail */
}
}
/**
* \b testCallbackPut
*
* Attempt an atomQueuePut() on (full) queue2 from interrupt context.
* Should receive an ATOM_ERR_CONTEXT error. Sets g_result if passes.
*
* @param[in] cb_data Not used
*/
static void testCallbackPut (POINTER cb_data)
{
uint8_t msg;
/* Check the return value from atomQueuePut() */
msg = 0x66;
if (atomQueuePut(&queue2, 0, &msg) == ATOM_ERR_CONTEXT)
{
/* Received the error we expected, set g_result to notify success */
g_result = 1;
}
else
{
/* Did not get expected error, don't set g_result signifying fail */
}
}

276
tests/queue5.c Normal file
View File

@@ -0,0 +1,276 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomqueue.h"
/* Number of queue entries */
#define QUEUE_ENTRIES 8
/* Test OS objects */
static ATOM_QUEUE queue1;
static uint8_t queue1_storage[QUEUE_ENTRIES];
static ATOM_TCB tcb1, tcb2, tcb3, tcb4;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test4_thread_stack[TEST_THREAD_STACK_SIZE];
/* Data updated by threads */
static volatile uint8_t wake_cnt;
static volatile uint8_t wake_order[4];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start queue test.
*
* With multiple threads blocking on a single queue, this test confirms that
* they are woken in order when the queue is posted. The correct order for
* waking is that the higher priority threads are woken first, followed by the
* lower priority threads. Where multiple threads of the same priority are
* waiting, the threads are woken in FIFO order (the order in which they started
* waiting on the queue).
*
* To test this we create four threads which all wait on a single queue.
* One pair of threads are running at high priority, with the other pair at a
* lower priority:
*
* Thread 1: low prio thread A
* Thread 2: low prio thread B
* Thread 3: high prio thread A
* Thread 4: high prio thread B
*
* The threads are forced to start blocking on the same queue in the
* above order.
*
* We expect to see them woken up in the following order:
* 3, 4, 1, 2
*
* This proves the multiple blocking thread ordering in terms of both
* the priority-queueing and same-priority-FIFO-queueing.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures, count;
uint8_t msg;
/* Default to zero failures */
failures = 0;
/* Create empty queue */
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test q1\n"));
failures++;
}
/* Start the threads */
else
{
/*
* The test threads all start by calling atomQueueGet() to receive
* a message from the queue. Because the queue is empty, all test
* threads should immediately block on the queue (until a message
* is posted to it).
*/
/* Create Thread 1 (lower priority thread A) */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO+1, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the queue */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 2 (lower priority thread B) */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO+1, test_thread_func, 2,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the queue */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 3 (higher priority thread A) */
if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 3,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the queue */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 4 (higher priority thread B) */
if (atomThreadCreate(&tcb4, TEST_THREAD_PRIO, test_thread_func, 4,
&test4_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the queue */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* All four threads will now be blocking on queue1 */
/*
* Initialise wake count, used by threads to determine
* what order they were woken in.
*/
wake_cnt = 0;
/* Loop waking all four threads */
for (count = 0; count < 4; count++)
{
/*
* Post a message to the queue. This will wake up one of the threads
* blocking on it (because it is currently empty). That thread will
* wake up, note the order at which it was woken, then go to sleep
* forever leaving the queue empty again. This is done four times so
* that all four threads are woken, noting their wake order.
*/
msg = 0x66;
if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK)
{
ATOMLOG (_STR("Post fail\n"));
failures++;
}
/*
* Sleep to give the thread time to wake up and modify the shared
* global data wake_cnt and wake_order[]. We deliberately do not
* use a mutex for protecting access to this shared data, as we
* are testing the queue module in isolation here.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC / 4);
}
/* All four threads now woken up, check they woke in correct order */
if ((wake_order[0] != 3) && (wake_order[1] != 4)
&& (wake_order[2] != 1) && (wake_order[3] != 2))
{
ATOMLOG (_STR("Bad order %d,%d,%d,%d\n"),
wake_order[0], wake_order[1], wake_order[2], wake_order[3]);
failures++;
}
/* Delete queue, test finished */
if (atomQueueDelete (&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread. The same thread entry point is used for all
* four test threads, with the thread number/ID (1-4) passed as the entry
* point parameter.
*
* @param[in] data Thread number (1,2,3,4)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t thread_id;
uint8_t msg;
/* Thread ID is passed through the function parameter */
thread_id = (uint8_t)data;
/*
* Wait for a message to appear on queue1. At creation of all test
* threads the queue is empty, so all four threads will block here.
*/
if (atomQueueGet (&queue1, 0, &msg) != ATOM_OK)
{
ATOMLOG (_STR("Get fail\n"));
}
else
{
/*
* Store our thread ID in the array using the current
* wake_cnt order. The threads are woken with large
* pauses between, which provides protection for this
* global data. This allows us to test queues without
* assuming a working implementation of a mutex (or
* similar protection mechanism).
*/
wake_order[wake_cnt++] = thread_id;
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

241
tests/queue6.c Normal file
View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomqueue.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test queue size */
#define QUEUE_ENTRIES 8
/* Test OS objects */
static ATOM_QUEUE queue1;
static uint32_t queue1_storage[QUEUE_ENTRIES];
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test message values (more values than can fit in an entire 8 message queue) */
uint32_t test_values[] =
{
0x12345678,
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF,
0xF000000F,
0x0F0000F0,
0x00F00F00,
0x000FF000,
0x87654321,
0xABCD0000,
0x0000CDEF
};
/* Test result tracking */
static volatile int g_result;
/* Forward declarations */
static void test1_thread_func (uint32_t data);
/**
* \b test_start
*
* Start queue test.
*
* This tests basic operation of queues.
*
* The main test thread creates a second thread and posts
* a series of messages to the second thread. The message
* values are checked against the expected values.
*
* We test using 4-byte messages.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures, count;
int num_entries;
uint32_t msg;
/* Default to zero failures */
failures = 0;
g_result = 0;
/* Create test queue */
if (atomQueueCreate (&queue1, (uint8_t *)&queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test queue\n"));
failures++;
}
/* Create a test thread that will block because the queue is empty */
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO + 1, test1_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
else
{
/*
* We have created an empty queue and a thread which should now
* be blocking on the queue. The test thread is lower priority
* than us.
*/
/* Wait for the other thread to start blocking on queue1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/*
* Post all entries in the test array to the queue.
* Because the second thread is lower priority than
* us, we will post 8 messages until the queue is
* full without waking up the second thread at all.
* At that point, we will block and the second
* thread will remove one message from the queue.
* With a spare entry in the queue, this thread
* will wake up again and post another message.
* This will continue until this thread has posted
* all messages, at which point the second thread
* will drain all remaining messages from the
* queue.
*
* Through this scheme we are able to test posting
* to the queue at all possible fill levels.
*/
num_entries = sizeof(test_values) / sizeof(test_values[0]);
for (count = 0; count < num_entries; count++)
{
/* Increment through and post all test values to the queue */
msg = test_values[count];
if (atomQueuePut (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed post\n"));
failures++;
}
}
/* Sleep a while for the second thread to finish */
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
/* Check that the second thread has found all test values */
if (g_result != 1)
{
ATOMLOG (_STR("Bad test vals\n"));
failures++;
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test1_thread_func
*
* Entry point for test thread 1.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test1_thread_func (uint32_t data)
{
uint32_t msg;
int num_entries, count, failures;
/* Default to no errors */
failures = 0;
/*
* Loop receiving messages until we have received the number of
* values in the test array.
*/
num_entries = sizeof(test_values) / sizeof(test_values[0]);
for (count = 0; count < num_entries; count++)
{
/* Receive a value from the queue */
if (atomQueueGet (&queue1, 0, (uint8_t *)&msg) != ATOM_OK)
{
ATOMLOG (_STR("Failed get\n"));
failures++;
}
/* Check that we received the expected value */
else if (msg != test_values[count])
{
ATOMLOG (_STR("Val%d\n"), count);
failures++;
}
}
/*
* Set g_result to indicate success if we had no failures.
* Thread-protection is not required on g_result because it
* is only ever set by this thread.
*/
if (failures == 0)
{
/* No failures */
g_result = 1;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

201
tests/queue7.c Normal file
View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomqueue.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test queue size */
#define QUEUE_ENTRIES 8
/* Test OS objects */
static ATOM_QUEUE queue1;
static uint8_t queue1_storage[QUEUE_ENTRIES];
static ATOM_TCB tcb1, tcb2, tcb3;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test results */
static volatile int pass_flag[3];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start queue test.
*
* This test verifies the queue deletion API, by deleting a queue
* on which multiple threads are blocking, and checking that all three
* are woken up with an appropriate error code.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Initialise pass status for all three threads to FALSE */
for (i = 0; i < 3; i++)
{
pass_flag[i] = FALSE;
}
/* Test wakeup of three threads on queue deletion */
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating Q\n"));
failures++;
}
else
{
/* The queue is empty so all three test threads will block */
/* Create test thread 1 */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
/* Create test thread 2 */
else if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 1,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
/* Create test thread 3 */
else if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 2,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 3\n"));
failures++;
}
/* Test threads now created */
else
{
/* Wait a while for threads to start blocking on queue1 */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Delete queue1 now that all three threads should be blocking */
if (atomQueueDelete (&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Delete fail\n"));
failures++;
}
else
{
/* Wait a while for all three threads to wake up */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check that all three threads have passed */
if ((pass_flag[0] != TRUE) || (pass_flag[1] != TRUE) || (pass_flag[2] != TRUE))
{
ATOMLOG (_STR("Thread fail\n"));
failures++;
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test threads.
*
* @param[in] data Thread ID (0-2)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
uint8_t msg;
int thread_id;
/* Pull out the passed thread ID */
thread_id = (int)data;
/*
* Wait on queue1 with timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomQueueGet(&queue1, (5 * SYSTEM_TICKS_PER_SEC), &msg);
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set pass_flag to notify success */
pass_flag[thread_id] = TRUE;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

118
tests/queue8.c Normal file
View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomqueue.h"
/* Test queue size */
#define QUEUE_ENTRIES 8
/* Test OS objects */
static ATOM_QUEUE queue1;
static uint8_t queue1_storage[QUEUE_ENTRIES];
/**
* \b test_start
*
* Start queue test.
*
* This tests timeouts on a queue. We make a thread block with timeout
* on a queue, and test that sufficient time has actually passed as
* was requested by the timeout parameter.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint32_t start_time, end_time;
uint8_t msg;
/* Default to zero failures */
failures = 0;
/* Create queue */
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating Q\n"));
failures++;
}
else
{
/* The queue is empty so atomQueueGet() calls will block */
/* Take note of the start time */
start_time = atomTimeGet();
/* Block on the queue with two second timeout */
if (atomQueueGet (&queue1, 2 * SYSTEM_TICKS_PER_SEC, &msg) != ATOM_TIMEOUT)
{
ATOMLOG (_STR("Failed get\n"));
failures++;
}
/* Take note of the end time */
end_time = atomTimeGet();
/* Now check that two seconds have passed */
if ((end_time < (start_time + (2 * SYSTEM_TICKS_PER_SEC)))
|| (end_time > (start_time + (2 * SYSTEM_TICKS_PER_SEC) + 1)))
{
ATOMLOG (_STR("Bad time\n"));
failures++;
}
/* Delete queue, test finished */
if (atomQueueDelete (&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}

265
tests/queue9.c Normal file
View File

@@ -0,0 +1,265 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomqueue.h"
#include "atomsem.h"
/* Number of test loops for stress-test */
#define NUM_TEST_LOOPS 10000
/* Test queue size */
#define QUEUE_ENTRIES 8
/* Test OS objects */
static ATOM_QUEUE queue1;
static uint8_t queue1_storage[QUEUE_ENTRIES];
static ATOM_SEM sem1;
static ATOM_TCB tcb1, tcb2, tcb3, tcb4;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test4_thread_stack[TEST_THREAD_STACK_SIZE];
/*
* Global failure count (can be updated by test threads but is
* protected by an interrupt lockout).
*/
static volatile int g_failures;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start queue test.
*
* Stress-tests queue Get and Put operations. Four threads are created which are
* continually Putting and Getting the same queue, with no time delays between
* each Get/Put. Because all threads are at the same priority this ensures that
* on timeslices when threads are rescheduled there are several context-switch
* points, while the threads may be part-way through queue API calls.
*
* @retval Number of g_failures
*/
uint32_t test_start (void)
{
CRITICAL_STORE;
int finish_cnt;
/* Default to zero g_failures */
g_failures = 0;
/* Create queue to stress */
if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK)
{
ATOMLOG (_STR("Error creating Q\n"));
g_failures++;
}
/* Create sem to receive thread-finished notification */
else if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating sem\n"));
g_failures++;
}
else
{
/* Create Thread 1 */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 2 */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 2,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 3 */
if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 3,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 4 */
if (atomThreadCreate(&tcb4, TEST_THREAD_PRIO, test_thread_func, 4,
&test4_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/*
* All four threads will now be performing Gets/Puts on queue1.
* When they have finished they will post sem1, so we wait
* until sem1 is posted four times.
*/
finish_cnt = 0;
while (1)
{
/*
* Attempt to Get sem1. When we have managed to get
* the semaphore four times, it must have been posted
* by all four threads.
*/
if (atomSemGet (&sem1, 0) == ATOM_OK)
{
/* Increment our count of finished threads */
finish_cnt++;
/* Check if all four threads have now posted sem1 */
if (finish_cnt == 4)
{
break;
}
}
}
/* Delete OS objects, test finished */
if (atomQueueDelete (&queue1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
}
/* Log final status */
if (g_failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), g_failures);
}
/* Quit */
return g_failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread. The same thread entry point is used for all
* four test threads.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint32_t loop_cnt;
uint8_t status;
uint8_t msg;
CRITICAL_STORE;
/* Run a Put/Get pair many times */
loop_cnt = NUM_TEST_LOOPS;
while (loop_cnt--)
{
/* Put a message in the queue */
msg = 0x66;
if ((status = atomQueuePut (&queue1, 0, &msg)) != ATOM_OK)
{
/* Error putting mutex, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
break;
}
/* Retrieve a messages from the queue */
if ((status = atomQueueGet (&queue1, 0, &msg)) != ATOM_OK)
{
/* Error getting queue msg, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
break;
}
}
/* Post sem1 to notify the main thread we're finished */
if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Sem1 putfail\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

343
tests/sem1.c Normal file
View File

@@ -0,0 +1,343 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomsem.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test OS objects */
static ATOM_SEM sem1, sem2;
static ATOM_TCB tcb1, tcb2;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
/* Forward declarations */
static void test1_thread_func (uint32_t data);
static void test2_thread_func (uint32_t data);
/**
* \b test_start
*
* Start semaphore test.
*
* This test exercises the semaphore creation and deletion APIs, including
* waking threads blocking on a semaphore if the semaphore is deleted.
* Deletion wakeups are tested twice: once for a thread which is blocking
* with a timeout and once for a thread which is blocking with no timeout.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint32_t i;
uint8_t status;
/* Default to zero failures */
failures = 0;
/* Test creation and deletion of semaphores: good values */
for (i = 0; i < 1000; i++)
{
if (atomSemCreate (&sem1, 0) == ATOM_OK)
{
if (atomSemDelete (&sem1) == ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Error deleting semaphore\n"));
failures++;
break;
}
}
else
{
/* Fail */
ATOMLOG (_STR("Error creating semaphore\n"));
failures++;
break;
}
}
/* Test creation and deletion of semaphores: creation checks */
if (atomSemCreate (NULL, 0) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad semaphore creation checks\n"));
failures++;
}
/* Test creation and deletion of semaphores: deletion checks */
if (atomSemDelete (NULL) != ATOM_OK)
{
/* Success */
}
else
{
/* Fail */
ATOMLOG (_STR("Bad semaphore deletion checks\n"));
failures++;
}
/* Test wakeup of threads on semaphore deletion (thread blocking with no timeout) */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else if (atomSemCreate (&sem2, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 2\n"));
failures++;
}
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test1_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
else
{
/*
* We have created two semaphores. sem1 is for the other thread
* to wait on, which we will delete from this thread. We want
* to see that the other thread is woken up if its semaphore
* is deleted. This is indicated through sem2 being posted
* back to us.
*/
/* Wait for the other thread to start blocking on sem1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on sem1 now, delete sem1 */
if (atomSemDelete(&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Failed sem1 delete\n"));
failures++;
}
else
{
/* Sem1 deleted. The thread should now wake up and post sem2. */
if ((status = atomSemGet (&sem2, (5*SYSTEM_TICKS_PER_SEC))) != ATOM_OK)
{
ATOMLOG (_STR("Notify fail (%d)\n"), status);
failures++;
}
else
{
/* Success */
/* Clean up the last remaining semaphore */
if (atomSemDelete (&sem2) != ATOM_OK)
{
ATOMLOG (_STR("Failed sem2 delete\n"));
failures++;
}
}
}
}
}
/* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else if (atomSemCreate (&sem2, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 2\n"));
failures++;
}
else if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test2_thread_func, 0,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
else
{
/*
* We have created two semaphores. sem1 is for the other thread
* to wait on, which we will delete from this thread. We want
* to see that the other thread is woken up if its semaphore
* is deleted. This is indicated through sem2 being posted
* back to us.
*/
/* Wait for the other thread to start blocking on sem1 */
if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Failed timer delay\n"));
failures++;
}
else
{
/* The other thread will be blocking on sem1 now, delete sem1 */
if (atomSemDelete(&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Failed sem1 delete\n"));
failures++;
}
else
{
/* Sem1 deleted. The thread should now wake up and post sem2. */
if ((status = atomSemGet (&sem2, (5*SYSTEM_TICKS_PER_SEC))) != ATOM_OK)
{
ATOMLOG (_STR("Notify fail (%d)\n"), status);
failures++;
}
else
{
/* Success */
/* Clean up the last remaining semaphore */
if (atomSemDelete (&sem2) != ATOM_OK)
{
ATOMLOG (_STR("Failed sem2 delete\n"));
failures++;
}
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test1_thread_func
*
* Entry point for test thread 1.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test1_thread_func (uint32_t data)
{
uint8_t status;
/*
* Wait on sem1 with no timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomSemGet(&sem1, 0);
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, post sem2 to notify success */
if ((status = atomSemPut(&sem2)) != ATOM_OK)
{
ATOMLOG (_STR("Error posting sem2 on wakeup (%d)\n"), status);
}
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}
/**
* \b test2_thread_func
*
* Entry point for test thread 2.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test2_thread_func (uint32_t data)
{
uint8_t status;
/*
* Wait on sem1 with timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomSemGet(&sem1, (5 * SYSTEM_TICKS_PER_SEC));
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test2 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, post sem2 to notify success */
if ((status = atomSemPut(&sem2)) != ATOM_OK)
{
ATOMLOG (_STR("Error posting sem2 on wakeup\n"));
}
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

334
tests/sem2.c Normal file
View File

@@ -0,0 +1,334 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomsem.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test OS objects */
static ATOM_SEM sem1, sem2;
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start semaphore test.
*
* This test exercises the atomSemGet() and atomSemPut() APIs including
* forcing the various error indications which can be returned from the
* APIs to ensure that handling for these corner cases have been correctly
* implemented.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint8_t status;
ATOM_TIMER timer_cb;
/* Default to zero failures */
failures = 0;
/* Test semaphore wait timeouts */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Wait on semaphore with timeout */
if ((status = atomSemGet (&sem1, SYSTEM_TICKS_PER_SEC)) != ATOM_TIMEOUT)
{
ATOMLOG (_STR("Timo %d\n"), status);
failures++;
}
else
{
/* Test semaphore still operates correctly after timeout */
if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Put failed\n"));
failures++;
}
else
{
/* Count should now be 1 */
if (atomSemGet (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Get failed\n"));
failures++;
}
else
{
/* Delete it, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
}
}
}
/* Test semaphore blocks if count is zero */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Wait on semaphore with timeout */
if ((status = atomSemGet (&sem1, SYSTEM_TICKS_PER_SEC)) != ATOM_TIMEOUT)
{
ATOMLOG (_STR("Timo %d\n"), status);
failures++;
}
else
{
/* Delete it, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
}
/* Test semaphore does not block if count is one */
if (atomSemCreate (&sem1, 1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Wait on semaphore with timeout */
if ((status = atomSemGet (&sem1, SYSTEM_TICKS_PER_SEC)) != ATOM_OK)
{
ATOMLOG (_STR("Get %d\n"), status);
failures++;
}
else
{
/* Delete it, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
}
/* Test parameter checks */
if (atomSemGet (NULL, 0) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Get param failed\n"));
failures++;
}
if (atomSemPut (NULL) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Put param failed\n"));
failures++;
}
/* Test atomSemGet() cannot be called from interrupt context */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test sem1\n"));
failures++;
}
else if (atomSemCreate (&sem2, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test sem2\n"));
failures++;
}
else
{
/* Fill out the timer callback request structure */
timer_cb.cb_func = testCallback;
timer_cb.cb_data = NULL;
timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;
/* Request the timer callback to run in one second */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("Error registering timer\n"));
failures++;
}
/* Wait up to two seconds for sem2 to be posted indicating success */
else if (atomSemGet (&sem2, 2 * SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Context check failed\n"));
failures++;
}
/* Delete the two test semaphores */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Sem1 delete failed\n"));
failures++;
}
if (atomSemDelete (&sem2) != ATOM_OK)
{
ATOMLOG (_STR("Sem2 delete failed\n"));
failures++;
}
}
/* Test for ATOM_WOULDBLOCK */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test sem1\n"));
failures++;
}
else
{
/* Semaphore count is zero so will block */
if ((status = atomSemGet (&sem1, -1)) != ATOM_WOULDBLOCK)
{
ATOMLOG (_STR("Wouldblock err %d\n"), status);
failures++;
}
/* Delete the test semaphore */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Sem1 delete failed\n"));
failures++;
}
}
/* Test no timeout */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test sem1\n"));
failures++;
}
else
{
/* Increment the semaphore */
if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Error on put\n"));
failures++;
}
/* Semaphore count is one so will not block */
if (atomSemGet (&sem1, -1) != ATOM_OK)
{
ATOMLOG (_STR("Error on get\n"));
failures++;
}
/* Delete the test semaphore */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Sem1 delete failed\n"));
failures++;
}
}
/* Test for semaphore counter overflows with too many puts */
if (atomSemCreate (&sem1, 255) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test sem1\n"));
failures++;
}
else
{
/* Increment the semaphore (expect this to overflow the count at 256) */
if (atomSemPut (&sem1) != ATOM_ERR_OVF)
{
ATOMLOG (_STR("Failed to detect overflow\n"));
failures++;
}
/* Delete the test semaphore */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Sem1 delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Attempt an atomSemGet() on sem1 from interrupt context.
* Should receive an ATOM_ERR_CONTEXT error. Posts sem2 if successful.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
/* Check the return value from atomSemGet() */
if (atomSemGet(&sem1, 0) == ATOM_ERR_CONTEXT)
{
/* Received the error we expected, post sem2 to notify success */
atomSemPut(&sem2);
}
else
{
/*
* Did not get the expected error, don't post sem2 and the test
* thread will time out, signifying an error.
*/
}
}

253
tests/sem3.c Normal file
View File

@@ -0,0 +1,253 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomsem.h"
/* Test OS objects */
static ATOM_SEM sem1;
static ATOM_TCB tcb1, tcb2, tcb3, tcb4;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test4_thread_stack[TEST_THREAD_STACK_SIZE];
/* Data updated by threads */
static volatile uint8_t wake_cnt;
static volatile uint8_t wake_order[4];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start semaphore test.
*
* With multiple threads blocking on a single semaphore, this test confirms that
* they are woken in order when the semaphore is posted. The correct order for
* waking is that the higher priority threads are woken first, followed by the
* lower priority threads. Where multiple threads of the same priority are
* waiting, the threads are woken in FIFO order (the order in which they started
* waiting on the semaphore).
*
* To test this we create four threads which all wait on a single semaphore.
* One pair of threads are running at high priority, with the other pair at a
* lower priority:
*
* Thread 1: low prio thread A
* Thread 2: low prio thread B
* Thread 3: high prio thread A
* Thread 4: high prio thread B
*
* The threads are forced to start blocking on the same semaphore in the
* above order (the semaphore is initialised with count 0 to ensure any
* threads calling atomSemGet() will block).
*
* We expect to see them woken up in the following order:
* 3, 4, 1, 2
*
* This proves the multiple blocking thread ordering in terms of both
* the priority-queueing and same-priority-FIFO-queueing.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Create sem with count zero (so that all threads will block) */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Create Thread 1 (lower priority thread A) */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO+1, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the semaphore */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 2 (lower priority thread B) */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO+1, test_thread_func, 2,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the semaphore */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 3 (higher priority thread A) */
if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 3,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the semaphore */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Create Thread 4 (higher priority thread B) */
if (atomThreadCreate(&tcb4, TEST_THREAD_PRIO, test_thread_func, 4,
&test4_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/* Delay to ensure the thread will start blocking on the semaphore */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* All four threads will now be blocking on sem1 */
/*
* Initialise wake count, used by threads to determine
* what order they were woken in.
*/
wake_cnt = 0;
/*
* Wake the four threads up in order, leaving some time between
* each wake up for them to deal with global data in a
* thread-safe fashion.
*/
for (i = 0; i < 4; i++)
{
/* Post semaphore to wake one of the threads up */
if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Post fail\n"));
failures++;
}
/* Sleep to give the thread time to manipulate global data */
atomTimerDelay (SYSTEM_TICKS_PER_SEC / 4);
}
/* All four threads now woken up, check they woke in correct order */
if ((wake_order[0] != 3) || (wake_order[1] != 4)
|| (wake_order[2] != 1) || (wake_order[3] != 2))
{
ATOMLOG (_STR("Bad order %d,%d,%d,%d\n"),
wake_order[0], wake_order[1], wake_order[2], wake_order[3]);
failures++;
}
/* Delete semaphore, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread. The same thread entry point is used for all
* four test threads, with the thread number/ID (1-4) passed as the entry
* point parameter.
*
* @param[in] data Thread number (1,2,3,4)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t thread_id;
/* Thread ID is passed through the function parameter */
thread_id = (uint8_t)data;
/*
* Wait for sem1 to be posted. At creation of all test threads
* the semaphore count is zero, so all four threads will block
* here.
*/
if (atomSemGet (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Thread sem fail\n"));
}
else
{
/*
* Store our thread ID in the array using the current
* wake_cnt order. The threads are deliberately woken up
* some time apart to ensure that no protection is required
* on this global data.
*/
wake_order[wake_cnt++] = thread_id;
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

254
tests/sem4.c Normal file
View File

@@ -0,0 +1,254 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomsem.h"
/* Number of test loops for stress-test */
#define NUM_TEST_LOOPS 10000
/* Test OS objects */
static ATOM_SEM sem1, sem2;
static ATOM_TCB tcb1, tcb2, tcb3, tcb4;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test4_thread_stack[TEST_THREAD_STACK_SIZE];
/*
* Global failure count (can be updated by test threads but is
* protected by an interrupt lockout).
*/
static volatile int g_failures;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start semaphore test.
*
* Stress-tests semaphore Get and Put operations. Four threads are created which are
* continually Getting and Putting the same semaphore, with no time delays between
* each Get/Put. A single semaphore is used, which is initially created with a count
* of two, meaning that at any one time there should be threads blocking and not
* blocking. This ensures that the stress-test covers multiple threads accessing the
* semaphore APIs simultaneously, as well as usage of the APIs while other threads
* are blocking on the semaphore.
*
* @retval Number of g_failures
*/
uint32_t test_start (void)
{
CRITICAL_STORE;
int finish_cnt;
/* Default to zero g_failures */
g_failures = 0;
/* Create sem to stress with count two */
if (atomSemCreate (&sem1, 2) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
g_failures++;
}
/* Create sem to receive thread-finished notification */
else if (atomSemCreate (&sem2, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
g_failures++;
}
else
{
/* Create Thread 1 */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 2 */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 2,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 3 */
if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 3,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Create Thread 4 */
if (atomThreadCreate(&tcb4, TEST_THREAD_PRIO, test_thread_func, 4,
&test4_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/*
* All four threads will now be performing Gets/Puts on sem1.
* When they have finished they will post sem2, so we wait
* until sem2 is posted four times.
*/
finish_cnt = 0;
while (1)
{
/*
* Attempt to Get sem2. When we have managed to get
* the semaphore four times, it must have been posted
* by all four threads.
*/
if (atomSemGet (&sem2, 0) == ATOM_OK)
{
/* Increment our count of finished threads */
finish_cnt++;
/* Check if all four threads have now posted sem2 */
if (finish_cnt == 4)
{
break;
}
}
}
/* Delete semaphores, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
if (atomSemDelete (&sem2) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
}
/* Log final status */
if (g_failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), g_failures);
}
/* Quit */
return g_failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread. The same thread entry point is used for all
* four test threads.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint32_t loop_cnt;
uint8_t status;
CRITICAL_STORE;
/* Run a Get/Put pair many times */
loop_cnt = NUM_TEST_LOOPS;
while (loop_cnt--)
{
if ((status = atomSemGet (&sem1, 0)) != ATOM_OK)
{
/* Error getting semaphore, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
break;
}
else if ((status = atomSemPut (&sem1)) != ATOM_OK)
{
/* Error putting semaphore, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
break;
}
}
/* Post sem2 to notify the main thread we're finished */
if (atomSemPut (&sem2) != ATOM_OK)
{
ATOMLOG (_STR("Sem2 putfail\n"));
CRITICAL_START ();
g_failures++;
CRITICAL_END ();
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

195
tests/sem5.c Normal file
View File

@@ -0,0 +1,195 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomsem.h"
/* Test OS objects */
static ATOM_SEM sem1, sem2;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start semaphore test.
*
* This tests basic synchronisation between threads using a semaphore.
*
* A second thread is created, which blocks on a semaphore until posted
* by the main thread. Testing all aspects of this transaction proves
* the basic usage of semaphores as a synchronisation mechanism
* between threads.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* Create sem with count zero for second thread to block on */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
/* Create sem to receive test-passed notification */
else if (atomSemCreate (&sem2, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Create second thread */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/*
* The second thread has now been created and should block on
* sem1 until we increment it to 1 (sem1 was created with a
* count of zero). Once the second thread has stopped blocking
* on sem1, it will post sem2 to notify us that it has finished.
*
* We can test the count of sem2 before and after posting sem1
* to ensure that it was the posting of sem1 which caused the
* second thread to wake up.
*/
/*
* Wait a little while, then check the second thread hasn't
* already posted sem2, i.e. did not wait until sem1 was posted.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
if (atomSemGet (&sem2, -1) != ATOM_WOULDBLOCK)
{
ATOMLOG (_STR("Did not wait\n"));
failures++;
}
/* Post sem1 to stop the second thread blocking */
else if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Put fail\n"));
failures++;
}
/* Now check that the second thread has woken up and posted sem2 */
else
{
/* Give the thread some time to wake up and post sem2 */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check that the second thread has now woken and posted sem2 */
if (atomSemGet (&sem2, -1) != ATOM_OK)
{
ATOMLOG (_STR("Sem2 not posted\n"));
failures++;
}
}
/* Delete semaphores, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
if (atomSemDelete (&sem2) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
/* Block on sem1. Main thread will post when we should wake up. */
if ((status = atomSemGet (&sem1, 0)) != ATOM_OK)
{
/* Error getting semaphore, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
}
/* Post sem2 to notify that we received the sem1 notification */
else if ((status = atomSemPut (&sem2)) != ATOM_OK)
{
/* Error putting semaphore, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

201
tests/sem6.c Normal file
View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomsem.h"
/* Semaphore count */
#define INITIAL_SEM_COUNT 10
/* Test OS objects */
static ATOM_SEM sem1, sem2;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start semaphore test.
*
* This tests basic counting semaphore operation between two threads.
*
* A semaphore is created with a count of 10. A second thread then
* ensures that it can decrement the semaphore 10 times before
* it can no longer be decremented.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* Create sem with count ten for second thread to decrement */
if (atomSemCreate (&sem1, INITIAL_SEM_COUNT) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
/* Create sem to receive test-passed notification */
else if (atomSemCreate (&sem2, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Check that sem2 doesn't already have a positive count */
if (atomSemGet (&sem2, -1) != ATOM_WOULDBLOCK)
{
ATOMLOG (_STR("Sem2 already put\n"));
failures++;
}
/* Create second thread */
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/*
* The second thread has now been created and will attempt to
* decrement sem1 ten times, then finally check that it cannot
* decrement it any further. If this passes then the second
* thread will post sem2 to notify us that the test has passed.
*/
else
{
/* Give the second thread one second to post sem2 */
if (atomSemGet (&sem2, SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Sem2 not posted\n"));
failures++;
}
}
/* Delete semaphores, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
if (atomSemDelete (&sem2) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
int count;
int failures;
/*
* Attempt to decrement sem1 ten times, which should happen immediately
* each time.
*/
failures = 0;
count = INITIAL_SEM_COUNT;
while (count--)
{
/* Decrement sem1 */
if ((status = atomSemGet (&sem1, -1)) != ATOM_OK)
{
/* Error decrementing semaphore, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
failures++;
}
}
/* Check above stage was successful */
if (failures == 0)
{
/* Sem1 should now have a count of zero, and not allow a decrement */
if ((status = atomSemGet (&sem1, -1)) != ATOM_WOULDBLOCK)
{
/* Error getting semaphore, notify the status code */
ATOMLOG (_STR("W%d\n"), status);
}
/* Post sem2 to notify that the test passed */
else if ((status = atomSemPut (&sem2)) != ATOM_OK)
{
/* Error putting semaphore, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
}
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

278
tests/sem7.c Normal file
View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomsem.h"
/* Test OS objects */
static ATOM_SEM sem1;
static ATOM_TCB tcb1;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
/* Global shared data protected by mutex */
static volatile int shared_data;
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start semaphore test.
*
* This tests usage of a semaphore for basic mutual exclusion type
* operation. Note that Atomthreads has a more fully-featured real
* mutex implementation in the mutex module.
*
* The semaphore sem1 is initialised with a count of 1. Whichever
* thread holds this semaphore can then modify the global variable
* "shared_data".
*
* The main thread first takes the "mutex" sem1, then creates a
* second thread. The second thread should block on the sem1 mutex
* until the main thread releases it. The test checks that the
* global "shared_data" is not modified by the second thread
* until the main thread releases the mutex.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Create sem with count one for mutex purposes */
if (atomSemCreate (&sem1, 1) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Initialise the shared_data to zero */
shared_data = 0;
/* Take the mutex to ensure only this thread can modify shared_data */
if (atomSemGet (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error taking mutex\n"));
failures++;
}
/* Create second thread */
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread\n"));
failures++;
}
/*
* The second thread has now been created and should block on
* the "mutex" sem1 (which now has count zero) until we release
* it. We wait a while and check that shared_data has not been
* modified.
*/
for (i = 0; i < 4; i++)
{
/*
* Sleep for a while to give the second thread a chance to
* modify shared_data, thought it shouldn't until we
* release the mutex.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check shared data. The second thread always sets it to one. */
if (shared_data != 0)
{
ATOMLOG (_STR("Shared data modified\n"));
failures++;
break;
}
}
/* Check successful so far */
if (failures == 0)
{
/*
* Release the mutex, which will allow the second thread to
* wake and start modifying shared_data.
*/
if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Failed release\n"));
failures++;
}
/*
* Wait a little while then check that shared_data has
* been modified.
*/
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
if (shared_data != 1)
{
ATOMLOG (_STR("Expected modify\n"));
failures++;
}
/*
* Release and take the mutex again a few times to ensure
* that the mutex continues to protect shared_data.
*/
for (i = 0; i < 4; i++)
{
/*
* Take the mutex again, to prevent second thread accessing
* shared_data.
*/
if (atomSemGet (&sem1, SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Retake %d\n"), i);
failures++;
break;
}
else
{
/*
* Set shared_data to 0 and wait to ensure that the
* second thread doesn't modify it while we have the
* mutex again.
*/
shared_data = 0;
/* Wait a while to give second thread potential to run */
atomTimerDelay(SYSTEM_TICKS_PER_SEC/4);
/*
* Check that shared_data has not been modified while we
* own the mutex.
*/
if (shared_data != 0)
{
/* Thread is still modifying the data */
ATOMLOG (_STR("Still modifying\n"));
failures++;
break;
}
/*
* Release the mutex, which will allow the second thread to
* wake and start modifying shared_data again.
*/
if (atomSemPut (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Failed release\n"));
failures++;
}
}
}
}
/* Delete semaphore, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
/* Repeatedly attempt to get the mutex and set shared_data to 1 */
while (1)
{
/* Block on the mutex sem1 */
if ((status = atomSemGet (&sem1, 0)) != ATOM_OK)
{
/* Error getting semaphore, notify the status code */
ATOMLOG (_STR("G%d\n"), status);
break;
}
/* Got the mutex */
else
{
/* Set shared_data to signify that we think we have the mutex */
shared_data = 1;
/* Release the mutex allowing the main thread to take it again */
if ((status = atomSemPut (&sem1)) != ATOM_OK)
{
/* Error putting semaphore, notify the status code */
ATOMLOG (_STR("P%d\n"), status);
break;
}
}
}
/* Loop forever - we only reach here on error */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

292
tests/sem8.c Normal file
View File

@@ -0,0 +1,292 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
#include "atomsem.h"
/* Test OS objects */
static ATOM_SEM sem1;
static ATOM_TCB tcb1, tcb2, tcb3;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test running flag */
static volatile int test_running;
/* Forward declarations */
static void test_thread_func (uint32_t data);
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start semaphore test.
*
* This stress-tests atomSemGet()/atomSemPut() with a single thread
* continually calling atomSemGet() and several contexts continually
* calling atomSemPut(). This stresses in particular the atomSemPut()
* API, with three threads at different priorities posting
* simultaneously, as well as a timer callback posting it from
* interrupt context. In all cases the same semaphore is posted.
*
* This tests the thread-safety and interrupt-safety of the semaphore
* APIs, and particularly the atomSemPut() function.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint32_t end_time;
ATOM_TIMER timer_cb;
/* Default to zero failures */
failures = 0;
/* Create sem with count of zero */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Set the test running flag */
test_running = TRUE;
/*
* Fill out a timer callback request structure. Pass the timer
* structure itself so that the callback can requeue the request.
*/
timer_cb.cb_func = testCallback;
timer_cb.cb_data = &timer_cb;
timer_cb.cb_ticks = 1;
/*
* Request a timer callback to run in one tick's time. The callback
* will automatically queue another so that this happens repeatedly
* until the test is flagged as finished.
*/
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("Error registering timer\n"));
failures++;
}
/* Create thread 1: Higher priority than main thread so should sleep */
else if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO - 1, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
/* Create thread 2: Same priority as main thread so should not sleep */
else if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 0,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
/* Create thread 3: Same priority as main thread so should not sleep */
else if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO + 1, test_thread_func, 0,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 3\n"));
failures++;
}
/* The test threads have now all been created */
else
{
/*
* Continually decrement the semaphore while the test threads
* and timer callbacks are continually incrementing it. The
* test finishes after this runs without error for 5 seconds.
*/
end_time = atomTimeGet() + (5 * SYSTEM_TICKS_PER_SEC);
while (atomTimeGet() < end_time)
{
/* Decrement the semaphore */
if (atomSemGet (&sem1, SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("SemGet\n"));
failures++;
break;
}
}
/* Test finished, stop the other threads and timer callbacks */
test_running = FALSE;
/*
* Wait before finishing: a timer callback could be due
* shortly, and we allocated the timer structure off the
* local call stack.
*/
atomTimerDelay(2);
}
/* Delete semaphores, test finished */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete failed\n"));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread.
*
* @param[in] data sleep_flag passed through here
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
int sleep_flag, count, failures;
/* Were we requested to sleep occasionally? */
sleep_flag = (int)data;
/* Run until the main thread sets the finish flag or we get an error */
failures = 0;
while ((test_running == TRUE) && (failures == 0))
{
/* Post the semaphore 50 times */
count = 50;
while (count--)
{
/*
* Post the semaphore. Allow overflows as these are likely
* to occur when so many threads are posting the same
* semaphore continually.
*/
status = atomSemPut (&sem1);
if ((status != ATOM_OK) && (status != ATOM_ERR_OVF))
{
ATOMLOG (_STR("Put\n"));
failures++;
break;
}
}
/*
* If requested to do so, sleep for a tick. This only happens on threads which
* are higher priority than the main test thread, and is necessary to allow
* the main thread to actually run. For better stress-testing, same or lower
* priority threads do not sleep.
*/
if (sleep_flag)
{
atomTimerDelay (1);
}
}
/* Loop forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}
/**
* \b testCallback
*
* Post the semaphore from interrupt context. This will be occurring while
* atomSemPut() calls for the other threads are in progress, because it is
* called by the system tick ISR. This tests that the APIs lockout
* interrupts where necessary.
*
* Automatically requeues itself for one tick in the future, so this
* continually fires until the finish flag is set.
*
* @param[in] cb_data Pointer to the original ATOM_TIMER structure
*/
static void testCallback (POINTER cb_data)
{
ATOM_TIMER *ptimer;
uint8_t status;
/* Pull out the original timer request */
ptimer = (ATOM_TIMER *)cb_data;
/* Post sem1 */
status = atomSemPut (&sem1);
if ((status != ATOM_OK) && (status != ATOM_ERR_OVF))
{
/* Error */
}
/* Enqueue another timer callback in one tick's time */
if (test_running == TRUE)
{
/* Update the callback time and requeue */
ptimer->cb_ticks = 1;
if (atomTimerRegister (ptimer) != ATOM_OK)
{
}
}
else
{
/* Test finished, no more will be queued */
}
}

193
tests/sem9.c Normal file
View File

@@ -0,0 +1,193 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomsem.h"
#include "atomtests.h"
#include "atomuser.h"
/* Test OS objects */
static ATOM_SEM sem1;
static ATOM_TCB tcb1, tcb2, tcb3;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
/* Test results */
static volatile int pass_flag[3];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start semaphore test.
*
* This test verifies the semaphore deletion API, by deleting a semaphore
* on which multiple threads are blocking, and checking that all three
* are woken up with an appropriate error code.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Initialise pass status for all three threads to FALSE */
for (i = 0; i < 3; i++)
{
pass_flag[i] = FALSE;
}
/* Test wakeup of three threads on semaphore deletion */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("Error creating test semaphore 1\n"));
failures++;
}
else
{
/* Create test thread 1 */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 0,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 1\n"));
failures++;
}
/* Create test thread 2 */
else if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 1,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 2\n"));
failures++;
}
/* Create test thread 3 */
else if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 2,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Error creating test thread 3\n"));
failures++;
}
/* Test threads now created */
else
{
/* Wait a while for threads to start blocking on sem1 */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Delete sem1 now that all three threads should be blocking */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete fail\n"));
failures++;
}
else
{
/* Wait a while for all three threads to wake up */
atomTimerDelay (SYSTEM_TICKS_PER_SEC/4);
/* Check that all three threads have passed */
if ((pass_flag[0] != TRUE) || (pass_flag[1] != TRUE) || (pass_flag[2] != TRUE))
{
ATOMLOG (_STR("Thread fail\n"));
failures++;
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test threads.
*
* @param[in] data Thread ID (0-2)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t status;
int thread_id;
/* Pull out the passed thread ID */
thread_id = (int)data;
/*
* Wait on sem1 with timeout. We are expecting to be woken up
* by the main thread while blocking.
*/
status = atomSemGet(&sem1, (5 * SYSTEM_TICKS_PER_SEC));
if (status != ATOM_ERR_DELETED)
{
ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
}
else
{
/* We were woken due to deletion as expected, set pass_flag to notify success */
pass_flag[thread_id] = TRUE;
}
/* Wait forever */
while (1)
{
atomTimerDelay (SYSTEM_TICKS_PER_SEC);
}
}

62
tests/test-template.c Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
/**
* \b test_start
*
* Start test.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}

258
tests/timer1.c Normal file
View File

@@ -0,0 +1,258 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomsem.h"
#include "atomtimer.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_SEM sem1;
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start timer test.
*
* This test exercises the atomTimerDelay() API. It checks that
* the correct time delay is used, and also checks that error
* checking is correctly implemented within the API.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
uint32_t start_time, end_time;
ATOM_TIMER timer_cb;
/* Default to zero failures */
failures = 0;
/* Test parameter-checks */
if (atomTimerDelay(0) != ATOM_ERR_PARAM)
{
ATOMLOG(_STR("Param\n"));
failures++;
}
/* Create a semaphore for receiving test notification */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("SemCreate\n"));
failures++;
}
else
{
/*
* Create a timer callback which will attempt to
* call atomTimerDelay() at interrupt context.
*/
timer_cb.cb_func = testCallback;
timer_cb.cb_data = NULL;
timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;
/* Request the timer callback to run in one second */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerRegister\n"));
failures++;
}
/* Wait up to two seconds for sem1 to be posted indicating success */
else if (atomSemGet (&sem1, 2 * SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Context check\n"));
failures++;
}
/* Delete the test semaphore */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete\n"));
failures++;
}
}
/*
* Test that a 1 tick delay returns when system time
* has increased by exactly 1 tick.
*/
/*
* We first delay by 1 tick to ensure that the thread
* is running at the start of a new tick, which should
* ensure that the time does not tick over between
* setting start_time and actually calling
* atomTimerDelay().
*/
atomTimerDelay(1);
/* Record the start time */
start_time = atomTimeGet();
/* Request a 1 tick sleep */
if (atomTimerDelay(1) != ATOM_OK)
{
ATOMLOG (_STR("Delay1\n"));
failures++;
}
else
{
/* Record the time we woke up */
end_time = atomTimeGet();
/* Check that time has advanced by exactly 1 tick */
if ((end_time - start_time) != 1)
{
ATOMLOG (_STR("Tick1:%d\n"), (end_time-start_time));
failures++;
}
}
/*
* Test that a 2 tick delay returns when system time
* has increased by exactly 2 ticks.
*/
/*
* We first delay by 1 tick to ensure that the thread
* is running at the start of a new tick, which should
* ensure that the time does not tick over between
* setting start_time and actually calling
* atomTimerDelay().
*/
atomTimerDelay(1);
/* Record the start time */
start_time = atomTimeGet();
/* Request a 2 tick sleep */
if (atomTimerDelay(2) != ATOM_OK)
{
ATOMLOG (_STR("Delay2\n"));
failures++;
}
else
{
/* Record the time we woke up */
end_time = atomTimeGet();
/* Check that time has advanced by exactly 2 ticks */
if ((end_time - start_time) != 2)
{
ATOMLOG (_STR("Tick2:%d\n"), (end_time-start_time));
failures++;
}
}
/*
* Test that a 500 tick delay returns when system time
* has increased by exactly 500 ticks.
*/
/*
* We first delay by 1 tick to ensure that the thread
* is running at the start of a new tick, which should
* ensure that the time does not tick over between
* setting start_time and actually calling
* atomTimerDelay().
*/
atomTimerDelay(1);
/* Record the start time */
start_time = atomTimeGet();
/* Request a 500 tick sleep */
if (atomTimerDelay(500) != ATOM_OK)
{
ATOMLOG (_STR("Delay500\n"));
failures++;
}
else
{
/* Record the time we woke up */
end_time = atomTimeGet();
/* Check that time has advanced by exactly 500 ticks */
if ((end_time - start_time) != 500)
{
ATOMLOG (_STR("Tick500:%d\n"), (end_time-start_time));
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Attempt an atomTimerDelay() call from interrupt context.
* Should receive an ATOM_ERR_CONTEXT error. Posts sem1 if successful.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
/* Check the return value from atomTimerDelay() */
if (atomTimerDelay(1) == ATOM_ERR_CONTEXT)
{
/* Received the error we expected, post sem1 to notify success */
atomSemPut(&sem1);
}
else
{
/*
* Did not get the expected error, don't post sem1 and the test
* thread will time out, signifying an error.
*/
}
}

176
tests/timer2.c Normal file
View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtimer.h"
#include "atomtests.h"
/* Test period (in seconds) */
#define TEST_PERIOD_SECS 10
/* Test OS objects */
static ATOM_TCB tcb1, tcb2, tcb3;
static uint8_t test1_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test2_thread_stack[TEST_THREAD_STACK_SIZE];
static uint8_t test3_thread_stack[TEST_THREAD_STACK_SIZE];
/* Per-thread failure counts */
static volatile int g_failure_cnt[3];
/* Forward declarations */
static void test_thread_func (uint32_t data);
/**
* \b test_start
*
* Start timer test.
*
* Tests that atomTimerDelay() delays for the correct time
* period when used by three threads simultanously.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
/* Default to zero failures */
failures = 0;
g_failure_cnt[0] = g_failure_cnt[1] = g_failure_cnt[2] = 0;
/* Create Thread 1 */
if (atomThreadCreate(&tcb1, TEST_THREAD_PRIO, test_thread_func, 1,
&test1_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Thread1\n"));
failures++;
}
/* Create Thread 2 */
if (atomThreadCreate(&tcb2, TEST_THREAD_PRIO, test_thread_func, 2,
&test2_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Thread2\n"));
failures++;
}
/* Create Thread 3 */
if (atomThreadCreate(&tcb3, TEST_THREAD_PRIO, test_thread_func, 3,
&test3_thread_stack[TEST_THREAD_STACK_SIZE - 1]) != ATOM_OK)
{
/* Fail */
ATOMLOG (_STR("Thread3\n"));
failures++;
}
/* Sleep for 10 seconds allowing the three threads to run tests */
if (atomTimerDelay(TEST_PERIOD_SECS * SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Period\n"));
failures++;
}
/* Add the per-thread failure count to the main count */
failures += g_failure_cnt[0] + g_failure_cnt[1] + g_failure_cnt[2];
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b test_thread_func
*
* Entry point for test thread. The same thread entry point is used for all
* three test threads, with the thread number/ID (1-3) passed as the entry
* point parameter.
*
* @param[in] data Thread number (1,2,3)
*
* @return None
*/
static void test_thread_func (uint32_t data)
{
uint8_t thread_id;
uint32_t start_time, end_time;
/* Thread ID is passed through the function parameter */
thread_id = (uint8_t)data;
/*
* Sleep for 1 tick to ensure that the thread starts near
* a timer tick boundary. This ensures that the system
* tick does not advance between the atomTimeGet() call
* and the actual atomTimerDelay() call being made.
*/
atomTimerDelay (1);
/* Loop running the test forever */
while (1)
{
/* Record the start time */
start_time = atomTimeGet();
/* Sleep for n ticks, where n is the thread ID */
if (atomTimerDelay(thread_id) != ATOM_OK)
{
g_failure_cnt[thread_id-1]++;
}
else
{
/* Record the time we woke up */
end_time = atomTimeGet();
/* Check that time has advanced by exactly n ticks */
if ((end_time - start_time) != thread_id)
{
g_failure_cnt[thread_id-1]++;
}
}
}
}

252
tests/timer3.c Normal file
View File

@@ -0,0 +1,252 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomsem.h"
#include "atomtimer.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_SEM sem1;
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start timer test.
*
* This test exercises the atomTimerRegister() API. It tests that bad
* parameters are trapped, and that timer callbacks occur at the
* correct time.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
ATOM_TIMER timer_cb;
uint32_t expected_time;
/* Default to zero failures */
failures = 0;
/* Create a semaphore for receiving test notifications */
if (atomSemCreate (&sem1, 0) != ATOM_OK)
{
ATOMLOG (_STR("SemCreate\n"));
failures++;
}
/* Test that bad parameters are trapped */
/* NULL parameter check */
if (atomTimerRegister(NULL) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Param1\n"));
failures++;
}
/* NULL callback function */
timer_cb.cb_ticks = 1;
timer_cb.cb_func = NULL;
if (atomTimerRegister(&timer_cb) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Param2\n"));
failures++;
}
/* Zero ticks */
timer_cb.cb_ticks = 0;
timer_cb.cb_func = testCallback;
if (atomTimerRegister(&timer_cb) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Param3\n"));
failures++;
}
/* Request a callback in 1 tick */
/*
* Sleep for one tick first to ensure we start near a
* tick boundary. This should ensure that the timer
* tick does not advance while we are setting up the
* timer but before registering the timer.
*/
atomTimerDelay(1);
/* Request a callback in one tick time */
timer_cb.cb_ticks = 1;
/* We pass our testCallback() the expected end time */
timer_cb.cb_func = testCallback;
expected_time = atomTimeGet() + timer_cb.cb_ticks;
timer_cb.cb_data = &expected_time;
/* Register the timer callback */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg1\n"));
failures++;
}
/* Wait up to 5 ticks for sem1 to be posted indicating success */
else if (atomSemGet (&sem1, 5) != ATOM_OK)
{
ATOMLOG (_STR("Tick1\n"));
failures++;
}
/* Request a callback in 2 ticks */
/*
* Sleep for one tick first to ensure we start near a
* tick boundary. This should ensure that the timer
* tick does not advance while we are setting up the
* timer but before registering the timer.
*/
atomTimerDelay(1);
/* Request a callback in 2 ticks time */
timer_cb.cb_ticks = 2;
/* We pass our testCallback() the expected end time */
timer_cb.cb_func = testCallback;
expected_time = atomTimeGet() + timer_cb.cb_ticks;
timer_cb.cb_data = &expected_time;
/* Register the timer callback */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg2\n"));
failures++;
}
/* Wait up to 5 ticks for sem1 to be posted indicating success */
else if (atomSemGet (&sem1, 5) != ATOM_OK)
{
ATOMLOG (_STR("Tick2\n"));
failures++;
}
/* Request a callback in 500 ticks */
/*
* Sleep for one tick first to ensure we start near a
* tick boundary. This should ensure that the timer
* tick does not advance while we are setting up the
* timer but before registering the timer.
*/
atomTimerDelay(1);
/* Request a callback in 500 ticks time */
timer_cb.cb_ticks = 500;
/* We pass our testCallback() the expected end time */
timer_cb.cb_func = testCallback;
expected_time = atomTimeGet() + timer_cb.cb_ticks;
timer_cb.cb_data = &expected_time;
/* Register the timer callback */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg500\n"));
failures++;
}
/* Wait up to 600 ticks for sem1 to be posted indicating success */
else if (atomSemGet (&sem1, 600) != ATOM_OK)
{
ATOMLOG (_STR("Tick500\n"));
failures++;
}
/* Delete the test semaphore */
if (atomSemDelete (&sem1) != ATOM_OK)
{
ATOMLOG (_STR("Delete\n"));
failures++;
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Check the time at which this timer callback occurs matches
* the time we expected. Post sem1 if correct.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
uint32_t expected_end_time;
/* Pull out the expected end time */
expected_end_time = *(uint32_t *)cb_data;
/*
* Check the callback time (now) matches the time
* we expected the callback.
*/
if (atomTimeGet() == expected_end_time)
{
/* Called back when we expected, post sem1 to notify success */
atomSemPut(&sem1);
}
else
{
/*
* Not called at expected time, don't post sem1 and the test
* thread will time out, signifying an error.
*/
}
}

183
tests/timer4.c Normal file
View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtimer.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_TIMER timer_cb[4];
/* Global test data */
static uint32_t cb_ticks[4];
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start timer test.
*
* This test exercises the atomTimerRegister() API, particularly the
* linked lists used internally for managing an ordered list of timers.
*
* Several timers are registered out of order (in terms of the callback
* time) and we check that the callbacks are called at the expected
* times.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/*
* Fill out four timer request structures. Callbacks are
* requested starting in one second, with the others
* at 1 tick intervals thereafter.
*/
for (i = 0; i < 4; i++)
{
/*
* testCallback() is passed the expected
* callback time via cb_data.
*/
cb_ticks[i] = SYSTEM_TICKS_PER_SEC + i;
timer_cb[i].cb_ticks = cb_ticks[i];
timer_cb[i].cb_func = testCallback;
timer_cb[i].cb_data = &cb_ticks[i];
}
/* Register the timers in a different order */
if (atomTimerRegister (&timer_cb[1]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg1\n"));
failures++;
}
else if (atomTimerRegister (&timer_cb[3]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg3\n"));
failures++;
}
else if (atomTimerRegister (&timer_cb[2]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg2\n"));
failures++;
}
else if (atomTimerRegister (&timer_cb[0]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg0\n"));
failures++;
}
else
{
/* Successfully registered timers */
/* Wait two seconds for callbacks to complete */
if (atomTimerDelay(2 * SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Wait\n"));
failures++;
}
else
{
/*
* The callbacks should have cleared down cb_ticks[x]
* to zero if they were called at the expected
* system time.
*/
for (i = 0; i < 4; i++)
{
/* Check the callback has zeroed the area */
if (cb_ticks[i] != 0)
{
ATOMLOG (_STR("Clear%d\n"), i);
failures++;
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Check the time at which this timer callback occurs matches
* the time we expected. Clear down the expected time location
* if correct.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
uint32_t expected_end_time;
/* Pull out the expected end time */
expected_end_time = *(uint32_t *)cb_data;
/*
* Check the callback time (now) matches the time
* we expected the callback.
*/
if (atomTimeGet() == expected_end_time)
{
/* Called back when we expected, clear the passed location */
*(uint32_t *)cb_data = 0;
}
else
{
/* Not called at expected time, don't clear the location */
}
}

150
tests/timer5.c Normal file
View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomsem.h"
#include "atomtimer.h"
#include "atomtests.h"
/* Global test data */
static volatile int callback_ran_flag;
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start timer test.
*
* This test exercises the atomTimerCancel() API. It tests that bad
* parameters are trapped, and that it can be used to cancel an
* in-progress timer callback request.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
ATOM_TIMER timer_cb;
/* Default to zero failures */
failures = 0;
/* Test parameter checks */
if (atomTimerCancel(NULL) != ATOM_ERR_PARAM)
{
ATOMLOG (_STR("Param\n"));
failures++;
}
/* Test cancel when timer not registered */
if (atomTimerCancel(&timer_cb) != ATOM_ERR_NOT_FOUND)
{
ATOMLOG (_STR("NotFound\n"));
failures++;
}
/* Test a callback can be cancelled */
callback_ran_flag = FALSE;
/* Request a callback in one second, no callback param required */
timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC;
timer_cb.cb_func = testCallback;
/* Register the timer callback */
if (atomTimerRegister (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg\n"));
failures++;
}
else
{
/* Successfully registered for one second's time */
/* Cancel the callback */
if (atomTimerCancel (&timer_cb) != ATOM_OK)
{
ATOMLOG (_STR("TimerCancel\n"));
failures++;
}
else
{
/* Successfully cancelled the callback */
/* Wait two seconds, and check callback did not occur */
if (atomTimerDelay(2 * SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Wait\n"));
failures++;
}
else
{
/* The ran flag should still be FALSE */
if (callback_ran_flag != FALSE)
{
ATOMLOG (_STR("Called back\n"));
failures++;
}
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Set a flag to say we ran. Expected not to run for a pass.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
/* Callback was called */
callback_ran_flag = TRUE;
}

165
tests/timer6.c Normal file
View File

@@ -0,0 +1,165 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtimer.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_TIMER timer_cb[4];
/* Global test data */
static int callback_ran_flag[4];
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start timer test.
*
* This test exercises the atomTimerCancel() API, particularly its
* behaviour when there are several timers registered. Four timers
* are registered, two of which are cancelled, and the test confirms
* that only the two which are not cancelled are called back.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
int failures;
int i;
/* Default to zero failures */
failures = 0;
/* Clear down the ran flag for all four timers */
for (i = 0; i < 4; i++)
{
callback_ran_flag[i] = FALSE;
}
/*
* Fill out four timer request structures. Callbacks are
* requested starting in one second, with the others
* at 1 tick intervals thereafter.
*/
for (i = 0; i < 4; i++)
{
/*
* testCallback() is passed a pointer to the flag it
* should set to notify that it has run.
*/
timer_cb[i].cb_ticks = SYSTEM_TICKS_PER_SEC + i;
timer_cb[i].cb_func = testCallback;
timer_cb[i].cb_data = &callback_ran_flag[i];
}
/* Register all four timers */
for (i = 0; i < 4; i++)
{
if (atomTimerRegister (&timer_cb[i]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg\n"));
failures++;
}
}
/* Check timers were successfully created */
if (failures == 0)
{
/* Cancel two of the callbacks */
if (atomTimerCancel (&timer_cb[1]) != ATOM_OK)
{
ATOMLOG (_STR("Cancel1\n"));
failures++;
}
if (atomTimerCancel (&timer_cb[2]) != ATOM_OK)
{
ATOMLOG (_STR("Cancel2\n"));
failures++;
}
/* Wait two seconds for callbacks to complete */
if (atomTimerDelay(2 * SYSTEM_TICKS_PER_SEC) != ATOM_OK)
{
ATOMLOG (_STR("Wait\n"));
failures++;
}
else
{
/*
* We should now find that timer callbacks 0 and 3
* have run, but 1 and 2 did not (due to cancellation).
*/
if ((callback_ran_flag[0] != TRUE) || (callback_ran_flag[3] != TRUE)
|| (callback_ran_flag[1] != FALSE) || (callback_ran_flag[2] != FALSE))
{
ATOMLOG (_STR("Cancellations\n"));
failures++;
}
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Set a flag to say we ran. Some of the callbacks are
* expected to execute this, while those that are
* cancelled should not.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
/* Callback was called */
*(int *)cb_data = TRUE;
}

183
tests/timer7.c Normal file
View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomtests.h"
/* Test OS objects */
static ATOM_TIMER timer_cb[4];
/* Global test data */
static volatile uint32_t cb_order[4];
static int cb_cnt = 0;
static uint32_t cb_time[4];
/* Forward declarations */
static void testCallback (POINTER cb_data);
/**
* \b test_start
*
* Start timer test.
*
* Test the behaviour of the timer subsystem on a system clock rollover.
*
* Sets the system clock to just before rollover and registers several
* timers. Tests that all timer callbacks occur and that they occur in
* in the correct order, when they span a timer rollover.
*
* @retval Number of failures
*/
uint32_t test_start (void)
{
CRITICAL_STORE;
int i, failures;
/* Default to zero failures */
failures = 0;
/*
* Lockout interrupts while registering to ensure that the clock does
* not roll over under us while we are registering our test timers.
*/
CRITICAL_START ();
/* Set the clock to rollover - 6 */
atomTimeSet (0xFFFFFFFA);
/* Timer in 2 ticks (pre-rollover): should be called back first */
timer_cb[0].cb_ticks = 2;
timer_cb[0].cb_func = testCallback;
timer_cb[0].cb_data = (POINTER)0;
if (atomTimerRegister (&timer_cb[0]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg0\n"));
failures++;
}
/* Timer in 10 ticks (post-rollover): should be called back last */
timer_cb[1].cb_ticks = 10;
timer_cb[1].cb_func = testCallback;
timer_cb[1].cb_data = (POINTER)3;
if (atomTimerRegister (&timer_cb[1]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg1\n"));
failures++;
}
/* Timer in 4 ticks (pre-rollover): should be called back second */
timer_cb[2].cb_ticks = 4;
timer_cb[2].cb_func = testCallback;
timer_cb[2].cb_data = (POINTER)1;
if (atomTimerRegister (&timer_cb[2]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg2\n"));
failures++;
}
/* Timer in 9 ticks (post-rollover): should be called back third */
timer_cb[3].cb_ticks = 9;
timer_cb[3].cb_func = testCallback;
timer_cb[3].cb_data = (POINTER)2;
if (atomTimerRegister (&timer_cb[3]) != ATOM_OK)
{
ATOMLOG (_STR("TimerReg3\n"));
failures++;
}
/* Initialise the cb_order delay to known values */
for (i = 0; i < 4; i++)
{
cb_order[i] = 99;
}
/* Unlock interrupts and let the test begin */
CRITICAL_END ();
/*
* Wait 20 ticks for the callbacks to complete. Also tests another
* timer registration via atomTimerDelay() for us.
*/
atomTimerDelay (20);
/* Check the order the callbacks came in matched our expectations */
for (i = 0; i < 4; i++)
{
if (cb_order[i] != i)
{
ATOMLOG (_STR("T%d=%d\n"), i, cb_order[i]);
failures++;
}
}
/* Log final status */
if (failures == 0)
{
ATOMLOG (_STR("Pass\n"));
}
else
{
ATOMLOG (_STR("Fail(%d)\n"), failures);
}
/* Quit */
return failures;
}
/**
* \b testCallback
*
* Timer callback. Store our cb_data value in cb_order[].
* This allows us to check that the callback order was as expectd.
*
* @param[in] cb_data Not used
*/
static void testCallback (POINTER cb_data)
{
int expected_order;
/* Pull out the expected ordere */
expected_order = (int)cb_data;
/* Store our callback order in cb_order[] */
cb_order[cb_cnt] = expected_order;
/* Store the current time for debug purposes */
cb_time[cb_cnt] = atomTimeGet();
/* Interrupts are locked out so we can modify cb_cnt without protection */
cb_cnt++;
}