Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 #include "rtos/ThisThread.h" 00024 00025 #include "mbed.h" 00026 #include "rtos/rtos_idle.h" 00027 #include "rtos/rtos_handlers.h" 00028 #include "mbed_assert.h" 00029 00030 #define ALIGN_UP(pos, align) ((pos) % (align) ? (pos) + ((align) - (pos) % (align)) : (pos)) 00031 MBED_STATIC_ASSERT(ALIGN_UP(0, 8) == 0, "ALIGN_UP macro error"); 00032 MBED_STATIC_ASSERT(ALIGN_UP(1, 8) == 8, "ALIGN_UP macro error"); 00033 00034 #define ALIGN_DOWN(pos, align) ((pos) - ((pos) % (align))) 00035 MBED_STATIC_ASSERT(ALIGN_DOWN(7, 8) == 0, "ALIGN_DOWN macro error"); 00036 MBED_STATIC_ASSERT(ALIGN_DOWN(8, 8) == 8, "ALIGN_DOWN macro error"); 00037 00038 namespace rtos { 00039 00040 #ifndef MBED_TZ_DEFAULT_ACCESS 00041 #define MBED_TZ_DEFAULT_ACCESS 0 00042 #endif 00043 00044 void Thread::constructor(uint32_t tz_module, osPriority priority, 00045 uint32_t stack_size, unsigned char *stack_mem, const char *name) 00046 { 00047 00048 const uintptr_t unaligned_mem = reinterpret_cast<uintptr_t>(stack_mem); 00049 const uintptr_t aligned_mem = ALIGN_UP(unaligned_mem, 8); 00050 const uint32_t offset = aligned_mem - unaligned_mem; 00051 const uint32_t aligned_size = ALIGN_DOWN(stack_size - offset, 8); 00052 00053 _tid = 0; 00054 _dynamic_stack = (stack_mem == NULL); 00055 _finished = false; 00056 memset(&_obj_mem, 0, sizeof(_obj_mem)); 00057 memset(&_attr, 0, sizeof(_attr)); 00058 _attr.priority = priority; 00059 _attr.stack_size = aligned_size; 00060 _attr.name = name ? name : "application_unnamed_thread"; 00061 _attr.stack_mem = reinterpret_cast<uint32_t *>(aligned_mem); 00062 _attr.tz_module = tz_module; 00063 } 00064 00065 void Thread::constructor(osPriority priority, 00066 uint32_t stack_size, unsigned char *stack_mem, const char *name) 00067 { 00068 constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name); 00069 } 00070 00071 void Thread::constructor(Callback<void()> task, 00072 osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) 00073 { 00074 constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name); 00075 00076 switch (start(task)) { 00077 case osErrorResource: 00078 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_RESOURCES), "OS ran out of threads!\n", task); 00079 break; 00080 case osErrorParameter: 00081 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_ALREADY_IN_USE), "Thread already running!\n", task); 00082 break; 00083 case osErrorNoMemory: 00084 MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Error allocating the stack memory\n", task); 00085 default: 00086 break; 00087 } 00088 } 00089 00090 osStatus Thread::start(Callback<void()> task) 00091 { 00092 _mutex.lock(); 00093 00094 if ((_tid != 0) || _finished) { 00095 _mutex.unlock(); 00096 return osErrorParameter; 00097 } 00098 00099 if (_attr.stack_mem == NULL) { 00100 _attr.stack_mem = new uint32_t[_attr.stack_size / sizeof(uint32_t)]; 00101 MBED_ASSERT(_attr.stack_mem != NULL); 00102 } 00103 00104 //Fill the stack with a magic word for maximum usage checking 00105 for (uint32_t i = 0; i < (_attr.stack_size / sizeof(uint32_t)); i++) { 00106 ((uint32_t *)_attr.stack_mem)[i] = osRtxStackMagicWord; 00107 } 00108 00109 memset(&_obj_mem, 0, sizeof(_obj_mem)); 00110 _attr.cb_size = sizeof(_obj_mem); 00111 _attr.cb_mem = &_obj_mem; 00112 _task = task; 00113 _tid = osThreadNew(Thread::_thunk, this, &_attr); 00114 if (_tid == NULL) { 00115 if (_dynamic_stack) { 00116 delete[](uint32_t *)(_attr.stack_mem); 00117 _attr.stack_mem = (uint32_t *)NULL; 00118 } 00119 _mutex.unlock(); 00120 _join_sem.release(); 00121 return osErrorResource; 00122 } 00123 00124 _mutex.unlock(); 00125 return osOK; 00126 } 00127 00128 osStatus Thread::terminate() 00129 { 00130 osStatus_t ret = osOK; 00131 _mutex.lock(); 00132 00133 // Set the Thread's tid to NULL and 00134 // release the semaphore before terminating 00135 // since this thread could be terminating itself 00136 osThreadId_t local_id = _tid; 00137 _join_sem.release(); 00138 _tid = (osThreadId_t)NULL; 00139 if (!_finished) { 00140 _finished = true; 00141 // if local_id == 0 Thread was not started in first place 00142 // and does not have to be terminated 00143 if (local_id != 0) { 00144 ret = osThreadTerminate(local_id); 00145 } 00146 } 00147 _mutex.unlock(); 00148 return ret; 00149 } 00150 00151 osStatus Thread::join() 00152 { 00153 int32_t ret = _join_sem.wait(); 00154 if (ret < 0) { 00155 return osError; 00156 } 00157 00158 // The semaphore has been released so this thread is being 00159 // terminated or has been terminated. Once the mutex has 00160 // been locked it is ensured that the thread is deleted. 00161 _mutex.lock(); 00162 MBED_ASSERT(NULL == _tid); 00163 _mutex.unlock(); 00164 00165 // Release sem so any other threads joining this thread wake up 00166 _join_sem.release(); 00167 return osOK; 00168 } 00169 00170 osStatus Thread::set_priority(osPriority priority) 00171 { 00172 osStatus_t ret; 00173 _mutex.lock(); 00174 00175 ret = osThreadSetPriority(_tid, priority); 00176 00177 _mutex.unlock(); 00178 return ret; 00179 } 00180 00181 osPriority Thread::get_priority() const 00182 { 00183 osPriority_t ret; 00184 _mutex.lock(); 00185 00186 ret = osThreadGetPriority(_tid); 00187 00188 _mutex.unlock(); 00189 return ret; 00190 } 00191 00192 uint32_t Thread::flags_set(uint32_t flags) 00193 { 00194 flags = osThreadFlagsSet(_tid, flags); 00195 MBED_ASSERT(!(flags & osFlagsError)); 00196 return flags; 00197 } 00198 00199 int32_t Thread::signal_set(int32_t flags) 00200 { 00201 return osThreadFlagsSet(_tid, flags); 00202 } 00203 00204 Thread::State Thread::get_state() const 00205 { 00206 uint8_t state = osThreadTerminated; 00207 00208 _mutex.lock(); 00209 00210 if (_tid != NULL) { 00211 #if defined(MBED_OS_BACKEND_RTX5) 00212 state = _obj_mem.state; 00213 #else 00214 state = osThreadGetState(_tid); 00215 #endif 00216 } 00217 00218 _mutex.unlock(); 00219 00220 State user_state; 00221 00222 switch (state) { 00223 case osThreadInactive: 00224 user_state = Inactive; 00225 break; 00226 case osThreadReady: 00227 user_state = Ready; 00228 break; 00229 case osThreadRunning: 00230 user_state = Running; 00231 break; 00232 #if defined(MBED_OS_BACKEND_RTX5) 00233 case osRtxThreadWaitingDelay: 00234 user_state = WaitingDelay; 00235 break; 00236 case osRtxThreadWaitingJoin: 00237 user_state = WaitingJoin; 00238 break; 00239 case osRtxThreadWaitingThreadFlags: 00240 user_state = WaitingThreadFlag; 00241 break; 00242 case osRtxThreadWaitingEventFlags: 00243 user_state = WaitingEventFlag; 00244 break; 00245 case osRtxThreadWaitingMutex: 00246 user_state = WaitingMutex; 00247 break; 00248 case osRtxThreadWaitingSemaphore: 00249 user_state = WaitingSemaphore; 00250 break; 00251 case osRtxThreadWaitingMemoryPool: 00252 user_state = WaitingMemoryPool; 00253 break; 00254 case osRtxThreadWaitingMessageGet: 00255 user_state = WaitingMessageGet; 00256 break; 00257 case osRtxThreadWaitingMessagePut: 00258 user_state = WaitingMessagePut; 00259 break; 00260 #endif 00261 case osThreadTerminated: 00262 default: 00263 user_state = Deleted; 00264 break; 00265 } 00266 00267 return user_state; 00268 } 00269 00270 uint32_t Thread::stack_size() const 00271 { 00272 uint32_t size = 0; 00273 _mutex.lock(); 00274 00275 if (_tid != NULL) { 00276 size = osThreadGetStackSize(_tid); 00277 } 00278 00279 _mutex.unlock(); 00280 return size; 00281 } 00282 00283 uint32_t Thread::free_stack() const 00284 { 00285 uint32_t size = 0; 00286 _mutex.lock(); 00287 00288 #if defined(MBED_OS_BACKEND_RTX5) 00289 if (_tid != NULL) { 00290 mbed_rtos_storage_thread_t *thread = (mbed_rtos_storage_thread_t *)_tid; 00291 size = (uint32_t)thread->sp - (uint32_t)thread->stack_mem; 00292 } 00293 #endif 00294 00295 _mutex.unlock(); 00296 return size; 00297 } 00298 00299 uint32_t Thread::used_stack() const 00300 { 00301 uint32_t size = 0; 00302 _mutex.lock(); 00303 00304 #if defined(MBED_OS_BACKEND_RTX5) 00305 if (_tid != NULL) { 00306 mbed_rtos_storage_thread_t *thread = (mbed_rtos_storage_thread_t *)_tid; 00307 size = ((uint32_t)thread->stack_mem + thread->stack_size) - thread->sp; 00308 } 00309 #endif 00310 00311 _mutex.unlock(); 00312 return size; 00313 } 00314 00315 uint32_t Thread::max_stack() const 00316 { 00317 uint32_t size = 0; 00318 _mutex.lock(); 00319 00320 if (_tid != NULL) { 00321 #if defined(MBED_OS_BACKEND_RTX5) 00322 mbed_rtos_storage_thread_t *thread = (mbed_rtos_storage_thread_t *)_tid; 00323 uint32_t high_mark = 0; 00324 while ((((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackMagicWord) || (((uint32_t *)(thread->stack_mem))[high_mark] == osRtxStackFillPattern)) { 00325 high_mark++; 00326 } 00327 size = thread->stack_size - (high_mark * sizeof(uint32_t)); 00328 #else 00329 size = osThreadGetStackSize(_tid) - osThreadGetStackSpace(_tid); 00330 #endif 00331 } 00332 00333 _mutex.unlock(); 00334 return size; 00335 } 00336 00337 const char *Thread::get_name() const 00338 { 00339 return _attr.name; 00340 } 00341 00342 osThreadId_t Thread::get_id() const 00343 { 00344 return _tid; 00345 } 00346 00347 int32_t Thread::signal_clr(int32_t flags) 00348 { 00349 return osThreadFlagsClear(flags); 00350 } 00351 00352 osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) 00353 { 00354 uint32_t res; 00355 osEvent evt; 00356 uint32_t options = osFlagsWaitAll; 00357 if (signals == 0) { 00358 options = osFlagsWaitAny; 00359 signals = 0x7FFFFFFF; 00360 } 00361 res = osThreadFlagsWait(signals, options, millisec); 00362 if (res & osFlagsError) { 00363 switch (res) { 00364 case osFlagsErrorISR: 00365 evt.status = osErrorISR; 00366 break; 00367 case osFlagsErrorResource: 00368 evt.status = osOK; 00369 break; 00370 case osFlagsErrorTimeout: 00371 evt.status = (osStatus)osEventTimeout; 00372 break; 00373 case osFlagsErrorParameter: 00374 default: 00375 evt.status = (osStatus)osErrorValue; 00376 break; 00377 } 00378 } else { 00379 evt.status = (osStatus)osEventSignal; 00380 evt.value.signals = res; 00381 } 00382 00383 return evt; 00384 } 00385 00386 osStatus Thread::wait(uint32_t millisec) 00387 { 00388 ThisThread::sleep_for(millisec); 00389 return osOK; 00390 } 00391 00392 osStatus Thread::wait_until(uint64_t millisec) 00393 { 00394 ThisThread::sleep_until(millisec); 00395 return osOK; 00396 } 00397 00398 osStatus Thread::yield() 00399 { 00400 return osThreadYield(); 00401 } 00402 00403 osThreadId Thread::gettid() 00404 { 00405 return osThreadGetId(); 00406 } 00407 00408 void Thread::attach_idle_hook(void (*fptr)(void)) 00409 { 00410 rtos_attach_idle_hook (fptr); 00411 } 00412 00413 void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) 00414 { 00415 rtos_attach_thread_terminate_hook (fptr); 00416 } 00417 00418 Thread::~Thread() 00419 { 00420 // terminate is thread safe 00421 terminate(); 00422 if (_dynamic_stack) { 00423 delete[](uint32_t *)(_attr.stack_mem); 00424 _attr.stack_mem = (uint32_t *)NULL; 00425 } 00426 } 00427 00428 void Thread::_thunk(void *thread_ptr) 00429 { 00430 Thread *t = (Thread *)thread_ptr; 00431 t->_task(); 00432 t->_mutex.lock(); 00433 t->_tid = (osThreadId)NULL; 00434 t->_finished = true; 00435 t->_join_sem.release(); 00436 // rtos will release the mutex automatically 00437 } 00438 00439 }
Generated on Tue Aug 9 2022 00:37:22 by
