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