Rtos API example

Committer:
marcozecchini
Date:
Sat Feb 23 12:13:36 2019 +0000
Revision:
0:9fca2b23d0ba
final commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
marcozecchini 0:9fca2b23d0ba 1 /* mbed Microcontroller Library
marcozecchini 0:9fca2b23d0ba 2 * Copyright (c) 2017 ARM Limited
marcozecchini 0:9fca2b23d0ba 3 *
marcozecchini 0:9fca2b23d0ba 4 * Licensed under the Apache License, Version 2.0 (the "License");
marcozecchini 0:9fca2b23d0ba 5 * you may not use this file except in compliance with the License.
marcozecchini 0:9fca2b23d0ba 6 * You may obtain a copy of the License at
marcozecchini 0:9fca2b23d0ba 7 *
marcozecchini 0:9fca2b23d0ba 8 * http://www.apache.org/licenses/LICENSE-2.0
marcozecchini 0:9fca2b23d0ba 9 *
marcozecchini 0:9fca2b23d0ba 10 * Unless required by applicable law or agreed to in writing, software
marcozecchini 0:9fca2b23d0ba 11 * distributed under the License is distributed on an "AS IS" BASIS,
marcozecchini 0:9fca2b23d0ba 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
marcozecchini 0:9fca2b23d0ba 13 * See the License for the specific language governing permissions and
marcozecchini 0:9fca2b23d0ba 14 * limitations under the License.
marcozecchini 0:9fca2b23d0ba 15 */
marcozecchini 0:9fca2b23d0ba 16 #include "mbed.h"
marcozecchini 0:9fca2b23d0ba 17 #include "greentea-client/test_env.h"
marcozecchini 0:9fca2b23d0ba 18 #include "unity.h"
marcozecchini 0:9fca2b23d0ba 19 #include "utest.h"
marcozecchini 0:9fca2b23d0ba 20 #include "rtos.h"
marcozecchini 0:9fca2b23d0ba 21
marcozecchini 0:9fca2b23d0ba 22 using namespace utest::v1;
marcozecchini 0:9fca2b23d0ba 23
marcozecchini 0:9fca2b23d0ba 24 #if defined(MBED_RTOS_SINGLE_THREAD)
marcozecchini 0:9fca2b23d0ba 25 #error [NOT_SUPPORTED] test not supported
marcozecchini 0:9fca2b23d0ba 26 #endif
marcozecchini 0:9fca2b23d0ba 27
marcozecchini 0:9fca2b23d0ba 28 #define THREAD_DELAY 30
marcozecchini 0:9fca2b23d0ba 29 #define SEMAPHORE_SLOTS 2
marcozecchini 0:9fca2b23d0ba 30 #define SEM_CHANGES 100
marcozecchini 0:9fca2b23d0ba 31 #define SHORT_WAIT 5
marcozecchini 0:9fca2b23d0ba 32
marcozecchini 0:9fca2b23d0ba 33 #define THREAD_STACK_SIZE 320 /* larger stack cause out of heap memory on some 16kB RAM boards in multi thread test*/
marcozecchini 0:9fca2b23d0ba 34
marcozecchini 0:9fca2b23d0ba 35 Semaphore two_slots(SEMAPHORE_SLOTS);
marcozecchini 0:9fca2b23d0ba 36
marcozecchini 0:9fca2b23d0ba 37 volatile int change_counter = 0;
marcozecchini 0:9fca2b23d0ba 38 volatile int sem_counter = 0;
marcozecchini 0:9fca2b23d0ba 39 volatile bool sem_defect = false;
marcozecchini 0:9fca2b23d0ba 40
marcozecchini 0:9fca2b23d0ba 41 void test_thread(int const *delay)
marcozecchini 0:9fca2b23d0ba 42 {
marcozecchini 0:9fca2b23d0ba 43 const int thread_delay = *delay;
marcozecchini 0:9fca2b23d0ba 44 while (true) {
marcozecchini 0:9fca2b23d0ba 45 two_slots.wait();
marcozecchini 0:9fca2b23d0ba 46 sem_counter++;
marcozecchini 0:9fca2b23d0ba 47 const bool sem_lock_failed = sem_counter > SEMAPHORE_SLOTS;
marcozecchini 0:9fca2b23d0ba 48 if (sem_lock_failed) {
marcozecchini 0:9fca2b23d0ba 49 sem_defect = true;
marcozecchini 0:9fca2b23d0ba 50 }
marcozecchini 0:9fca2b23d0ba 51 Thread::wait(thread_delay);
marcozecchini 0:9fca2b23d0ba 52 sem_counter--;
marcozecchini 0:9fca2b23d0ba 53 change_counter++;
marcozecchini 0:9fca2b23d0ba 54 two_slots.release();
marcozecchini 0:9fca2b23d0ba 55 }
marcozecchini 0:9fca2b23d0ba 56 }
marcozecchini 0:9fca2b23d0ba 57
marcozecchini 0:9fca2b23d0ba 58 /* Test multiple threads
marcozecchini 0:9fca2b23d0ba 59
marcozecchini 0:9fca2b23d0ba 60 Given 3 threads started with different delays and a semaphore with 2 tokens
marcozecchini 0:9fca2b23d0ba 61 when each thread runs it tries to acquire a token
marcozecchini 0:9fca2b23d0ba 62 then no more than two threads should be able to access protected region
marcozecchini 0:9fca2b23d0ba 63 */
marcozecchini 0:9fca2b23d0ba 64 void test_multi()
marcozecchini 0:9fca2b23d0ba 65 {
marcozecchini 0:9fca2b23d0ba 66 const int t1_delay = THREAD_DELAY * 1;
marcozecchini 0:9fca2b23d0ba 67 const int t2_delay = THREAD_DELAY * 2;
marcozecchini 0:9fca2b23d0ba 68 const int t3_delay = THREAD_DELAY * 3;
marcozecchini 0:9fca2b23d0ba 69
marcozecchini 0:9fca2b23d0ba 70 Thread t1(osPriorityNormal, THREAD_STACK_SIZE);
marcozecchini 0:9fca2b23d0ba 71 Thread t2(osPriorityNormal, THREAD_STACK_SIZE);
marcozecchini 0:9fca2b23d0ba 72 Thread t3(osPriorityNormal, THREAD_STACK_SIZE);
marcozecchini 0:9fca2b23d0ba 73
marcozecchini 0:9fca2b23d0ba 74 t1.start(callback(test_thread, &t1_delay));
marcozecchini 0:9fca2b23d0ba 75 t2.start(callback(test_thread, &t2_delay));
marcozecchini 0:9fca2b23d0ba 76 t3.start(callback(test_thread, &t3_delay));
marcozecchini 0:9fca2b23d0ba 77
marcozecchini 0:9fca2b23d0ba 78 while (true) {
marcozecchini 0:9fca2b23d0ba 79 if (change_counter >= SEM_CHANGES or sem_defect == true) {
marcozecchini 0:9fca2b23d0ba 80 t1.terminate();
marcozecchini 0:9fca2b23d0ba 81 t2.terminate();
marcozecchini 0:9fca2b23d0ba 82 t3.terminate();
marcozecchini 0:9fca2b23d0ba 83 break;
marcozecchini 0:9fca2b23d0ba 84 }
marcozecchini 0:9fca2b23d0ba 85 }
marcozecchini 0:9fca2b23d0ba 86 }
marcozecchini 0:9fca2b23d0ba 87
marcozecchini 0:9fca2b23d0ba 88 struct thread_data {
marcozecchini 0:9fca2b23d0ba 89 Semaphore *sem;
marcozecchini 0:9fca2b23d0ba 90 uint32_t data;
marcozecchini 0:9fca2b23d0ba 91 };
marcozecchini 0:9fca2b23d0ba 92
marcozecchini 0:9fca2b23d0ba 93 void single_thread(struct thread_data *data)
marcozecchini 0:9fca2b23d0ba 94 {
marcozecchini 0:9fca2b23d0ba 95 int32_t cnt = data->sem->wait();
marcozecchini 0:9fca2b23d0ba 96 TEST_ASSERT_EQUAL(1, cnt);
marcozecchini 0:9fca2b23d0ba 97 data->data++;
marcozecchini 0:9fca2b23d0ba 98 }
marcozecchini 0:9fca2b23d0ba 99
marcozecchini 0:9fca2b23d0ba 100 /** Test single thread
marcozecchini 0:9fca2b23d0ba 101
marcozecchini 0:9fca2b23d0ba 102 Given a two threads A & B and a semaphore (with count of 0) and a counter (equals to 0)
marcozecchini 0:9fca2b23d0ba 103 when thread B calls @a wait
marcozecchini 0:9fca2b23d0ba 104 then thread B waits for a token to become available
marcozecchini 0:9fca2b23d0ba 105 then the counter is equal to 0
marcozecchini 0:9fca2b23d0ba 106 when thread A calls @a release on the semaphore
marcozecchini 0:9fca2b23d0ba 107 then thread B acquires a token and increments the counter
marcozecchini 0:9fca2b23d0ba 108 then the counter equals to 1
marcozecchini 0:9fca2b23d0ba 109 */
marcozecchini 0:9fca2b23d0ba 110 void test_single_thread()
marcozecchini 0:9fca2b23d0ba 111 {
marcozecchini 0:9fca2b23d0ba 112 Thread t(osPriorityNormal, THREAD_STACK_SIZE);
marcozecchini 0:9fca2b23d0ba 113 Semaphore sem(0);
marcozecchini 0:9fca2b23d0ba 114 struct thread_data data;
marcozecchini 0:9fca2b23d0ba 115 osStatus res;
marcozecchini 0:9fca2b23d0ba 116
marcozecchini 0:9fca2b23d0ba 117 data.sem = &sem;
marcozecchini 0:9fca2b23d0ba 118 data.data = 0;
marcozecchini 0:9fca2b23d0ba 119
marcozecchini 0:9fca2b23d0ba 120 res = t.start(callback(single_thread, &data));
marcozecchini 0:9fca2b23d0ba 121 TEST_ASSERT_EQUAL(osOK, res);
marcozecchini 0:9fca2b23d0ba 122 Thread::wait(SHORT_WAIT);
marcozecchini 0:9fca2b23d0ba 123
marcozecchini 0:9fca2b23d0ba 124 TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
marcozecchini 0:9fca2b23d0ba 125 TEST_ASSERT_EQUAL(0, data.data);
marcozecchini 0:9fca2b23d0ba 126
marcozecchini 0:9fca2b23d0ba 127 res = sem.release();
marcozecchini 0:9fca2b23d0ba 128 TEST_ASSERT_EQUAL(osOK, res);
marcozecchini 0:9fca2b23d0ba 129
marcozecchini 0:9fca2b23d0ba 130 Thread::wait(SHORT_WAIT);
marcozecchini 0:9fca2b23d0ba 131
marcozecchini 0:9fca2b23d0ba 132 TEST_ASSERT_EQUAL(1, data.data);
marcozecchini 0:9fca2b23d0ba 133
marcozecchini 0:9fca2b23d0ba 134 t.join();
marcozecchini 0:9fca2b23d0ba 135 }
marcozecchini 0:9fca2b23d0ba 136
marcozecchini 0:9fca2b23d0ba 137 void timeout_thread(Semaphore *sem)
marcozecchini 0:9fca2b23d0ba 138 {
marcozecchini 0:9fca2b23d0ba 139 int32_t cnt = sem->wait(30);
marcozecchini 0:9fca2b23d0ba 140 TEST_ASSERT_EQUAL(0, cnt);
marcozecchini 0:9fca2b23d0ba 141 }
marcozecchini 0:9fca2b23d0ba 142
marcozecchini 0:9fca2b23d0ba 143 /** Test timeout
marcozecchini 0:9fca2b23d0ba 144
marcozecchini 0:9fca2b23d0ba 145 Given thread and a semaphore with no tokens available
marcozecchini 0:9fca2b23d0ba 146 when thread calls @a wait on the semaphore with timeout of 10ms
marcozecchini 0:9fca2b23d0ba 147 then the thread waits for 10ms and timeouts after
marcozecchini 0:9fca2b23d0ba 148 */
marcozecchini 0:9fca2b23d0ba 149 void test_timeout()
marcozecchini 0:9fca2b23d0ba 150 {
marcozecchini 0:9fca2b23d0ba 151 Thread t(osPriorityNormal, THREAD_STACK_SIZE);
marcozecchini 0:9fca2b23d0ba 152 Semaphore sem(0);
marcozecchini 0:9fca2b23d0ba 153 osStatus res;
marcozecchini 0:9fca2b23d0ba 154
marcozecchini 0:9fca2b23d0ba 155 Timer timer;
marcozecchini 0:9fca2b23d0ba 156 timer.start();
marcozecchini 0:9fca2b23d0ba 157 res = t.start(callback(timeout_thread, &sem));
marcozecchini 0:9fca2b23d0ba 158 TEST_ASSERT_EQUAL(osOK, res);
marcozecchini 0:9fca2b23d0ba 159 Thread::wait(SHORT_WAIT);
marcozecchini 0:9fca2b23d0ba 160
marcozecchini 0:9fca2b23d0ba 161 TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
marcozecchini 0:9fca2b23d0ba 162
marcozecchini 0:9fca2b23d0ba 163 t.join();
marcozecchini 0:9fca2b23d0ba 164 TEST_ASSERT_UINT32_WITHIN(5000, 30000, timer.read_us());
marcozecchini 0:9fca2b23d0ba 165 }
marcozecchini 0:9fca2b23d0ba 166
marcozecchini 0:9fca2b23d0ba 167 /** Test no timeouts
marcozecchini 0:9fca2b23d0ba 168
marcozecchini 0:9fca2b23d0ba 169 Test 1 token no timeout
marcozecchini 0:9fca2b23d0ba 170 Given thread and a semaphore with one token available
marcozecchini 0:9fca2b23d0ba 171 when thread calls @a wait on the semaphore with timeout of 0ms
marcozecchini 0:9fca2b23d0ba 172 then the thread acquires the token immediately
marcozecchini 0:9fca2b23d0ba 173
marcozecchini 0:9fca2b23d0ba 174 Test 0 tokens no timeout
marcozecchini 0:9fca2b23d0ba 175 Given thread and a semaphore with no tokens available
marcozecchini 0:9fca2b23d0ba 176 when thread calls @a wait on the semaphore with timeout of 0ms
marcozecchini 0:9fca2b23d0ba 177 then the thread returns immediately without acquiring a token
marcozecchini 0:9fca2b23d0ba 178 */
marcozecchini 0:9fca2b23d0ba 179 template<int T>
marcozecchini 0:9fca2b23d0ba 180 void test_no_timeout()
marcozecchini 0:9fca2b23d0ba 181 {
marcozecchini 0:9fca2b23d0ba 182 Semaphore sem(T);
marcozecchini 0:9fca2b23d0ba 183
marcozecchini 0:9fca2b23d0ba 184 Timer timer;
marcozecchini 0:9fca2b23d0ba 185 timer.start();
marcozecchini 0:9fca2b23d0ba 186
marcozecchini 0:9fca2b23d0ba 187 int32_t cnt = sem.wait(0);
marcozecchini 0:9fca2b23d0ba 188 TEST_ASSERT_EQUAL(T, cnt);
marcozecchini 0:9fca2b23d0ba 189
marcozecchini 0:9fca2b23d0ba 190 TEST_ASSERT_UINT32_WITHIN(5000, 0, timer.read_us());
marcozecchini 0:9fca2b23d0ba 191 }
marcozecchini 0:9fca2b23d0ba 192
marcozecchini 0:9fca2b23d0ba 193 /** Test multiple tokens wait
marcozecchini 0:9fca2b23d0ba 194
marcozecchini 0:9fca2b23d0ba 195 Given a thread and a semaphore initialized with 5 tokens
marcozecchini 0:9fca2b23d0ba 196 when thread calls @a wait 6 times on the semaphore
marcozecchini 0:9fca2b23d0ba 197 then the token counts goes to zero
marcozecchini 0:9fca2b23d0ba 198 */
marcozecchini 0:9fca2b23d0ba 199 void test_multiple_tokens_wait()
marcozecchini 0:9fca2b23d0ba 200 {
marcozecchini 0:9fca2b23d0ba 201 Semaphore sem(5);
marcozecchini 0:9fca2b23d0ba 202
marcozecchini 0:9fca2b23d0ba 203 for(int i = 5; i >= 0; i--) {
marcozecchini 0:9fca2b23d0ba 204 int32_t cnt = sem.wait(0);
marcozecchini 0:9fca2b23d0ba 205 TEST_ASSERT_EQUAL(i, cnt);
marcozecchini 0:9fca2b23d0ba 206 }
marcozecchini 0:9fca2b23d0ba 207 }
marcozecchini 0:9fca2b23d0ba 208
marcozecchini 0:9fca2b23d0ba 209 /** Test multiple tokens release
marcozecchini 0:9fca2b23d0ba 210
marcozecchini 0:9fca2b23d0ba 211 Given a thread and a semaphore initialized with zero tokens and max of 5
marcozecchini 0:9fca2b23d0ba 212 when thread calls @a release 6 times on the semaphore
marcozecchini 0:9fca2b23d0ba 213 then the token count should be equal to 5 and last release call should fail
marcozecchini 0:9fca2b23d0ba 214 */
marcozecchini 0:9fca2b23d0ba 215 void test_multiple_tokens_release()
marcozecchini 0:9fca2b23d0ba 216 {
marcozecchini 0:9fca2b23d0ba 217 Semaphore sem(0, 5);
marcozecchini 0:9fca2b23d0ba 218
marcozecchini 0:9fca2b23d0ba 219 for(int i = 5; i > 0; i--) {
marcozecchini 0:9fca2b23d0ba 220 osStatus stat = sem.release();
marcozecchini 0:9fca2b23d0ba 221 TEST_ASSERT_EQUAL(osOK, stat);
marcozecchini 0:9fca2b23d0ba 222 }
marcozecchini 0:9fca2b23d0ba 223 osStatus stat = sem.release();
marcozecchini 0:9fca2b23d0ba 224 TEST_ASSERT_EQUAL(osErrorResource, stat);
marcozecchini 0:9fca2b23d0ba 225 }
marcozecchini 0:9fca2b23d0ba 226
marcozecchini 0:9fca2b23d0ba 227 utest::v1::status_t test_setup(const size_t number_of_cases)
marcozecchini 0:9fca2b23d0ba 228 {
marcozecchini 0:9fca2b23d0ba 229 GREENTEA_SETUP(10, "default_auto");
marcozecchini 0:9fca2b23d0ba 230 return verbose_test_setup_handler(number_of_cases);
marcozecchini 0:9fca2b23d0ba 231 }
marcozecchini 0:9fca2b23d0ba 232
marcozecchini 0:9fca2b23d0ba 233 Case cases[] = {
marcozecchini 0:9fca2b23d0ba 234 Case("Test single thread", test_single_thread),
marcozecchini 0:9fca2b23d0ba 235 Case("Test timeout", test_timeout),
marcozecchini 0:9fca2b23d0ba 236 Case("Test 1 token no timeout", test_no_timeout<1>),
marcozecchini 0:9fca2b23d0ba 237 Case("Test 0 tokens no timeout", test_no_timeout<0>),
marcozecchini 0:9fca2b23d0ba 238 Case("Test multiple tokens wait", test_multiple_tokens_wait),
marcozecchini 0:9fca2b23d0ba 239 Case("Test multiple tokens release", test_multiple_tokens_release),
marcozecchini 0:9fca2b23d0ba 240 Case("Test multiple threads", test_multi)
marcozecchini 0:9fca2b23d0ba 241 };
marcozecchini 0:9fca2b23d0ba 242
marcozecchini 0:9fca2b23d0ba 243 Specification specification(test_setup, cases);
marcozecchini 0:9fca2b23d0ba 244
marcozecchini 0:9fca2b23d0ba 245 int main()
marcozecchini 0:9fca2b23d0ba 246 {
marcozecchini 0:9fca2b23d0ba 247 return !Harness::run(specification);
marcozecchini 0:9fca2b23d0ba 248 }