Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "mbed.h"
00017 #include "greentea-client/test_env.h"
00018 #include "unity.h"
00019 #include "utest.h"
00020 #include "rtos.h"
00021 
00022 using namespace utest::v1;
00023 
00024 #if defined(MBED_RTOS_SINGLE_THREAD)
00025   #error [NOT_SUPPORTED] test not supported
00026 #endif
00027 
00028 #define THREAD_DELAY     30
00029 #define SEMAPHORE_SLOTS  2
00030 #define SEM_CHANGES      100
00031 #define SHORT_WAIT       5
00032 
00033 #define THREAD_STACK_SIZE 320 /* larger stack cause out of heap memory on some 16kB RAM boards in multi thread test*/
00034 
00035 Semaphore two_slots(SEMAPHORE_SLOTS);
00036 
00037 volatile int change_counter = 0;
00038 volatile int sem_counter = 0;
00039 volatile bool sem_defect = false;
00040 
00041 void test_thread(int const *delay)
00042 {
00043     const int thread_delay = *delay;
00044     while (true) {
00045         two_slots.wait();
00046         sem_counter++;
00047         const bool sem_lock_failed = sem_counter > SEMAPHORE_SLOTS;
00048         if (sem_lock_failed) {
00049             sem_defect = true;
00050         }
00051         Thread::wait(thread_delay);
00052         sem_counter--;
00053         change_counter++;
00054         two_slots.release();
00055     }
00056 }
00057 
00058 /* Test multiple threads
00059 
00060     Given 3 threads started with different delays and a semaphore with 2 tokens
00061     when each thread runs it tries to acquire a token
00062     then no more than two threads should be able to access protected region
00063 */
00064 void test_multi()
00065 {
00066     const int t1_delay = THREAD_DELAY * 1;
00067     const int t2_delay = THREAD_DELAY * 2;
00068     const int t3_delay = THREAD_DELAY * 3;
00069 
00070     Thread t1(osPriorityNormal, THREAD_STACK_SIZE);
00071     Thread t2(osPriorityNormal, THREAD_STACK_SIZE);
00072     Thread t3(osPriorityNormal, THREAD_STACK_SIZE);
00073 
00074     t1.start(callback(test_thread, &t1_delay));
00075     t2.start(callback(test_thread, &t2_delay));
00076     t3.start(callback(test_thread, &t3_delay));
00077 
00078     while (true) {
00079         if (change_counter >= SEM_CHANGES or sem_defect == true) {
00080             t1.terminate();
00081             t2.terminate();
00082             t3.terminate();
00083             break;
00084         }
00085     }
00086 }
00087 
00088 struct thread_data {
00089     Semaphore *sem;
00090     uint32_t data;
00091 };
00092 
00093 void single_thread(struct thread_data *data)
00094 {
00095     int32_t cnt = data->sem->wait();
00096     TEST_ASSERT_EQUAL(1, cnt);
00097     data->data++;
00098 }
00099 
00100 /** Test single thread
00101 
00102     Given a two threads A & B and a semaphore (with count of 0) and a counter (equals to 0)
00103     when thread B calls @a wait
00104     then thread B waits for a token to become available
00105     then the counter is equal to 0
00106     when thread A calls @a release on the semaphore
00107     then thread B acquires a token and increments the counter
00108     then the counter equals to 1
00109  */
00110 void test_single_thread()
00111 {
00112     Thread t(osPriorityNormal, THREAD_STACK_SIZE);
00113     Semaphore sem(0);
00114     struct thread_data data;
00115     osStatus res;
00116 
00117     data.sem = &sem;
00118     data.data = 0;
00119 
00120     res = t.start(callback(single_thread, &data));
00121     TEST_ASSERT_EQUAL(osOK, res);
00122     Thread::wait(SHORT_WAIT);
00123 
00124     TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
00125     TEST_ASSERT_EQUAL(0, data.data);
00126 
00127     res = sem.release();
00128     TEST_ASSERT_EQUAL(osOK, res);
00129 
00130     Thread::wait(SHORT_WAIT);
00131 
00132     TEST_ASSERT_EQUAL(1, data.data);
00133 
00134     t.join();
00135 }
00136 
00137 void timeout_thread(Semaphore *sem)
00138 {
00139     int32_t cnt = sem->wait(30);
00140     TEST_ASSERT_EQUAL(0, cnt);
00141 }
00142 
00143 /** Test timeout
00144 
00145     Given thread and a semaphore with no tokens available
00146     when thread calls @a wait on the semaphore with timeout of 10ms
00147     then the thread waits for 10ms and timeouts after
00148  */
00149 void test_timeout()
00150 {
00151     Thread t(osPriorityNormal, THREAD_STACK_SIZE);
00152     Semaphore sem(0);
00153     osStatus res;
00154 
00155     Timer timer;
00156     timer.start();
00157     res = t.start(callback(timeout_thread, &sem));
00158     TEST_ASSERT_EQUAL(osOK, res);
00159     Thread::wait(SHORT_WAIT);
00160 
00161     TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
00162 
00163     t.join();
00164     TEST_ASSERT_UINT32_WITHIN(5000, 30000, timer.read_us());
00165 }
00166 
00167 /** Test no timeouts
00168 
00169 Test 1 token no timeout
00170 Given thread and a semaphore with one token available
00171 when thread calls @a wait on the semaphore with timeout of 0ms
00172 then the thread acquires the token immediately
00173 
00174 Test 0 tokens no timeout
00175 Given thread and a semaphore with no tokens available
00176 when thread calls @a wait on the semaphore with timeout of 0ms
00177 then the thread returns immediately without acquiring a token
00178  */
00179 template<int T>
00180 void test_no_timeout()
00181 {
00182     Semaphore sem(T);
00183 
00184     Timer timer;
00185     timer.start();
00186 
00187     int32_t cnt = sem.wait(0);
00188     TEST_ASSERT_EQUAL(T, cnt);
00189 
00190     TEST_ASSERT_UINT32_WITHIN(5000, 0, timer.read_us());
00191 }
00192 
00193 /** Test multiple tokens wait
00194 
00195     Given a thread and a semaphore initialized with 5 tokens
00196     when thread calls @a wait 6 times on the semaphore
00197     then the token counts goes to zero
00198  */
00199 void test_multiple_tokens_wait()
00200 {
00201     Semaphore sem(5);
00202 
00203     for(int i = 5; i >= 0; i--) {
00204         int32_t cnt = sem.wait(0);
00205         TEST_ASSERT_EQUAL(i, cnt);
00206     }
00207 }
00208 
00209 /** Test multiple tokens release
00210 
00211     Given a thread and a semaphore initialized with zero tokens and max of 5
00212     when thread calls @a release 6 times on the semaphore
00213     then the token count should be equal to 5 and last release call should fail
00214  */
00215 void test_multiple_tokens_release()
00216 {
00217     Semaphore sem(0, 5);
00218 
00219     for(int i = 5; i > 0; i--) {
00220         osStatus stat = sem.release();
00221         TEST_ASSERT_EQUAL(osOK, stat);
00222     }
00223     osStatus stat = sem.release();
00224     TEST_ASSERT_EQUAL(osErrorResource, stat);
00225 }
00226 
00227 utest::v1::status_t test_setup(const size_t number_of_cases)
00228 {
00229     GREENTEA_SETUP(10, "default_auto");
00230     return verbose_test_setup_handler(number_of_cases);
00231 }
00232 
00233 Case cases[] = {
00234     Case("Test single thread", test_single_thread),
00235     Case("Test timeout", test_timeout),
00236     Case("Test 1 token no timeout", test_no_timeout<1>),
00237     Case("Test 0 tokens no timeout", test_no_timeout<0>),
00238     Case("Test multiple tokens wait", test_multiple_tokens_wait),
00239     Case("Test multiple tokens release", test_multiple_tokens_release),
00240     Case("Test multiple threads", test_multi)
00241 };
00242 
00243 Specification specification(test_setup, cases);
00244 
00245 int main()
00246 {
00247     return !Harness::run(specification);
00248 }