/** * \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] param Thread number (1,2,3) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t thread_id; uint32_t start_time, end_time; /* Thread ID is passed through the function parameter */ thread_id = (uint8_t)param; /* * 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]++; } } } }
/** * \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(&tcb[0], TEST_THREAD_PRIO, 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++; } /* * 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++; } } /* 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_thread_func * * Entry point for test thread. * * @param[in] param Thread ID (0 to 3) * * @return None */ static void test_thread_func (uint32_t param) { int thread_id, expected_thread; int time_error, thread_error; uint32_t new_time; CRITICAL_STORE; /* Pull out thread ID */ thread_id = (int)param; /* 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); } } } }