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