2016-07-19 18:39:53 +00:00
|
|
|
#include "mbed.h"
|
|
|
|
#include "greentea-client/test_env.h"
|
2017-02-15 19:59:26 +00:00
|
|
|
#include "unity.h"
|
|
|
|
#include "utest.h"
|
2016-07-19 18:39:53 +00:00
|
|
|
#include "rtos.h"
|
|
|
|
|
2016-07-25 10:41:00 +00:00
|
|
|
#if defined(MBED_RTOS_SINGLE_THREAD)
|
|
|
|
#error [NOT_SUPPORTED] test not supported
|
|
|
|
#endif
|
|
|
|
|
2017-02-15 19:59:26 +00:00
|
|
|
using namespace utest::v1;
|
2016-07-19 18:39:53 +00:00
|
|
|
|
2017-02-15 19:59:26 +00:00
|
|
|
#define TEST_STACK_SIZE 512
|
2016-07-19 18:39:53 +00:00
|
|
|
|
2017-02-15 19:59:26 +00:00
|
|
|
#define TEST_ONE_SEC_MS (1000)
|
|
|
|
#define TEST_HALF_SEC_MS (500)
|
|
|
|
#define TEST_HALF_SEC_US (500000)
|
|
|
|
#define TEST_ONE_MS_US (1000)
|
|
|
|
|
|
|
|
#define THREAD_DELAY 50
|
|
|
|
#define SIGNALS_TO_EMIT 100
|
2016-07-19 18:39:53 +00:00
|
|
|
|
|
|
|
Mutex stdio_mutex;
|
|
|
|
|
|
|
|
volatile int change_counter = 0;
|
|
|
|
volatile bool changing_counter = false;
|
|
|
|
volatile bool mutex_defect = false;
|
|
|
|
|
|
|
|
bool manipulate_protected_zone(const int thread_delay) {
|
|
|
|
bool result = true;
|
|
|
|
|
2017-02-15 19:59:26 +00:00
|
|
|
osStatus stat = stdio_mutex.lock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
2016-07-19 18:39:53 +00:00
|
|
|
if (changing_counter == true) {
|
|
|
|
result = false;
|
|
|
|
mutex_defect = true;
|
|
|
|
}
|
|
|
|
changing_counter = true;
|
|
|
|
|
|
|
|
change_counter++;
|
|
|
|
Thread::wait(thread_delay);
|
|
|
|
|
|
|
|
changing_counter = false;
|
2017-02-15 19:59:26 +00:00
|
|
|
stat = stdio_mutex.unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
2016-07-19 18:39:53 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-12-21 13:46:09 +00:00
|
|
|
void test_thread(int const *thread_delay) {
|
2016-07-19 18:39:53 +00:00
|
|
|
while (true) {
|
2016-12-21 13:46:09 +00:00
|
|
|
manipulate_protected_zone(*thread_delay);
|
2016-07-19 18:39:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-15 19:59:26 +00:00
|
|
|
void test_multiple_threads(void)
|
|
|
|
{
|
2016-07-19 18:39:53 +00:00
|
|
|
const int t1_delay = THREAD_DELAY * 1;
|
|
|
|
const int t2_delay = THREAD_DELAY * 2;
|
|
|
|
const int t3_delay = THREAD_DELAY * 3;
|
2017-02-15 19:59:26 +00:00
|
|
|
|
|
|
|
Thread t2(osPriorityNormal, TEST_STACK_SIZE);
|
|
|
|
Thread t3(osPriorityNormal, TEST_STACK_SIZE);
|
2016-12-21 13:46:09 +00:00
|
|
|
|
|
|
|
t2.start(callback(test_thread, &t2_delay));
|
|
|
|
t3.start(callback(test_thread, &t3_delay));
|
2016-07-19 18:39:53 +00:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
// Thread 1 action
|
|
|
|
Thread::wait(t1_delay);
|
|
|
|
manipulate_protected_zone(t1_delay);
|
2017-02-15 19:59:26 +00:00
|
|
|
|
2016-07-19 18:39:53 +00:00
|
|
|
if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) {
|
|
|
|
t2.terminate();
|
|
|
|
t3.terminate();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-15 19:59:26 +00:00
|
|
|
TEST_ASSERT_EQUAL(mutex_defect, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_dual_thread_nolock_lock_thread(Mutex *mutex)
|
|
|
|
{
|
|
|
|
bool stat_b = mutex->trylock();
|
|
|
|
TEST_ASSERT_EQUAL(stat_b, true);
|
|
|
|
|
|
|
|
osStatus stat = mutex->unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_dual_thread_nolock_trylock_thread(Mutex *mutex)
|
|
|
|
{
|
|
|
|
bool stat_b = mutex->trylock();
|
|
|
|
TEST_ASSERT_EQUAL(stat_b, true);
|
|
|
|
|
|
|
|
osStatus stat = mutex->unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <void (*F)(Mutex *)>
|
|
|
|
void test_dual_thread_nolock(void)
|
|
|
|
{
|
|
|
|
Mutex mutex;
|
2017-05-14 23:55:19 +00:00
|
|
|
Thread thread(osPriorityNormal, TEST_STACK_SIZE);
|
2017-02-15 19:59:26 +00:00
|
|
|
|
|
|
|
thread.start(callback(F, &mutex));
|
|
|
|
|
|
|
|
wait_us(TEST_HALF_SEC_MS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_dual_thread_lock_unlock_thread(Mutex *mutex)
|
|
|
|
{
|
|
|
|
osStatus stat = mutex->lock(osWaitForever);
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_dual_thread_lock_unlock(void)
|
|
|
|
{
|
|
|
|
Mutex mutex;
|
|
|
|
osStatus stat;
|
|
|
|
Thread thread(osPriorityNormal, TEST_STACK_SIZE);
|
|
|
|
|
|
|
|
stat = mutex.lock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
|
|
|
|
thread.start(callback(test_dual_thread_lock_unlock_thread, &mutex));
|
|
|
|
|
|
|
|
stat = mutex.unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
|
|
|
|
wait_us(TEST_HALF_SEC_MS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_dual_thread_lock_trylock_thread(Mutex *mutex)
|
|
|
|
{
|
|
|
|
bool stat = mutex->trylock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_dual_thread_lock_lock_thread(Mutex *mutex)
|
|
|
|
{
|
|
|
|
uint32_t start = us_ticker_read();
|
|
|
|
|
|
|
|
osStatus stat = mutex->lock(TEST_HALF_SEC_MS);
|
2017-05-15 14:55:45 +00:00
|
|
|
TEST_ASSERT_EQUAL(stat, osErrorTimeout);
|
2017-02-15 19:59:26 +00:00
|
|
|
TEST_ASSERT_UINT32_WITHIN(TEST_ONE_MS_US, TEST_HALF_SEC_US, us_ticker_read() - start);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <void (*F)(Mutex *)>
|
|
|
|
void test_dual_thread_lock(void)
|
|
|
|
{
|
|
|
|
Mutex mutex;
|
|
|
|
osStatus stat;
|
|
|
|
Thread thread(osPriorityNormal, TEST_STACK_SIZE);
|
|
|
|
|
|
|
|
stat = mutex.lock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
|
|
|
|
thread.start(callback(F, &mutex));
|
|
|
|
|
|
|
|
wait_us(TEST_ONE_SEC_MS);
|
|
|
|
|
|
|
|
stat = mutex.unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_single_thread_lock_recursive(void)
|
|
|
|
{
|
|
|
|
Mutex mutex;
|
|
|
|
osStatus stat;
|
|
|
|
|
|
|
|
stat = mutex.lock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
|
|
|
|
stat = mutex.lock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
|
|
|
|
stat = mutex.unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
|
|
|
|
stat = mutex.unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_single_thread_trylock(void)
|
|
|
|
{
|
|
|
|
Mutex mutex;
|
|
|
|
|
|
|
|
bool stat_b = mutex.trylock();
|
|
|
|
TEST_ASSERT_EQUAL(stat_b, true);
|
|
|
|
|
|
|
|
osStatus stat = mutex.unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_single_thread_lock(void)
|
|
|
|
{
|
|
|
|
Mutex mutex;
|
|
|
|
osStatus stat;
|
|
|
|
|
|
|
|
stat = mutex.lock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
|
|
|
|
stat = mutex.unlock();
|
|
|
|
TEST_ASSERT_EQUAL(stat, osOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
utest::v1::status_t test_setup(const size_t number_of_cases) {
|
|
|
|
GREENTEA_SETUP(15, "default_auto");
|
|
|
|
return verbose_test_setup_handler(number_of_cases);
|
|
|
|
}
|
|
|
|
|
|
|
|
Case cases[] = {
|
|
|
|
Case("Test single thread lock", test_single_thread_lock),
|
|
|
|
Case("Test single thread trylock", test_single_thread_trylock),
|
|
|
|
Case("Test single thread lock recursive", test_single_thread_lock_recursive),
|
|
|
|
Case("Test dual thread lock locked", test_dual_thread_lock<test_dual_thread_lock_lock_thread>),
|
|
|
|
Case("Test dual thread trylock locked", test_dual_thread_lock<test_dual_thread_lock_trylock_thread>),
|
|
|
|
Case("Test dual thread lock unlock", test_dual_thread_lock_unlock),
|
|
|
|
Case("Test dual thread second thread lock", test_dual_thread_nolock<test_dual_thread_nolock_lock_thread>),
|
|
|
|
Case("Test dual thread second thread trylock", test_dual_thread_nolock<test_dual_thread_nolock_trylock_thread>),
|
|
|
|
Case("Test multiple thread", test_multiple_threads),
|
|
|
|
};
|
|
|
|
|
|
|
|
Specification specification(test_setup, cases);
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
return !Harness::run(specification);
|
2016-07-19 18:39:53 +00:00
|
|
|
}
|