mbed-os

Fork of mbed-os by erkin yucel

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elessair 0:f269e3021894 1 /* mbed Microcontroller Library
elessair 0:f269e3021894 2 * Copyright (c) 2006-2012 ARM Limited
elessair 0:f269e3021894 3 *
elessair 0:f269e3021894 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
elessair 0:f269e3021894 5 * of this software and associated documentation files (the "Software"), to deal
elessair 0:f269e3021894 6 * in the Software without restriction, including without limitation the rights
elessair 0:f269e3021894 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
elessair 0:f269e3021894 8 * copies of the Software, and to permit persons to whom the Software is
elessair 0:f269e3021894 9 * furnished to do so, subject to the following conditions:
elessair 0:f269e3021894 10 *
elessair 0:f269e3021894 11 * The above copyright notice and this permission notice shall be included in
elessair 0:f269e3021894 12 * all copies or substantial portions of the Software.
elessair 0:f269e3021894 13 *
elessair 0:f269e3021894 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
elessair 0:f269e3021894 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
elessair 0:f269e3021894 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
elessair 0:f269e3021894 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
elessair 0:f269e3021894 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
elessair 0:f269e3021894 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
elessair 0:f269e3021894 20 * SOFTWARE.
elessair 0:f269e3021894 21 */
elessair 0:f269e3021894 22 #include "rtos/Thread.h"
elessair 0:f269e3021894 23
elessair 0:f269e3021894 24 #include "mbed.h"
elessair 0:f269e3021894 25 #include "rtos/rtos_idle.h"
elessair 0:f269e3021894 26
elessair 0:f269e3021894 27 // rt_tid2ptcb is an internal function which we exposed to get TCB for thread id
elessair 0:f269e3021894 28 #undef NULL //Workaround for conflicting macros in rt_TypeDef.h and stdio.h
elessair 0:f269e3021894 29 #include "rt_TypeDef.h"
elessair 0:f269e3021894 30
elessair 0:f269e3021894 31 extern "C" P_TCB rt_tid2ptcb(osThreadId thread_id);
elessair 0:f269e3021894 32
elessair 0:f269e3021894 33
elessair 0:f269e3021894 34 static void (*terminate_hook)(osThreadId id) = 0;
elessair 0:f269e3021894 35 extern "C" void thread_terminate_hook(osThreadId id)
elessair 0:f269e3021894 36 {
elessair 0:f269e3021894 37 if (terminate_hook != (void (*)(osThreadId))NULL) {
elessair 0:f269e3021894 38 terminate_hook(id);
elessair 0:f269e3021894 39 }
elessair 0:f269e3021894 40 }
elessair 0:f269e3021894 41
elessair 0:f269e3021894 42 namespace rtos {
elessair 0:f269e3021894 43
elessair 0:f269e3021894 44 void Thread::constructor(osPriority priority,
elessair 0:f269e3021894 45 uint32_t stack_size, unsigned char *stack_pointer) {
elessair 0:f269e3021894 46 _tid = 0;
elessair 0:f269e3021894 47 _dynamic_stack = (stack_pointer == NULL);
elessair 0:f269e3021894 48
elessair 0:f269e3021894 49 #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM)
elessair 0:f269e3021894 50 _thread_def.tpriority = priority;
elessair 0:f269e3021894 51 _thread_def.stacksize = stack_size;
elessair 0:f269e3021894 52 _thread_def.stack_pointer = (uint32_t*)stack_pointer;
elessair 0:f269e3021894 53 #endif
elessair 0:f269e3021894 54 }
elessair 0:f269e3021894 55
elessair 0:f269e3021894 56 void Thread::constructor(Callback<void()> task,
elessair 0:f269e3021894 57 osPriority priority, uint32_t stack_size, unsigned char *stack_pointer) {
elessair 0:f269e3021894 58 constructor(priority, stack_size, stack_pointer);
elessair 0:f269e3021894 59
elessair 0:f269e3021894 60 switch (start(task)) {
elessair 0:f269e3021894 61 case osErrorResource:
elessair 0:f269e3021894 62 error("OS ran out of threads!\n");
elessair 0:f269e3021894 63 break;
elessair 0:f269e3021894 64 case osErrorParameter:
elessair 0:f269e3021894 65 error("Thread already running!\n");
elessair 0:f269e3021894 66 break;
elessair 0:f269e3021894 67 case osErrorNoMemory:
elessair 0:f269e3021894 68 error("Error allocating the stack memory\n");
elessair 0:f269e3021894 69 default:
elessair 0:f269e3021894 70 break;
elessair 0:f269e3021894 71 }
elessair 0:f269e3021894 72 }
elessair 0:f269e3021894 73
elessair 0:f269e3021894 74 osStatus Thread::start(Callback<void()> task) {
elessair 0:f269e3021894 75 _mutex.lock();
elessair 0:f269e3021894 76
elessair 0:f269e3021894 77 if (_tid != 0) {
elessair 0:f269e3021894 78 _mutex.unlock();
elessair 0:f269e3021894 79 return osErrorParameter;
elessair 0:f269e3021894 80 }
elessair 0:f269e3021894 81
elessair 0:f269e3021894 82 #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM)
elessair 0:f269e3021894 83 _thread_def.pthread = Thread::_thunk;
elessair 0:f269e3021894 84 if (_thread_def.stack_pointer == NULL) {
elessair 0:f269e3021894 85 _thread_def.stack_pointer = new uint32_t[_thread_def.stacksize/sizeof(uint32_t)];
elessair 0:f269e3021894 86 MBED_ASSERT(_thread_def.stack_pointer != NULL);
elessair 0:f269e3021894 87 }
elessair 0:f269e3021894 88
elessair 0:f269e3021894 89 //Fill the stack with a magic word for maximum usage checking
elessair 0:f269e3021894 90 for (uint32_t i = 0; i < (_thread_def.stacksize / sizeof(uint32_t)); i++) {
elessair 0:f269e3021894 91 _thread_def.stack_pointer[i] = 0xE25A2EA5;
elessair 0:f269e3021894 92 }
elessair 0:f269e3021894 93 #endif
elessair 0:f269e3021894 94 _task = task;
elessair 0:f269e3021894 95 _tid = osThreadCreate(&_thread_def, this);
elessair 0:f269e3021894 96 if (_tid == NULL) {
elessair 0:f269e3021894 97 if (_dynamic_stack) {
elessair 0:f269e3021894 98 delete[] (_thread_def.stack_pointer);
elessair 0:f269e3021894 99 _thread_def.stack_pointer = (uint32_t*)NULL;
elessair 0:f269e3021894 100 }
elessair 0:f269e3021894 101 _mutex.unlock();
elessair 0:f269e3021894 102 _join_sem.release();
elessair 0:f269e3021894 103 return osErrorResource;
elessair 0:f269e3021894 104 }
elessair 0:f269e3021894 105
elessair 0:f269e3021894 106 _mutex.unlock();
elessair 0:f269e3021894 107 return osOK;
elessair 0:f269e3021894 108 }
elessair 0:f269e3021894 109
elessair 0:f269e3021894 110 osStatus Thread::terminate() {
elessair 0:f269e3021894 111 osStatus ret;
elessair 0:f269e3021894 112 _mutex.lock();
elessair 0:f269e3021894 113
elessair 0:f269e3021894 114 // Set the Thread's tid to NULL and
elessair 0:f269e3021894 115 // release the semaphore before terminating
elessair 0:f269e3021894 116 // since this thread could be terminating itself
elessair 0:f269e3021894 117 osThreadId local_id = _tid;
elessair 0:f269e3021894 118 _join_sem.release();
elessair 0:f269e3021894 119 _tid = (osThreadId)NULL;
elessair 0:f269e3021894 120
elessair 0:f269e3021894 121 ret = osThreadTerminate(local_id);
elessair 0:f269e3021894 122
elessair 0:f269e3021894 123 _mutex.unlock();
elessair 0:f269e3021894 124 return ret;
elessair 0:f269e3021894 125 }
elessair 0:f269e3021894 126
elessair 0:f269e3021894 127 osStatus Thread::join() {
elessair 0:f269e3021894 128 int32_t ret = _join_sem.wait();
elessair 0:f269e3021894 129 if (ret < 0) {
elessair 0:f269e3021894 130 return osErrorOS;
elessair 0:f269e3021894 131 }
elessair 0:f269e3021894 132
elessair 0:f269e3021894 133 // The semaphore has been released so this thread is being
elessair 0:f269e3021894 134 // terminated or has been terminated. Once the mutex has
elessair 0:f269e3021894 135 // been locked it is ensured that the thread is deleted.
elessair 0:f269e3021894 136 _mutex.lock();
elessair 0:f269e3021894 137 MBED_ASSERT(NULL == _tid);
elessair 0:f269e3021894 138 _mutex.unlock();
elessair 0:f269e3021894 139
elessair 0:f269e3021894 140 // Release sem so any other threads joining this thread wake up
elessair 0:f269e3021894 141 _join_sem.release();
elessair 0:f269e3021894 142 return osOK;
elessair 0:f269e3021894 143 }
elessair 0:f269e3021894 144
elessair 0:f269e3021894 145 osStatus Thread::set_priority(osPriority priority) {
elessair 0:f269e3021894 146 osStatus ret;
elessair 0:f269e3021894 147 _mutex.lock();
elessair 0:f269e3021894 148
elessair 0:f269e3021894 149 ret = osThreadSetPriority(_tid, priority);
elessair 0:f269e3021894 150
elessair 0:f269e3021894 151 _mutex.unlock();
elessair 0:f269e3021894 152 return ret;
elessair 0:f269e3021894 153 }
elessair 0:f269e3021894 154
elessair 0:f269e3021894 155 osPriority Thread::get_priority() {
elessair 0:f269e3021894 156 osPriority ret;
elessair 0:f269e3021894 157 _mutex.lock();
elessair 0:f269e3021894 158
elessair 0:f269e3021894 159 ret = osThreadGetPriority(_tid);
elessair 0:f269e3021894 160
elessair 0:f269e3021894 161 _mutex.unlock();
elessair 0:f269e3021894 162 return ret;
elessair 0:f269e3021894 163 }
elessair 0:f269e3021894 164
elessair 0:f269e3021894 165 int32_t Thread::signal_set(int32_t signals) {
elessair 0:f269e3021894 166 // osSignalSet is thread safe as long as the underlying
elessair 0:f269e3021894 167 // thread does not get terminated or return from main
elessair 0:f269e3021894 168 return osSignalSet(_tid, signals);
elessair 0:f269e3021894 169 }
elessair 0:f269e3021894 170
elessair 0:f269e3021894 171 int32_t Thread::signal_clr(int32_t signals) {
elessair 0:f269e3021894 172 // osSignalClear is thread safe as long as the underlying
elessair 0:f269e3021894 173 // thread does not get terminated or return from main
elessair 0:f269e3021894 174 return osSignalClear(_tid, signals);
elessair 0:f269e3021894 175 }
elessair 0:f269e3021894 176
elessair 0:f269e3021894 177 Thread::State Thread::get_state() {
elessair 0:f269e3021894 178 #if !defined(__MBED_CMSIS_RTOS_CA9) && !defined(__MBED_CMSIS_RTOS_CM)
elessair 0:f269e3021894 179 #ifdef CMSIS_OS_RTX
elessair 0:f269e3021894 180 State status = Deleted;
elessair 0:f269e3021894 181 _mutex.lock();
elessair 0:f269e3021894 182
elessair 0:f269e3021894 183 if (_tid != NULL) {
elessair 0:f269e3021894 184 status = (State)_thread_def.tcb.state;
elessair 0:f269e3021894 185 }
elessair 0:f269e3021894 186
elessair 0:f269e3021894 187 _mutex.unlock();
elessair 0:f269e3021894 188 return status;
elessair 0:f269e3021894 189 #endif
elessair 0:f269e3021894 190 #else
elessair 0:f269e3021894 191 State status = Deleted;
elessair 0:f269e3021894 192 _mutex.lock();
elessair 0:f269e3021894 193
elessair 0:f269e3021894 194 if (_tid != NULL) {
elessair 0:f269e3021894 195 status = (State)osThreadGetState(_tid);
elessair 0:f269e3021894 196 }
elessair 0:f269e3021894 197
elessair 0:f269e3021894 198 _mutex.unlock();
elessair 0:f269e3021894 199 return status;
elessair 0:f269e3021894 200 #endif
elessair 0:f269e3021894 201 }
elessair 0:f269e3021894 202
elessair 0:f269e3021894 203 uint32_t Thread::stack_size() {
elessair 0:f269e3021894 204 #ifndef __MBED_CMSIS_RTOS_CA9
elessair 0:f269e3021894 205 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
elessair 0:f269e3021894 206 uint32_t size = 0;
elessair 0:f269e3021894 207 _mutex.lock();
elessair 0:f269e3021894 208
elessair 0:f269e3021894 209 if (_tid != NULL) {
elessair 0:f269e3021894 210 size = _thread_def.tcb.priv_stack;
elessair 0:f269e3021894 211 }
elessair 0:f269e3021894 212
elessair 0:f269e3021894 213 _mutex.unlock();
elessair 0:f269e3021894 214 return size;
elessair 0:f269e3021894 215 #else
elessair 0:f269e3021894 216 uint32_t size = 0;
elessair 0:f269e3021894 217 _mutex.lock();
elessair 0:f269e3021894 218
elessair 0:f269e3021894 219 if (_tid != NULL) {
elessair 0:f269e3021894 220 P_TCB tcb = rt_tid2ptcb(_tid);
elessair 0:f269e3021894 221 size = tcb->priv_stack;
elessair 0:f269e3021894 222 }
elessair 0:f269e3021894 223
elessair 0:f269e3021894 224 _mutex.unlock();
elessair 0:f269e3021894 225 return size;
elessair 0:f269e3021894 226 #endif
elessair 0:f269e3021894 227 #else
elessair 0:f269e3021894 228 return 0;
elessair 0:f269e3021894 229 #endif
elessair 0:f269e3021894 230 }
elessair 0:f269e3021894 231
elessair 0:f269e3021894 232 uint32_t Thread::free_stack() {
elessair 0:f269e3021894 233 #ifndef __MBED_CMSIS_RTOS_CA9
elessair 0:f269e3021894 234 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
elessair 0:f269e3021894 235 uint32_t size = 0;
elessair 0:f269e3021894 236 _mutex.lock();
elessair 0:f269e3021894 237
elessair 0:f269e3021894 238 if (_tid != NULL) {
elessair 0:f269e3021894 239 uint32_t bottom = (uint32_t)_thread_def.tcb.stack;
elessair 0:f269e3021894 240 size = _thread_def.tcb.tsk_stack - bottom;
elessair 0:f269e3021894 241 }
elessair 0:f269e3021894 242
elessair 0:f269e3021894 243 _mutex.unlock();
elessair 0:f269e3021894 244 return size;
elessair 0:f269e3021894 245 #else
elessair 0:f269e3021894 246 uint32_t size = 0;
elessair 0:f269e3021894 247 _mutex.lock();
elessair 0:f269e3021894 248
elessair 0:f269e3021894 249 if (_tid != NULL) {
elessair 0:f269e3021894 250 P_TCB tcb = rt_tid2ptcb(_tid);
elessair 0:f269e3021894 251 uint32_t bottom = (uint32_t)tcb->stack;
elessair 0:f269e3021894 252 size = tcb->tsk_stack - bottom;
elessair 0:f269e3021894 253 }
elessair 0:f269e3021894 254
elessair 0:f269e3021894 255 _mutex.unlock();
elessair 0:f269e3021894 256 return size;
elessair 0:f269e3021894 257 #endif
elessair 0:f269e3021894 258 #else
elessair 0:f269e3021894 259 return 0;
elessair 0:f269e3021894 260 #endif
elessair 0:f269e3021894 261 }
elessair 0:f269e3021894 262
elessair 0:f269e3021894 263 uint32_t Thread::used_stack() {
elessair 0:f269e3021894 264 #ifndef __MBED_CMSIS_RTOS_CA9
elessair 0:f269e3021894 265 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
elessair 0:f269e3021894 266 uint32_t size = 0;
elessair 0:f269e3021894 267 _mutex.lock();
elessair 0:f269e3021894 268
elessair 0:f269e3021894 269 if (_tid != NULL) {
elessair 0:f269e3021894 270 uint32_t top = (uint32_t)_thread_def.tcb.stack + _thread_def.tcb.priv_stack;
elessair 0:f269e3021894 271 size = top - _thread_def.tcb.tsk_stack;
elessair 0:f269e3021894 272 }
elessair 0:f269e3021894 273
elessair 0:f269e3021894 274 _mutex.unlock();
elessair 0:f269e3021894 275 return size;
elessair 0:f269e3021894 276 #else
elessair 0:f269e3021894 277 uint32_t size = 0;
elessair 0:f269e3021894 278 _mutex.lock();
elessair 0:f269e3021894 279
elessair 0:f269e3021894 280 if (_tid != NULL) {
elessair 0:f269e3021894 281 P_TCB tcb = rt_tid2ptcb(_tid);
elessair 0:f269e3021894 282 uint32_t top = (uint32_t)tcb->stack + tcb->priv_stack;
elessair 0:f269e3021894 283 size = top - tcb->tsk_stack;
elessair 0:f269e3021894 284 }
elessair 0:f269e3021894 285
elessair 0:f269e3021894 286 _mutex.unlock();
elessair 0:f269e3021894 287 return size;
elessair 0:f269e3021894 288 #endif
elessair 0:f269e3021894 289 #else
elessair 0:f269e3021894 290 return 0;
elessair 0:f269e3021894 291 #endif
elessair 0:f269e3021894 292 }
elessair 0:f269e3021894 293
elessair 0:f269e3021894 294 uint32_t Thread::max_stack() {
elessair 0:f269e3021894 295 #ifndef __MBED_CMSIS_RTOS_CA9
elessair 0:f269e3021894 296 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
elessair 0:f269e3021894 297 uint32_t size = 0;
elessair 0:f269e3021894 298 _mutex.lock();
elessair 0:f269e3021894 299
elessair 0:f269e3021894 300 if (_tid != NULL) {
elessair 0:f269e3021894 301 uint32_t high_mark = 0;
elessair 0:f269e3021894 302 while (_thread_def.tcb.stack[high_mark] == 0xE25A2EA5)
elessair 0:f269e3021894 303 high_mark++;
elessair 0:f269e3021894 304 size = _thread_def.tcb.priv_stack - (high_mark * 4);
elessair 0:f269e3021894 305 }
elessair 0:f269e3021894 306
elessair 0:f269e3021894 307 _mutex.unlock();
elessair 0:f269e3021894 308 return size;
elessair 0:f269e3021894 309 #else
elessair 0:f269e3021894 310 uint32_t size = 0;
elessair 0:f269e3021894 311 _mutex.lock();
elessair 0:f269e3021894 312
elessair 0:f269e3021894 313 if (_tid != NULL) {
elessair 0:f269e3021894 314 P_TCB tcb = rt_tid2ptcb(_tid);
elessair 0:f269e3021894 315 uint32_t high_mark = 0;
elessair 0:f269e3021894 316 while (tcb->stack[high_mark] == 0xE25A2EA5)
elessair 0:f269e3021894 317 high_mark++;
elessair 0:f269e3021894 318 size = tcb->priv_stack - (high_mark * 4);
elessair 0:f269e3021894 319 }
elessair 0:f269e3021894 320
elessair 0:f269e3021894 321 _mutex.unlock();
elessair 0:f269e3021894 322 return size;
elessair 0:f269e3021894 323 #endif
elessair 0:f269e3021894 324 #else
elessair 0:f269e3021894 325 return 0;
elessair 0:f269e3021894 326 #endif
elessair 0:f269e3021894 327 }
elessair 0:f269e3021894 328
elessair 0:f269e3021894 329 osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
elessair 0:f269e3021894 330 return osSignalWait(signals, millisec);
elessair 0:f269e3021894 331 }
elessair 0:f269e3021894 332
elessair 0:f269e3021894 333 osStatus Thread::wait(uint32_t millisec) {
elessair 0:f269e3021894 334 return osDelay(millisec);
elessair 0:f269e3021894 335 }
elessair 0:f269e3021894 336
elessair 0:f269e3021894 337 osStatus Thread::yield() {
elessair 0:f269e3021894 338 return osThreadYield();
elessair 0:f269e3021894 339 }
elessair 0:f269e3021894 340
elessair 0:f269e3021894 341 osThreadId Thread::gettid() {
elessair 0:f269e3021894 342 return osThreadGetId();
elessair 0:f269e3021894 343 }
elessair 0:f269e3021894 344
elessair 0:f269e3021894 345 void Thread::attach_idle_hook(void (*fptr)(void)) {
elessair 0:f269e3021894 346 rtos_attach_idle_hook(fptr);
elessair 0:f269e3021894 347 }
elessair 0:f269e3021894 348
elessair 0:f269e3021894 349 void Thread::attach_terminate_hook(void (*fptr)(osThreadId id)) {
elessair 0:f269e3021894 350 terminate_hook = fptr;
elessair 0:f269e3021894 351 }
elessair 0:f269e3021894 352
elessair 0:f269e3021894 353 Thread::~Thread() {
elessair 0:f269e3021894 354 // terminate is thread safe
elessair 0:f269e3021894 355 terminate();
elessair 0:f269e3021894 356 #ifdef __MBED_CMSIS_RTOS_CM
elessair 0:f269e3021894 357 if (_dynamic_stack) {
elessair 0:f269e3021894 358 delete[] (_thread_def.stack_pointer);
elessair 0:f269e3021894 359 _thread_def.stack_pointer = (uint32_t*)NULL;
elessair 0:f269e3021894 360 }
elessair 0:f269e3021894 361 #endif
elessair 0:f269e3021894 362 }
elessair 0:f269e3021894 363
elessair 0:f269e3021894 364 void Thread::_thunk(const void * thread_ptr)
elessair 0:f269e3021894 365 {
elessair 0:f269e3021894 366 Thread *t = (Thread*)thread_ptr;
elessair 0:f269e3021894 367 t->_task();
elessair 0:f269e3021894 368 t->_mutex.lock();
elessair 0:f269e3021894 369 t->_tid = (osThreadId)NULL;
elessair 0:f269e3021894 370 t->_join_sem.release();
elessair 0:f269e3021894 371 // rtos will release the mutex automatically
elessair 0:f269e3021894 372 }
elessair 0:f269e3021894 373
elessair 0:f269e3021894 374 }