mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Test: RTOS: Semaphore: Rework tests
							parent
							
								
									aae62bd990
								
							
						
					
					
						commit
						739a429820
					
				| 
						 | 
				
			
			@ -1,14 +1,19 @@
 | 
			
		|||
#include "mbed.h"
 | 
			
		||||
#include "greentea-client/test_env.h"
 | 
			
		||||
#include "unity.h"
 | 
			
		||||
#include "utest.h"
 | 
			
		||||
#include "rtos.h"
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
 | 
			
		||||
#if defined(MBED_RTOS_SINGLE_THREAD)
 | 
			
		||||
  #error [NOT_SUPPORTED] test not supported
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define THREAD_DELAY     75
 | 
			
		||||
#define THREAD_DELAY     30
 | 
			
		||||
#define SEMAPHORE_SLOTS  2
 | 
			
		||||
#define SEM_CHANGES      100
 | 
			
		||||
#define SHORT_WAIT       5
 | 
			
		||||
 | 
			
		||||
#define THREAD_STACK_SIZE 512
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +23,8 @@ volatile int change_counter = 0;
 | 
			
		|||
volatile int sem_counter = 0;
 | 
			
		||||
volatile bool sem_defect = false;
 | 
			
		||||
 | 
			
		||||
void test_thread(int const *delay) {
 | 
			
		||||
void test_thread(int const *delay)
 | 
			
		||||
{
 | 
			
		||||
    const int thread_delay = *delay;
 | 
			
		||||
    while (true) {
 | 
			
		||||
        two_slots.wait();
 | 
			
		||||
| 
						 | 
				
			
			@ -34,9 +40,14 @@ void test_thread(int const *delay) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main (void) {
 | 
			
		||||
    GREENTEA_SETUP(20, "default_auto");
 | 
			
		||||
/* Test multiple threads
 | 
			
		||||
 | 
			
		||||
    Given 3 threads started with different delays and a semaphore with 2 tokens
 | 
			
		||||
    when each thread runs it tries to acquire a token
 | 
			
		||||
    then no more than two threads should be able to access protected region
 | 
			
		||||
*/
 | 
			
		||||
void test_multi()
 | 
			
		||||
{
 | 
			
		||||
    const int t1_delay = THREAD_DELAY * 1;
 | 
			
		||||
    const int t2_delay = THREAD_DELAY * 2;
 | 
			
		||||
    const int t3_delay = THREAD_DELAY * 3;
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +68,164 @@ int main (void) {
 | 
			
		|||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GREENTEA_TESTSUITE_RESULT(!sem_defect);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct thread_data {
 | 
			
		||||
    Semaphore *sem;
 | 
			
		||||
    uint32_t data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void single_thread(struct thread_data *data)
 | 
			
		||||
{
 | 
			
		||||
    int32_t cnt = data->sem->wait();
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, cnt);
 | 
			
		||||
    data->data++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test single thread
 | 
			
		||||
 | 
			
		||||
    Given a two threads A & B and a semaphore (with count of 0) and a counter (equals to 0)
 | 
			
		||||
    when thread B calls @a wait
 | 
			
		||||
    then thread B waits for a token to become available
 | 
			
		||||
    then the counter is equal to 0
 | 
			
		||||
    when thread A calls @a release on the semaphore
 | 
			
		||||
    then thread B acquires a token and increments the counter
 | 
			
		||||
    then the counter equals to 1
 | 
			
		||||
 */
 | 
			
		||||
void test_single_thread()
 | 
			
		||||
{
 | 
			
		||||
    Thread t(osPriorityNormal, THREAD_STACK_SIZE);
 | 
			
		||||
    Semaphore sem(0);
 | 
			
		||||
    struct thread_data data;
 | 
			
		||||
    osStatus res;
 | 
			
		||||
 | 
			
		||||
    data.sem = &sem;
 | 
			
		||||
    data.data = 0;
 | 
			
		||||
 | 
			
		||||
    res = t.start(callback(single_thread, &data));
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, res);
 | 
			
		||||
    Thread::wait(SHORT_WAIT);
 | 
			
		||||
 | 
			
		||||
    TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, data.data);
 | 
			
		||||
 | 
			
		||||
    res = sem.release();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, res);
 | 
			
		||||
 | 
			
		||||
    Thread::wait(SHORT_WAIT);
 | 
			
		||||
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, data.data);
 | 
			
		||||
 | 
			
		||||
    t.join();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void timeout_thread(Semaphore *sem)
 | 
			
		||||
{
 | 
			
		||||
    int32_t cnt = sem->wait(30);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, cnt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timeout
 | 
			
		||||
 | 
			
		||||
    Given thread and a semaphore with no tokens available
 | 
			
		||||
    when thread calls @a wait on the semaphore with timeout of 10ms
 | 
			
		||||
    then the thread waits for 10ms and timeouts after
 | 
			
		||||
 */
 | 
			
		||||
void test_timeout()
 | 
			
		||||
{
 | 
			
		||||
    Thread t(osPriorityNormal, THREAD_STACK_SIZE);
 | 
			
		||||
    Semaphore sem(0);
 | 
			
		||||
    osStatus res;
 | 
			
		||||
 | 
			
		||||
    uint32_t start = us_ticker_read();
 | 
			
		||||
    res = t.start(callback(timeout_thread, &sem));
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, res);
 | 
			
		||||
    Thread::wait(SHORT_WAIT);
 | 
			
		||||
 | 
			
		||||
    TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
 | 
			
		||||
 | 
			
		||||
    t.join();
 | 
			
		||||
    TEST_ASSERT_UINT32_WITHIN(5000, 30000, us_ticker_read() - start);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test no timeouts
 | 
			
		||||
 | 
			
		||||
Test 1 token no timeout
 | 
			
		||||
Given thread and a semaphore with one token available
 | 
			
		||||
when thread calls @a wait on the semaphore with timeout of 0ms
 | 
			
		||||
then the thread acquires the token immediately
 | 
			
		||||
 | 
			
		||||
Test 0 tokens no timeout
 | 
			
		||||
Given thread and a semaphore with no tokens available
 | 
			
		||||
when thread calls @a wait on the semaphore with timeout of 0ms
 | 
			
		||||
then the thread returns immediately without acquiring a token
 | 
			
		||||
 */
 | 
			
		||||
template<int T>
 | 
			
		||||
void test_no_timeout()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(T);
 | 
			
		||||
 | 
			
		||||
    uint32_t start = us_ticker_read();
 | 
			
		||||
 | 
			
		||||
    int32_t cnt = sem.wait(0);
 | 
			
		||||
    TEST_ASSERT_EQUAL(T, cnt);
 | 
			
		||||
 | 
			
		||||
    TEST_ASSERT_UINT32_WITHIN(5000, 0, us_ticker_read() - start);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test multiple tokens wait
 | 
			
		||||
 | 
			
		||||
    Given a thread and a semaphore initialized with 5 tokens
 | 
			
		||||
    when thread calls @a wait 6 times on the semaphore
 | 
			
		||||
    then the token counts goes to zero
 | 
			
		||||
 */
 | 
			
		||||
void test_multiple_tokens_wait()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(5);
 | 
			
		||||
 | 
			
		||||
    for(int i = 5; i >= 0; i--) {
 | 
			
		||||
        int32_t cnt = sem.wait(0);
 | 
			
		||||
        TEST_ASSERT_EQUAL(i, cnt);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test multiple tokens release
 | 
			
		||||
 | 
			
		||||
    Given a thread and a semaphore initialized with zero tokens and max of 5
 | 
			
		||||
    when thread calls @a release 6 times on the semaphore
 | 
			
		||||
    then the token count should be equal to 5 and last release call should fail
 | 
			
		||||
 */
 | 
			
		||||
void test_multiple_tokens_release()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(0, 5);
 | 
			
		||||
 | 
			
		||||
    for(int i = 5; i > 0; i--) {
 | 
			
		||||
        osStatus stat = sem.release();
 | 
			
		||||
        TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
    }
 | 
			
		||||
    osStatus stat = sem.release();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utest::v1::status_t test_setup(const size_t number_of_cases)
 | 
			
		||||
{
 | 
			
		||||
    GREENTEA_SETUP(10, "default_auto");
 | 
			
		||||
    return verbose_test_setup_handler(number_of_cases);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Case cases[] = {
 | 
			
		||||
    Case("Test single thread", test_single_thread),
 | 
			
		||||
    Case("Test timeout", test_timeout),
 | 
			
		||||
    Case("Test 1 token no timeout", test_no_timeout<1>),
 | 
			
		||||
    Case("Test 0 tokens no timeout", test_no_timeout<0>),
 | 
			
		||||
    Case("Test multiple tokens wait", test_multiple_tokens_wait),
 | 
			
		||||
    Case("Test multiple tokens release", test_multiple_tokens_release),
 | 
			
		||||
    Case("Test multiple threads", test_multi)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Specification specification(test_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    /** Wait until a Semaphore resource becomes available.
 | 
			
		||||
      @param   millisec  timeout value or 0 in case of no time-out. (default: osWaitForever).
 | 
			
		||||
      @return  number of available tokens, or -1 in case of incorrect parameters
 | 
			
		||||
      @return  number of available tokens, before taking one; or -1 in case of incorrect parameters
 | 
			
		||||
    */
 | 
			
		||||
    int32_t wait(uint32_t millisec=osWaitForever);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue