Official mbed Real Time Operating System based on the RTX implementation of the CMSIS-RTOS API open standard.

Dependents:   denki-yohou_b TestY201 Network-RTOS NTPClient_HelloWorld ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Thread.cpp Source File

Thread.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2012 ARM Limited
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to deal
00006  * in the Software without restriction, including without limitation the rights
00007  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  * copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00020  * SOFTWARE.
00021  */
00022 #include "rtos/Thread.h"
00023 
00024 #include "mbed.h"
00025 #include "rtos/rtos_idle.h"
00026 
00027 // rt_tid2ptcb is an internal function which we exposed to get TCB for thread id
00028 #undef NULL  //Workaround for conflicting macros in rt_TypeDef.h and stdio.h
00029 #include "rt_TypeDef.h"
00030 
00031 extern "C" P_TCB rt_tid2ptcb(osThreadId thread_id);
00032 
00033 
00034 static void (*terminate_hook)(osThreadId id) = 0;
00035 extern "C" void thread_terminate_hook(osThreadId id)
00036 {
00037     if (terminate_hook != (void (*)(osThreadId))NULL) {
00038         terminate_hook(id);
00039     }
00040 }
00041 
00042 namespace rtos {
00043 
00044 void Thread::constructor(osPriority priority,
00045         uint32_t stack_size, unsigned char *stack_pointer) {
00046     _tid = 0;
00047     _dynamic_stack = (stack_pointer == NULL);
00048 
00049 #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM)
00050     _thread_def.tpriority = priority;
00051     _thread_def.stacksize = stack_size;
00052     _thread_def.stack_pointer = (uint32_t*)stack_pointer;
00053 #endif
00054 }
00055 
00056 void Thread::constructor(Callback<void()> task,
00057         osPriority priority, uint32_t stack_size, unsigned char *stack_pointer) {
00058     constructor(priority, stack_size, stack_pointer);
00059 
00060     switch (start(task)) {
00061         case osErrorResource:
00062             error("OS ran out of threads!\n");
00063             break;
00064         case osErrorParameter:
00065             error("Thread already running!\n");
00066             break;
00067         case osErrorNoMemory:
00068             error("Error allocating the stack memory\n");
00069         default:
00070             break;
00071     }
00072 }
00073 
00074 osStatus Thread::start(Callback<void()> task) {
00075     _mutex.lock();
00076 
00077     if (_tid != 0) {
00078         _mutex.unlock();
00079         return osErrorParameter;
00080     }
00081 
00082 #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM)
00083     _thread_def.pthread = Thread::_thunk;
00084     if (_thread_def.stack_pointer == NULL) {
00085         _thread_def.stack_pointer = new uint32_t[_thread_def.stacksize/sizeof(uint32_t)];
00086         MBED_ASSERT(_thread_def.stack_pointer != NULL);
00087     }
00088 
00089     //Fill the stack with a magic word for maximum usage checking
00090     for (uint32_t i = 0; i < (_thread_def.stacksize / sizeof(uint32_t)); i++) {
00091         _thread_def.stack_pointer[i] = 0xE25A2EA5;
00092     }
00093 #endif
00094     _task = task;
00095     _tid = osThreadCreate(&_thread_def, this);
00096     if (_tid == NULL) {
00097         if (_dynamic_stack) {
00098             delete[] (_thread_def.stack_pointer);
00099             _thread_def.stack_pointer = (uint32_t*)NULL;
00100         }
00101         _mutex.unlock();
00102         _join_sem.release();
00103         return osErrorResource;
00104     }
00105 
00106     _mutex.unlock();
00107     return osOK;
00108 }
00109 
00110 osStatus Thread::terminate() {
00111     osStatus ret;
00112     _mutex.lock();
00113 
00114     // Set the Thread's tid to NULL and
00115     // release the semaphore before terminating
00116     // since this thread could be terminating itself
00117     osThreadId local_id = _tid;
00118     _join_sem.release();
00119     _tid = (osThreadId)NULL;
00120 
00121     ret = osThreadTerminate(local_id);
00122 
00123     _mutex.unlock();
00124     return ret;
00125 }
00126 
00127 osStatus Thread::join() {
00128     int32_t ret = _join_sem.wait();
00129     if (ret < 0) {
00130         return osErrorOS;
00131     }
00132 
00133     // The semaphore has been released so this thread is being
00134     // terminated or has been terminated. Once the mutex has
00135     // been locked it is ensured that the thread is deleted.
00136     _mutex.lock();
00137     MBED_ASSERT(NULL == _tid);
00138     _mutex.unlock();
00139 
00140     // Release sem so any other threads joining this thread wake up
00141     _join_sem.release();
00142     return osOK;
00143 }
00144 
00145 osStatus Thread::set_priority(osPriority priority) {
00146     osStatus ret;
00147     _mutex.lock();
00148 
00149     ret = osThreadSetPriority(_tid, priority);
00150 
00151     _mutex.unlock();
00152     return ret;
00153 }
00154 
00155 osPriority Thread::get_priority() {
00156     osPriority ret;
00157     _mutex.lock();
00158 
00159     ret = osThreadGetPriority(_tid);
00160 
00161     _mutex.unlock();
00162     return ret;
00163 }
00164 
00165 int32_t Thread::signal_set(int32_t signals) {
00166     // osSignalSet is thread safe as long as the underlying
00167     // thread does not get terminated or return from main
00168     return osSignalSet(_tid, signals);
00169 }
00170 
00171 int32_t Thread::signal_clr(int32_t signals) {
00172     // osSignalClear is thread safe as long as the underlying
00173     // thread does not get terminated or return from main
00174     return osSignalClear(_tid, signals);
00175 }
00176 
00177 Thread::State Thread::get_state() {
00178 #if !defined(__MBED_CMSIS_RTOS_CA9) && !defined(__MBED_CMSIS_RTOS_CM)
00179 #ifdef CMSIS_OS_RTX
00180     State status = Deleted;
00181     _mutex.lock();
00182 
00183     if (_tid != NULL) {
00184         status = (State)_thread_def.tcb.state;
00185     }
00186 
00187     _mutex.unlock();
00188     return status;
00189 #endif
00190 #else
00191     State status = Deleted;
00192     _mutex.lock();
00193 
00194     if (_tid != NULL) {
00195         status = (State)osThreadGetState(_tid);
00196     }
00197 
00198     _mutex.unlock();
00199     return status;
00200 #endif
00201 }
00202 
00203 uint32_t Thread::stack_size() {
00204 #ifndef __MBED_CMSIS_RTOS_CA9
00205 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
00206     uint32_t size = 0;
00207     _mutex.lock();
00208 
00209     if (_tid != NULL) {
00210         size = _thread_def.tcb.priv_stack;
00211     }
00212 
00213     _mutex.unlock();
00214     return size;
00215 #else
00216     uint32_t size = 0;
00217     _mutex.lock();
00218 
00219     if (_tid != NULL) {
00220         P_TCB tcb = rt_tid2ptcb(_tid);
00221         size = tcb->priv_stack;
00222     }
00223 
00224     _mutex.unlock();
00225     return size;
00226 #endif
00227 #else
00228     return 0;
00229 #endif
00230 }
00231 
00232 uint32_t Thread::free_stack() {
00233 #ifndef __MBED_CMSIS_RTOS_CA9
00234 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
00235     uint32_t size = 0;
00236     _mutex.lock();
00237 
00238     if (_tid != NULL) {
00239         uint32_t bottom = (uint32_t)_thread_def.tcb.stack;
00240         size = _thread_def.tcb.tsk_stack - bottom;
00241     }
00242 
00243     _mutex.unlock();
00244     return size;
00245 #else
00246     uint32_t size = 0;
00247     _mutex.lock();
00248 
00249     if (_tid != NULL) {
00250         P_TCB tcb = rt_tid2ptcb(_tid);
00251         uint32_t bottom = (uint32_t)tcb->stack;
00252         size = tcb->tsk_stack - bottom;
00253     }
00254 
00255     _mutex.unlock();
00256     return size;
00257 #endif
00258 #else
00259     return 0;
00260 #endif
00261 }
00262 
00263 uint32_t Thread::used_stack() {
00264 #ifndef __MBED_CMSIS_RTOS_CA9
00265 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
00266     uint32_t size = 0;
00267     _mutex.lock();
00268 
00269     if (_tid != NULL) {
00270         uint32_t top = (uint32_t)_thread_def.tcb.stack + _thread_def.tcb.priv_stack;
00271         size = top - _thread_def.tcb.tsk_stack;
00272     }
00273 
00274     _mutex.unlock();
00275     return size;
00276 #else
00277     uint32_t size = 0;
00278     _mutex.lock();
00279 
00280     if (_tid != NULL) {
00281         P_TCB tcb = rt_tid2ptcb(_tid);
00282         uint32_t top = (uint32_t)tcb->stack + tcb->priv_stack;
00283         size =  top - tcb->tsk_stack;
00284     }
00285 
00286     _mutex.unlock();
00287     return size;
00288 #endif
00289 #else
00290     return 0;
00291 #endif
00292 }
00293 
00294 uint32_t Thread::max_stack() {
00295 #ifndef __MBED_CMSIS_RTOS_CA9
00296 #if defined(CMSIS_OS_RTX) && !defined(__MBED_CMSIS_RTOS_CM)
00297     uint32_t size = 0;
00298     _mutex.lock();
00299 
00300     if (_tid != NULL) {
00301         uint32_t high_mark = 0;
00302         while (_thread_def.tcb.stack[high_mark] == 0xE25A2EA5)
00303             high_mark++;
00304         size = _thread_def.tcb.priv_stack - (high_mark * 4);
00305     }
00306 
00307     _mutex.unlock();
00308     return size;
00309 #else
00310     uint32_t size = 0;
00311     _mutex.lock();
00312 
00313     if (_tid != NULL) {
00314         P_TCB tcb = rt_tid2ptcb(_tid);
00315         uint32_t high_mark = 0;
00316         while (tcb->stack[high_mark] == 0xE25A2EA5)
00317             high_mark++;
00318         size = tcb->priv_stack - (high_mark * 4);
00319     }
00320 
00321     _mutex.unlock();
00322     return size;
00323 #endif
00324 #else
00325     return 0;
00326 #endif
00327 }
00328 
00329 osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
00330     return osSignalWait(signals, millisec);
00331 }
00332 
00333 osStatus Thread::wait(uint32_t millisec) {
00334     return osDelay(millisec);
00335 }
00336 
00337 osStatus Thread::yield() {
00338     return osThreadYield();
00339 }
00340 
00341 osThreadId Thread::gettid() {
00342     return osThreadGetId();
00343 }
00344 
00345 void Thread::attach_idle_hook(void (*fptr)(void)) {
00346     rtos_attach_idle_hook(fptr);
00347 }
00348 
00349 void Thread::attach_terminate_hook(void (*fptr)(osThreadId id)) {
00350     terminate_hook = fptr;
00351 }
00352 
00353 Thread::~Thread() {
00354     // terminate is thread safe
00355     terminate();
00356 #ifdef __MBED_CMSIS_RTOS_CM
00357     if (_dynamic_stack) {
00358         delete[] (_thread_def.stack_pointer);
00359         _thread_def.stack_pointer = (uint32_t*)NULL;
00360     }
00361 #endif
00362 }
00363 
00364 void Thread::_thunk(const void * thread_ptr)
00365 {
00366     Thread *t = (Thread*)thread_ptr;
00367     t->_task();
00368     t->_mutex.lock();
00369     t->_tid = (osThreadId)NULL;
00370     t->_join_sem.release();
00371     // rtos will release the mutex automatically
00372 }
00373 
00374 }