/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; /* Compiler warnings */ param = param; /* * 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); } }
/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; /* Compiler warnings */ param = param; /* 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); } }
void uartProcess_thread_func (uint32_t param) { volatile uint32_t use=0,free=0; while (1) { //wait forever if (atomSemGet(&uart3Rxsem, 0) == ATOM_OK) { #ifdef GPS atomMutexGet (&gpsDatamutex,0); for (uint8_t i=0;i<rxDataBuff.len;i++) { GPSData.buff[i] = rxDataBuff.buff[i]; } atomMutexPut (&gpsDatamutex); atomSemPut (&gpsDatasem); #endif #ifdef CLI //UART send data to cli for (uint8_t i=0;i<rxDataBuff.len;i++) { cmdData.buff[i] = rxDataBuff.buff[i]; } cmdData.bufflen = rxDataBuff.len; atomSemPut (&cmdShellsem); #endif //get the used RAM atomThreadStackCheck (&uartProcess_tcb, (uint32_t*)&use, (uint32_t*)&free); taskState.taskRAMMax[uartProcess_tcb.threadNum][0]=(uint16_t)use; taskState.taskRAMMax[uartProcess_tcb.threadNum][1]=(uint16_t)free; } } }
/** * \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 */ } }
//TODO: Think better way to do I/O. //I/O thread? int uart_getchar(FILE *stream) { char ret = 0; loop_until_bit_is_set(REG_UCSRA, RXC0); if (atomMutexGet(&uart_rx_mutex, 0) == ATOM_OK) { ret = REG_UDR; atomMutexPut(&uart_rx_mutex); } return ret; }
/** * \b test_thread_func * * Entry point for test thread. The same thread entry point is used for all * four test threads. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint32_t loop_cnt; uint8_t status; CRITICAL_STORE; /* Compiler warnings */ param = param; /* 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); } }
/** * \b uart_read * * Simple polled UART read. * * @param[in] ptr Pointer to receive buffer * @param[in] len Max bytes to read * * @retval Number of bytes read * */ int uart_read (char *ptr, int len) { int todo = 0; /* Check we are initialised */ if (initialised == FALSE) { uart_init(); } /* Check parameters */ if ((ptr == NULL) || (len == 0)) { return 0; } /* Block thread on private access to the UART */ if (atomMutexGet(&uart_mutex, 0) == ATOM_OK) { /* Wait for not-empty */ while(UART_FR(UART0_ADDR) & UART_FR_RXFE) ; /* Read first byte */ *ptr++ = UART_DR(UART0_ADDR); /* Loop over remaining bytes until empty */ for (todo = 1; todo < len; todo++) { /* Quit if receive FIFO empty */ if(UART_FR(UART0_ADDR) & UART_FR_RXFE) { break; } /* Read next byte */ *ptr++ = UART_DR(UART0_ADDR); } /* Return mutex access */ atomMutexPut(&uart_mutex); } /* Return number of bytes read */ return todo; }
/* * Send character c down the UART Tx, wait until tx holding register * is empty. */ int uart_putchar(char c, FILE *stream) { /* Block on private access to the UART */ if (atomMutexGet(&uart_tx_mutex, 0) == ATOM_OK) { /* Convert \n to \r\n */ if (c == '\n') uart_putchar('\r', stream); /* Wait until the UART is ready then send the character out */ loop_until_bit_is_set(REG_UCSRA, BIT_UDRE); REG_UDR = c; /* Return mutex access */ atomMutexPut(&uart_tx_mutex); } return 0; }
/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; /* Compiler warnings */ param = param; /* 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); } }
/** * \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] param Thread number (1,2,3,4) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t thread_id; /* Thread ID is passed through the function parameter */ thread_id = (uint8_t)param; /* * 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); } }
/** * \b uart_write * * Simple polled UART write. * * @param[in] ptr Pointer to write buffer * @param[in] len Number of bytes to write * * @retval Number of bytes written */ int uart_write (const char *ptr, int len) { int todo; /* Check we are initialised */ if (initialised == FALSE) { uart_init(); } /* Check parameters */ if ((ptr == NULL) || (len == 0)) { return 0; } /* Block thread on private access to the UART */ if (atomMutexGet(&uart_mutex, 0) == ATOM_OK) { /* Loop through all bytes to write */ for (todo = 0; todo < len; todo++) { /* Wait for empty */ while(UART_FR(UART0_ADDR) & UART_FR_TXFF) ; /* Write byte to UART */ UART_DR(UART0_ADDR) = *ptr++; } /* Return mutex access */ atomMutexPut(&uart_mutex); } /* Return bytes-written count */ return len; }
void clock_update_func (uint32_t data) { while(1) { // Increment time (global variables protected by mutex lock) if (atomMutexGet(&clock_mutex, 0) == ATOM_OK) { g_sec++; if (g_sec > 59) { g_sec = 0; g_min++; if (g_min > 59) { g_min = 0; g_hour++; if (g_hour > 23) g_hour = 0; } } } atomMutexPut(&clock_mutex); atomTimerDelay(100); } }
/** * \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(&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++; } /* 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++; } /* 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 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(&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 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++; } } /* 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 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_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(&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 mutex */ 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 mutex */ 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 mutex */ 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 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++; } } /* 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 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(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread\n")); CRITICAL_START (); g_failures++; CRITICAL_END (); } /* Create Thread 2 */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 2, &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread\n")); CRITICAL_START (); g_failures++; CRITICAL_END (); } /* Create Thread 3 */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread\n")); CRITICAL_START (); g_failures++; CRITICAL_END (); } /* Create Thread 4 */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != 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 (); } } /* 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")); g_failures++; } else { /* Check the thread did not use up to the end of stack */ if (free_bytes == 0) { ATOMLOG (_STR("StackOverflow %d\n"), thread); g_failures++; } /* Log the stack usage */ #ifdef TESTS_LOG_STACK_USAGE ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes); #endif } } } #endif /* Quit */ return g_failures; }