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 00024 #include "mbed.h" 00025 #include "rtos/rtos_idle.h" 00026 #include "mbed_assert.h" 00027 00028 #define ALIGN_UP(pos, align) ((pos) % (align) ? (pos) + ((align) - (pos) % (align)) : (pos)) 00029 MBED_STATIC_ASSERT(ALIGN_UP(0, 8) == 0, "ALIGN_UP macro error"); 00030 MBED_STATIC_ASSERT(ALIGN_UP(1, 8) == 8, "ALIGN_UP macro error"); 00031 00032 #define ALIGN_DOWN(pos, align) ((pos) - ((pos) % (align))) 00033 MBED_STATIC_ASSERT(ALIGN_DOWN(7, 8) == 0, "ALIGN_DOWN macro error"); 00034 MBED_STATIC_ASSERT(ALIGN_DOWN(8, 8) == 8, "ALIGN_DOWN macro error"); 00035 00036 static void (*terminate_hook)(osThreadId_t id) = 0; 00037 extern "C" void thread_terminate_hook(osThreadId_t id) 00038 { 00039 if (terminate_hook != (void (*)(osThreadId_t))NULL) { 00040 terminate_hook(id); 00041 } 00042 } 00043 00044 namespace rtos { 00045 00046 void Thread::constructor(osPriority priority, 00047 uint32_t stack_size, unsigned char *stack_mem, const char *name) { 00048 00049 const uintptr_t unaligned_mem = reinterpret_cast<uintptr_t>(stack_mem); 00050 const uintptr_t aligned_mem = ALIGN_UP(unaligned_mem, 8); 00051 const uint32_t offset = aligned_mem - unaligned_mem; 00052 const uint32_t aligned_size = ALIGN_DOWN(stack_size - offset, 8); 00053 00054 _tid = 0; 00055 _dynamic_stack = (stack_mem == NULL); 00056 _finished = false; 00057 memset(&_obj_mem, 0, sizeof(_obj_mem)); 00058 memset(&_attr, 0, sizeof(_attr)); 00059 _attr.priority = priority; 00060 _attr.stack_size = aligned_size; 00061 _attr.name = name ? name : "application_unnamed_thread"; 00062 _attr.stack_mem = reinterpret_cast<uint32_t*>(aligned_mem); 00063 } 00064 00065 void Thread::constructor(Callback<void()> task, 00066 osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) { 00067 constructor(priority, stack_size, stack_mem, name); 00068 00069 switch (start(task)) { 00070 case osErrorResource: 00071 error("OS ran out of threads!\n"); 00072 break; 00073 case osErrorParameter: 00074 error("Thread already running!\n"); 00075 break; 00076 case osErrorNoMemory: 00077 error("Error allocating the stack memory\n"); 00078 default: 00079 break; 00080 } 00081 } 00082 00083 osStatus Thread::start(Callback<void()> task) { 00084 _mutex.lock(); 00085 00086 if ((_tid != 0) || _finished) { 00087 _mutex.unlock(); 00088 return osErrorParameter; 00089 } 00090 00091 if (_attr.stack_mem == NULL) { 00092 _attr.stack_mem = new uint32_t[_attr.stack_size/sizeof(uint32_t)]; 00093 MBED_ASSERT(_attr.stack_mem != NULL); 00094 } 00095 00096 //Fill the stack with a magic word for maximum usage checking 00097 for (uint32_t i = 0; i < (_attr.stack_size / sizeof(uint32_t)); i++) { 00098 ((uint32_t *)_attr.stack_mem)[i] = 0xE25A2EA5; 00099 } 00100 00101 memset(&_obj_mem, 0, sizeof(_obj_mem)); 00102 _attr.cb_size = sizeof(_obj_mem); 00103 _attr.cb_mem = &_obj_mem; 00104 _task = task; 00105 _tid = osThreadNew(Thread::_thunk, this, &_attr); 00106 if (_tid == NULL) { 00107 if (_dynamic_stack) { 00108 delete[] (uint32_t *)(_attr.stack_mem); 00109 _attr.stack_mem = (uint32_t*)NULL; 00110 } 00111 _mutex.unlock(); 00112 _join_sem.release(); 00113 return osErrorResource; 00114 } 00115 00116 _mutex.unlock(); 00117 return osOK; 00118 } 00119 00120 osStatus Thread::terminate() { 00121 osStatus_t ret = osOK; 00122 _mutex.lock(); 00123 00124 // Set the Thread's tid to NULL and 00125 // release the semaphore before terminating 00126 // since this thread could be terminating itself 00127 osThreadId_t local_id = _tid; 00128 _join_sem.release(); 00129 _tid = (osThreadId_t)NULL; 00130 if (!_finished) { 00131 _finished = true; 00132 // if local_id == 0 Thread was not started in first place 00133 // and does not have to be terminated 00134 if (local_id != 0) { 00135 ret = osThreadTerminate(local_id); 00136 } 00137 } 00138 _mutex.unlock(); 00139 return ret; 00140 } 00141 00142 osStatus Thread::join() { 00143 int32_t ret = _join_sem.wait(); 00144 if (ret < 0) { 00145 return osError; 00146 } 00147 00148 // The semaphore has been released so this thread is being 00149 // terminated or has been terminated. Once the mutex has 00150 // been locked it is ensured that the thread is deleted. 00151 _mutex.lock(); 00152 MBED_ASSERT(NULL == _tid); 00153 _mutex.unlock(); 00154 00155 // Release sem so any other threads joining this thread wake up 00156 _join_sem.release(); 00157 return osOK; 00158 } 00159 00160 osStatus Thread::set_priority(osPriority priority) { 00161 osStatus_t ret; 00162 _mutex.lock(); 00163 00164 ret = osThreadSetPriority(_tid, priority); 00165 00166 _mutex.unlock(); 00167 return ret; 00168 } 00169 00170 osPriority Thread::get_priority() { 00171 osPriority_t ret; 00172 _mutex.lock(); 00173 00174 ret = osThreadGetPriority(_tid); 00175 00176 _mutex.unlock(); 00177 return ret; 00178 } 00179 00180 int32_t Thread::signal_set(int32_t flags) { 00181 return osThreadFlagsSet(_tid, flags); 00182 } 00183 00184 Thread::State Thread::get_state() { 00185 uint8_t state = osThreadTerminated; 00186 00187 _mutex.lock(); 00188 00189 if (_tid != NULL) { 00190 #if defined(MBED_OS_BACKEND_RTX5) 00191 state = _obj_mem.state; 00192 #else 00193 state = osThreadGetState(_tid); 00194 #endif 00195 } 00196 00197 _mutex.unlock(); 00198 00199 State user_state; 00200 00201 switch(state) { 00202 case osThreadInactive: 00203 user_state = Inactive; 00204 break; 00205 case osThreadReady: 00206 user_state = Ready; 00207 break; 00208 case osThreadRunning: 00209 user_state = Running; 00210 break; 00211 #if defined(MBED_OS_BACKEND_RTX5) 00212 case osRtxThreadWaitingDelay: 00213 user_state = WaitingDelay; 00214 break; 00215 case osRtxThreadWaitingJoin: 00216 user_state = WaitingJoin; 00217 break; 00218 case osRtxThreadWaitingThreadFlags: 00219 user_state = WaitingThreadFlag; 00220 break; 00221 case osRtxThreadWaitingEventFlags: 00222 user_state = WaitingEventFlag; 00223 break; 00224 case osRtxThreadWaitingMutex: 00225 user_state = WaitingMutex; 00226 break; 00227 case osRtxThreadWaitingSemaphore: 00228 user_state = WaitingSemaphore; 00229 break; 00230 case osRtxThreadWaitingMemoryPool: 00231 user_state = WaitingMemoryPool; 00232 break; 00233 case osRtxThreadWaitingMessageGet: 00234 user_state = WaitingMessageGet; 00235 break; 00236 case osRtxThreadWaitingMessagePut: 00237 user_state = WaitingMessagePut; 00238 break; 00239 #endif 00240 case osThreadTerminated: 00241 default: 00242 user_state = Deleted; 00243 break; 00244 } 00245 00246 return user_state; 00247 } 00248 00249 uint32_t Thread::stack_size() { 00250 uint32_t size = 0; 00251 _mutex.lock(); 00252 00253 if (_tid != NULL) { 00254 size = osThreadGetStackSize(_tid); 00255 } 00256 00257 _mutex.unlock(); 00258 return size; 00259 } 00260 00261 uint32_t Thread::free_stack() { 00262 uint32_t size = 0; 00263 _mutex.lock(); 00264 00265 #if defined(MBED_OS_BACKEND_RTX5) 00266 if (_tid != NULL) { 00267 os_thread_t *thread = (os_thread_t *)_tid; 00268 size = (uint32_t)thread->sp - (uint32_t)thread->stack_mem; 00269 } 00270 #endif 00271 00272 _mutex.unlock(); 00273 return size; 00274 } 00275 00276 uint32_t Thread::used_stack() { 00277 uint32_t size = 0; 00278 _mutex.lock(); 00279 00280 #if defined(MBED_OS_BACKEND_RTX5) 00281 if (_tid != NULL) { 00282 os_thread_t *thread = (os_thread_t *)_tid; 00283 size = ((uint32_t)thread->stack_mem + thread->stack_size) - thread->sp; 00284 } 00285 #endif 00286 00287 _mutex.unlock(); 00288 return size; 00289 } 00290 00291 uint32_t Thread::max_stack() { 00292 uint32_t size = 0; 00293 _mutex.lock(); 00294 00295 if (_tid != NULL) { 00296 #if defined(MBED_OS_BACKEND_RTX5) 00297 os_thread_t *thread = (os_thread_t *)_tid; 00298 uint32_t high_mark = 0; 00299 while (((uint32_t *)(thread->stack_mem))[high_mark] == 0xE25A2EA5) 00300 high_mark++; 00301 size = thread->stack_size - (high_mark * sizeof(uint32_t)); 00302 #else 00303 size = osThreadGetStackSize(_tid) - osThreadGetStackSpace(_tid); 00304 #endif 00305 } 00306 00307 _mutex.unlock(); 00308 return size; 00309 } 00310 00311 const char *Thread::get_name() { 00312 return _attr.name; 00313 } 00314 00315 int32_t Thread::signal_clr(int32_t flags) { 00316 return osThreadFlagsClear(flags); 00317 } 00318 00319 osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) { 00320 uint32_t res; 00321 osEvent evt; 00322 uint32_t options = osFlagsWaitAll; 00323 if (signals == 0) { 00324 options = osFlagsWaitAny; 00325 signals = 0x7FFFFFFF; 00326 } 00327 res = osThreadFlagsWait(signals, options, millisec); 00328 if (res & osFlagsError) { 00329 switch (res) { 00330 case osFlagsErrorISR: 00331 evt.status = osErrorISR; 00332 break; 00333 case osFlagsErrorResource: 00334 evt.status = osOK; 00335 break; 00336 case osFlagsErrorTimeout: 00337 evt.status = (osStatus)osEventTimeout; 00338 break; 00339 case osFlagsErrorParameter: 00340 default: 00341 evt.status = (osStatus)osErrorValue; 00342 break; 00343 } 00344 } else { 00345 evt.status = (osStatus)osEventSignal; 00346 evt.value.signals = res; 00347 } 00348 00349 return evt; 00350 } 00351 00352 osStatus Thread::wait(uint32_t millisec) { 00353 return osDelay(millisec); 00354 } 00355 00356 osStatus Thread::wait_until(uint64_t millisec) { 00357 // CMSIS-RTOS 2.1.0 and 2.1.1 differ in the time type, which we determine 00358 // by looking at the return type of osKernelGetTickCount. We assume 00359 // our header at least matches the implementation, so we don't try looking 00360 // at the run-time version report. (There's no compile-time version report) 00361 if (sizeof osKernelGetTickCount() == sizeof(uint64_t)) { 00362 // CMSIS-RTOS 2.1.0 has a 64-bit API. The corresponding RTX 5.2.0 can't 00363 // delay more than 0xfffffffe ticks, but there's no limit stated for 00364 // the generic API. 00365 return osDelayUntil(millisec); 00366 } else { 00367 // 64-bit time doesn't wrap (for half a billion years, at last) 00368 uint64_t now = Kernel::get_ms_count(); 00369 // Report being late on entry 00370 if (now >= millisec) { 00371 return osErrorParameter; 00372 } 00373 // We're about to make a 32-bit delay call, so have at least this limit 00374 if (millisec - now > 0xFFFFFFFF) { 00375 return osErrorParameter; 00376 } 00377 // And this may have its own internal limit - we'll find out. 00378 // We hope/assume there's no problem with passing 00379 // osWaitForever = 0xFFFFFFFF - that value is only specified to have 00380 // special meaning for osSomethingWait calls. 00381 return osDelay(millisec - now); 00382 } 00383 } 00384 00385 osStatus Thread::yield() { 00386 return osThreadYield(); 00387 } 00388 00389 osThreadId Thread::gettid() { 00390 return osThreadGetId(); 00391 } 00392 00393 void Thread::attach_idle_hook(void (*fptr)(void)) { 00394 rtos_attach_idle_hook (fptr); 00395 } 00396 00397 void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) { 00398 terminate_hook = fptr; 00399 } 00400 00401 Thread::~Thread() { 00402 // terminate is thread safe 00403 terminate(); 00404 if (_dynamic_stack) { 00405 delete[] (uint32_t*)(_attr.stack_mem); 00406 _attr.stack_mem = (uint32_t*)NULL; 00407 } 00408 } 00409 00410 void Thread::_thunk(void * thread_ptr) 00411 { 00412 Thread *t = (Thread*)thread_ptr; 00413 t->_task(); 00414 t->_mutex.lock(); 00415 t->_tid = (osThreadId)NULL; 00416 t->_finished = true; 00417 t->_join_sem.release(); 00418 // rtos will release the mutex automatically 00419 } 00420 00421 }
Generated on Tue Jul 12 2022 13:31:36 by
