Marco Mayer / Mbed OS Queue
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 #if defined(MBED_RTOS_SINGLE_THREAD)
00023   #error [NOT_SUPPORTED] test not supported
00024 #endif
00025 
00026 using namespace utest::v1;
00027 
00028 #define TEST_STACK_SIZE 512
00029 
00030 #define TEST_LONG_DELAY 20
00031 #define TEST_DELAY 10
00032 #define SIGNALS_TO_EMIT 100
00033 
00034 Mutex stdio_mutex;
00035 
00036 volatile int change_counter = 0;
00037 volatile bool changing_counter = false;
00038 volatile bool mutex_defect = false;
00039 
00040 bool manipulate_protected_zone(const int thread_delay)
00041 {
00042     bool result = true;
00043 
00044     osStatus stat = stdio_mutex.lock();
00045     TEST_ASSERT_EQUAL(osOK, stat);
00046 
00047     core_util_critical_section_enter();
00048     if (changing_counter == true) {
00049         result = false;
00050         mutex_defect = true;
00051     }
00052     changing_counter = true;
00053 
00054     change_counter++;
00055     core_util_critical_section_exit();
00056 
00057     Thread::wait(thread_delay);
00058 
00059     core_util_critical_section_enter();
00060     changing_counter = false;
00061     core_util_critical_section_exit();
00062 
00063     stat = stdio_mutex.unlock();
00064     TEST_ASSERT_EQUAL(osOK, stat);
00065     return result;
00066 }
00067 
00068 void test_thread(int const *thread_delay)
00069 {
00070     while (true) {
00071         manipulate_protected_zone(*thread_delay);
00072     }
00073 }
00074 
00075 /** Test multiple thread
00076 
00077     Given 3 threads started with different delays and a section protected with a mutex
00078     when each thread runs it tries to lock the mutex
00079     then no more than one thread should be able to access protected region
00080 */
00081 void test_multiple_threads(void)
00082 {
00083     const int t1_delay = TEST_DELAY * 1;
00084     const int t2_delay = TEST_DELAY * 2;
00085     const int t3_delay = TEST_DELAY * 3;
00086 
00087     Thread t2(osPriorityNormal, TEST_STACK_SIZE);
00088     Thread t3(osPriorityNormal, TEST_STACK_SIZE);
00089 
00090     t2.start(callback(test_thread, &t2_delay));
00091     t3.start(callback(test_thread, &t3_delay));
00092 
00093     while (true) {
00094         // Thread 1 action
00095         Thread::wait(t1_delay);
00096         manipulate_protected_zone(t1_delay);
00097 
00098         core_util_critical_section_enter();
00099         if (change_counter >= SIGNALS_TO_EMIT or mutex_defect == true) {
00100             core_util_critical_section_exit();
00101             t2.terminate();
00102             t3.terminate();
00103             break;
00104         }
00105         core_util_critical_section_exit();
00106     }
00107 
00108     TEST_ASSERT_EQUAL(false, mutex_defect);
00109 }
00110 
00111 void test_dual_thread_nolock_lock_thread(Mutex *mutex)
00112 {
00113     osStatus stat = mutex->lock(osWaitForever);
00114     TEST_ASSERT_EQUAL(osOK, stat);
00115 
00116     stat = mutex->unlock();
00117     TEST_ASSERT_EQUAL(osOK, stat);
00118 }
00119 
00120 void test_dual_thread_nolock_trylock_thread(Mutex *mutex)
00121 {
00122     bool stat_b = mutex->trylock();
00123     TEST_ASSERT_EQUAL(true, stat_b);
00124 
00125     osStatus stat = mutex->unlock();
00126     TEST_ASSERT_EQUAL(osOK, stat);
00127 }
00128 
00129 /** Test dual thread no-lock
00130 
00131     Test dual thread second thread lock
00132     Given two threads A & B and a mutex
00133     When thread A creates a mutex and starts thread B
00134         and thread B calls @a lock and @a unlock
00135     Then returned statuses are osOK
00136 
00137     Test dual thread second thread trylock
00138     Given two threads A & B and a mutex
00139     When thread A creates a mutex and starts thread B
00140         and thread B calls @a trylock and @a unlock
00141     Then returned statuses are true and osOK
00142 */
00143 template <void (*F)(Mutex *)>
00144 void test_dual_thread_nolock(void)
00145 {
00146     Mutex mutex;
00147     Thread thread(osPriorityNormal, TEST_STACK_SIZE);
00148 
00149     thread.start(callback(F, &mutex));
00150 
00151     wait_ms(TEST_DELAY);
00152 }
00153 
00154 void test_dual_thread_lock_unlock_thread(Mutex *mutex)
00155 {
00156     osStatus stat = mutex->lock(osWaitForever);
00157     TEST_ASSERT_EQUAL(osOK, stat);
00158 }
00159 
00160 /** Test dual thread lock unlock
00161 
00162     Given two threads and a lock
00163     When thread A locks the lock and starts thread B
00164         and thread B calls @a lock on the mutex
00165     Then thread B waits for thread A to unlock the lock
00166     When thread A calls @a unlock on the mutex
00167     Then thread B acquires the lock
00168 */
00169 void test_dual_thread_lock_unlock(void)
00170 {
00171     Mutex mutex;
00172     osStatus stat;
00173     Thread thread(osPriorityNormal, TEST_STACK_SIZE);
00174 
00175     stat = mutex.lock();
00176     TEST_ASSERT_EQUAL(osOK, stat);
00177 
00178     thread.start(callback(test_dual_thread_lock_unlock_thread, &mutex));
00179 
00180     stat = mutex.unlock();
00181     TEST_ASSERT_EQUAL(osOK, stat);
00182 
00183     wait_ms(TEST_DELAY);
00184 }
00185 
00186 void test_dual_thread_lock_trylock_thread(Mutex *mutex)
00187 {
00188     bool stat = mutex->trylock();
00189     TEST_ASSERT_EQUAL(false, stat);
00190 }
00191 
00192 void test_dual_thread_lock_lock_thread(Mutex *mutex)
00193 {
00194     Timer timer;
00195     timer.start();
00196 
00197     osStatus stat = mutex->lock(TEST_DELAY);
00198     TEST_ASSERT_EQUAL(osErrorTimeout, stat);
00199     TEST_ASSERT_UINT32_WITHIN(5000, TEST_DELAY*1000, timer.read_us());
00200 }
00201 
00202 /** Test dual thread lock
00203 
00204     Test dual thread lock locked
00205     Given a mutex and two threads A & B
00206     When thread A calls @a lock and starts thread B
00207         and thread B calls @a lock with 500ms timeout
00208     Then thread B waits 500ms and timeouts
00209 
00210     Test dual thread trylock locked
00211     Given a mutex and two threads A & B
00212     When thread A calls @a lock and starts thread B
00213     Then thread B calls @a trylock
00214         and thread B fails to acquire the lock
00215 */
00216 template <void (*F)(Mutex *)>
00217 void test_dual_thread_lock(void)
00218 {
00219     Mutex mutex;
00220     osStatus stat;
00221     Thread thread(osPriorityNormal, TEST_STACK_SIZE);
00222 
00223     stat = mutex.lock();
00224     TEST_ASSERT_EQUAL(osOK, stat);
00225 
00226     thread.start(callback(F, &mutex));
00227 
00228     wait_ms(TEST_LONG_DELAY);
00229 
00230     stat = mutex.unlock();
00231     TEST_ASSERT_EQUAL(osOK, stat);
00232 }
00233 
00234 /** Test single thread lock recursive
00235 
00236     Given a mutex and a single running thread
00237     When thread calls @a lock twice and @a unlock twice on the mutex
00238     Then the returned statuses are osOK
00239 */
00240 void test_single_thread_lock_recursive(void)
00241 {
00242     Mutex mutex;
00243     osStatus stat;
00244 
00245     stat = mutex.lock();
00246     TEST_ASSERT_EQUAL(osOK, stat);
00247 
00248     stat = mutex.lock();
00249     TEST_ASSERT_EQUAL(osOK, stat);
00250 
00251     stat = mutex.unlock();
00252     TEST_ASSERT_EQUAL(osOK, stat);
00253 
00254     stat = mutex.unlock();
00255     TEST_ASSERT_EQUAL(osOK, stat);
00256 }
00257 
00258 /** Test single thread trylock
00259 
00260     Given a mutex and a single running thread
00261     When thread calls @a trylock and @a unlock on the mutex
00262     Then the returned statuses are osOK
00263 */
00264 void test_single_thread_trylock(void)
00265 {
00266     Mutex mutex;
00267 
00268     bool stat_b = mutex.trylock();
00269     TEST_ASSERT_EQUAL(true, stat_b);
00270 
00271     osStatus stat = mutex.unlock();
00272     TEST_ASSERT_EQUAL(osOK, stat);
00273 }
00274 
00275 /** Test single thread lock
00276 
00277     Given a mutex and a single running thread
00278     When thread calls @a lock and @a unlock on the mutex
00279     Then the returned statuses are osOK
00280 */
00281 void test_single_thread_lock(void)
00282 {
00283     Mutex mutex;
00284     osStatus stat;
00285 
00286     stat = mutex.lock();
00287     TEST_ASSERT_EQUAL(osOK, stat);
00288 
00289     stat = mutex.unlock();
00290     TEST_ASSERT_EQUAL(osOK, stat);
00291 }
00292 
00293 utest::v1::status_t test_setup(const size_t number_of_cases)
00294 {
00295     GREENTEA_SETUP(10, "default_auto");
00296     return verbose_test_setup_handler(number_of_cases);
00297 }
00298 
00299 Case cases[] = {
00300     Case("Test single thread lock", test_single_thread_lock),
00301     Case("Test single thread trylock", test_single_thread_trylock),
00302     Case("Test single thread lock recursive", test_single_thread_lock_recursive),
00303     Case("Test dual thread lock locked", test_dual_thread_lock<test_dual_thread_lock_lock_thread>),
00304     Case("Test dual thread trylock locked", test_dual_thread_lock<test_dual_thread_lock_trylock_thread>),
00305     Case("Test dual thread lock unlock", test_dual_thread_lock_unlock),
00306     Case("Test dual thread second thread lock", test_dual_thread_nolock<test_dual_thread_nolock_lock_thread>),
00307     Case("Test dual thread second thread trylock", test_dual_thread_nolock<test_dual_thread_nolock_trylock_thread>),
00308     Case("Test multiple thread", test_multiple_threads),
00309 };
00310 
00311 Specification specification(test_setup, cases);
00312 
00313 int main()
00314 {
00315     return !Harness::run(specification);
00316 }