/** * \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(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 1\n")); failures++; } /* Create test thread 2 */ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 1, &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 2\n")); failures++; } /* Create test thread 3 */ else if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 2, &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != 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++; } } } } /* Check thread stack usage (if enabled) */ #ifdef ATOM_STACK_CHECKING { uint32_t used_bytes, free_bytes; int thread; /* Check all threads */ for (thread = 0; thread < NUM_TEST_THREADS; thread++) { /* Check thread stack usage */ if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK) { ATOMLOG (_STR("StackCheck\n")); failures++; } else { /* Check the thread did not use up to the end of stack */ if (free_bytes == 0) { ATOMLOG (_STR("StackOverflow %d\n"), thread); failures++; } /* Log the stack usage */ #ifdef TESTS_LOG_STACK_USAGE ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes); #endif } } } #endif /* Quit */ return failures; }
/** * \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(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != 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(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0, &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != 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 */ } } } } } /* Check thread stack usage (if enabled) */ #ifdef ATOM_STACK_CHECKING { uint32_t used_bytes, free_bytes; int thread; /* Check all threads */ for (thread = 0; thread < NUM_TEST_THREADS; thread++) { /* Check thread stack usage */ if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK) { ATOMLOG (_STR("StackCheck\n")); failures++; } else { /* Check the thread did not use up to the end of stack */ if (free_bytes == 0) { ATOMLOG (_STR("StackOverflow %d\n"), thread); failures++; } /* Log the stack usage */ #ifdef TESTS_LOG_STACK_USAGE ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes); #endif } } } #endif /* Quit */ return failures; }
/** * \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(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1, &test_thread_stack[0][0], TEST_THREAD_STACK_SIZE, TRUE) != 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(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2, &test_thread_stack[1][0], TEST_THREAD_STACK_SIZE, TRUE) != 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(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, &test_thread_stack[2][0], TEST_THREAD_STACK_SIZE, TRUE) != 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(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, &test_thread_stack[3][0], TEST_THREAD_STACK_SIZE, TRUE) != 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++; } } /* Check thread stack usage (if enabled) */ #ifdef ATOM_STACK_CHECKING { uint32_t used_bytes, free_bytes; int thread; /* Check all threads */ for (thread = 0; thread < NUM_TEST_THREADS; thread++) { /* Check thread stack usage */ if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK) { ATOMLOG (_STR("StackCheck\n")); failures++; } else { /* Check the thread did not use up to the end of stack */ if (free_bytes == 0) { ATOMLOG (_STR("StackOverflow %d\n"), thread); failures++; } /* Log the stack usage */ #ifdef TESTS_LOG_STACK_USAGE ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes); #endif } } } #endif /* Quit */ return failures; }