mirror of
https://github.com/kelvinlawson/atomthreads.git
synced 2026-02-26 00:23:16 +01:00
Add Atomthreads RTOS source files.
This commit is contained in:
60
tests/atomtests.h
Normal file
60
tests/atomtests.h
Normal 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
120
tests/kern1.c
Normal 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
198
tests/kern2.c
Normal 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
213
tests/kern3.c
Normal 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
241
tests/kern4.c
Normal 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
331
tests/mutex1.c
Normal 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
299
tests/mutex2.c
Normal 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
263
tests/mutex3.c
Normal 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
266
tests/mutex4.c
Normal 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
271
tests/mutex5.c
Normal 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
262
tests/mutex6.c
Normal 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
236
tests/mutex7.c
Normal 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
200
tests/mutex8.c
Normal 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
187
tests/mutex9.c
Normal 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
158
tests/queue1.c
Normal 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
218
tests/queue10.c
Normal 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
277
tests/queue2.c
Normal 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
317
tests/queue3.c
Normal 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
293
tests/queue4.c
Normal 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
276
tests/queue5.c
Normal 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
241
tests/queue6.c
Normal 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
201
tests/queue7.c
Normal 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
118
tests/queue8.c
Normal 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
265
tests/queue9.c
Normal 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
343
tests/sem1.c
Normal 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
334
tests/sem2.c
Normal 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
253
tests/sem3.c
Normal 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
254
tests/sem4.c
Normal 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
195
tests/sem5.c
Normal 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
201
tests/sem6.c
Normal 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
278
tests/sem7.c
Normal 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
292
tests/sem8.c
Normal 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
193
tests/sem9.c
Normal 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
62
tests/test-template.c
Normal 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
258
tests/timer1.c
Normal 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
176
tests/timer2.c
Normal 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
252
tests/timer3.c
Normal 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
183
tests/timer4.c
Normal 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
150
tests/timer5.c
Normal 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
165
tests/timer6.c
Normal 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
183
tests/timer7.c
Normal 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++;
|
||||
}
|
||||
Reference in New Issue
Block a user