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