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 ret = osThreadTerminate(local_id); 00133 } 00134 _mutex.unlock(); 00135 return ret; 00136 } 00137 00138 osStatus Thread::join() { 00139 int32_t ret = _join_sem.wait(); 00140 if (ret < 0) { 00141 return osError; 00142 } 00143 00144 // The semaphore has been released so this thread is being 00145 // terminated or has been terminated. Once the mutex has 00146 // been locked it is ensured that the thread is deleted. 00147 _mutex.lock(); 00148 MBED_ASSERT(NULL == _tid); 00149 _mutex.unlock(); 00150 00151 // Release sem so any other threads joining this thread wake up 00152 _join_sem.release(); 00153 return osOK; 00154 } 00155 00156 osStatus Thread::set_priority(osPriority priority) { 00157 osStatus_t ret; 00158 _mutex.lock(); 00159 00160 ret = osThreadSetPriority(_tid, priority); 00161 00162 _mutex.unlock(); 00163 return ret; 00164 } 00165 00166 osPriority Thread::get_priority() { 00167 osPriority_t ret; 00168 _mutex.lock(); 00169 00170 ret = osThreadGetPriority(_tid); 00171 00172 _mutex.unlock(); 00173 return ret; 00174 } 00175 00176 int32_t Thread::signal_set(int32_t flags) { 00177 return osThreadFlagsSet(_tid, flags); 00178 } 00179 00180 Thread::State Thread::get_state() { 00181 uint8_t state = osThreadTerminated; 00182 00183 _mutex.lock(); 00184 00185 if (_tid != NULL) { 00186 #if defined(MBED_OS_BACKEND_RTX5) 00187 state = _obj_mem.state; 00188 #else 00189 state = osThreadGetState(_tid); 00190 #endif 00191 } 00192 00193 _mutex.unlock(); 00194 00195 State user_state; 00196 00197 switch(state) { 00198 case osThreadInactive: 00199 user_state = Inactive; 00200 break; 00201 case osThreadReady: 00202 user_state = Ready; 00203 break; 00204 case osThreadRunning: 00205 user_state = Running; 00206 break; 00207 #if defined(MBED_OS_BACKEND_RTX5) 00208 case osRtxThreadWaitingDelay: 00209 user_state = WaitingDelay; 00210 break; 00211 case osRtxThreadWaitingJoin: 00212 user_state = WaitingJoin; 00213 break; 00214 case osRtxThreadWaitingThreadFlags: 00215 user_state = WaitingThreadFlag; 00216 break; 00217 case osRtxThreadWaitingEventFlags: 00218 user_state = WaitingEventFlag; 00219 break; 00220 case osRtxThreadWaitingMutex: 00221 user_state = WaitingMutex; 00222 break; 00223 case osRtxThreadWaitingSemaphore: 00224 user_state = WaitingSemaphore; 00225 break; 00226 case osRtxThreadWaitingMemoryPool: 00227 user_state = WaitingMemoryPool; 00228 break; 00229 case osRtxThreadWaitingMessageGet: 00230 user_state = WaitingMessageGet; 00231 break; 00232 case osRtxThreadWaitingMessagePut: 00233 user_state = WaitingMessagePut; 00234 break; 00235 #endif 00236 case osThreadTerminated: 00237 default: 00238 user_state = Deleted; 00239 break; 00240 } 00241 00242 return user_state; 00243 } 00244 00245 uint32_t Thread::stack_size() { 00246 uint32_t size = 0; 00247 _mutex.lock(); 00248 00249 if (_tid != NULL) { 00250 size = osThreadGetStackSize(_tid); 00251 } 00252 00253 _mutex.unlock(); 00254 return size; 00255 } 00256 00257 uint32_t Thread::free_stack() { 00258 uint32_t size = 0; 00259 _mutex.lock(); 00260 00261 #if defined(MBED_OS_BACKEND_RTX5) 00262 if (_tid != NULL) { 00263 os_thread_t *thread = (os_thread_t *)_tid; 00264 size = (uint32_t)thread->sp - (uint32_t)thread->stack_mem; 00265 } 00266 #endif 00267 00268 _mutex.unlock(); 00269 return size; 00270 } 00271 00272 uint32_t Thread::used_stack() { 00273 uint32_t size = 0; 00274 _mutex.lock(); 00275 00276 #if defined(MBED_OS_BACKEND_RTX5) 00277 if (_tid != NULL) { 00278 os_thread_t *thread = (os_thread_t *)_tid; 00279 size = ((uint32_t)thread->stack_mem + thread->stack_size) - thread->sp; 00280 } 00281 #endif 00282 00283 _mutex.unlock(); 00284 return size; 00285 } 00286 00287 uint32_t Thread::max_stack() { 00288 uint32_t size = 0; 00289 _mutex.lock(); 00290 00291 if (_tid != NULL) { 00292 #if defined(MBED_OS_BACKEND_RTX5) 00293 os_thread_t *thread = (os_thread_t *)_tid; 00294 uint32_t high_mark = 0; 00295 while (((uint32_t *)(thread->stack_mem))[high_mark] == 0xE25A2EA5) 00296 high_mark++; 00297 size = thread->stack_size - (high_mark * sizeof(uint32_t)); 00298 #else 00299 size = osThreadGetStackSize(_tid) - osThreadGetStackSpace(_tid); 00300 #endif 00301 } 00302 00303 _mutex.unlock(); 00304 return size; 00305 } 00306 00307 const char *Thread::get_name() { 00308 return _attr.name; 00309 } 00310 00311 int32_t Thread::signal_clr(int32_t flags) { 00312 return osThreadFlagsClear(flags); 00313 } 00314 00315 osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) { 00316 uint32_t res; 00317 osEvent evt; 00318 uint32_t options = osFlagsWaitAll; 00319 if (signals == 0) { 00320 options = osFlagsWaitAny; 00321 signals = 0x7FFFFFFF; 00322 } 00323 res = osThreadFlagsWait(signals, options, millisec); 00324 if (res & osFlagsError) { 00325 switch (res) { 00326 case osFlagsErrorISR: 00327 evt.status = osErrorISR; 00328 break; 00329 case osFlagsErrorResource: 00330 evt.status = osOK; 00331 break; 00332 case osFlagsErrorTimeout: 00333 evt.status = (osStatus)osEventTimeout; 00334 break; 00335 case osFlagsErrorParameter: 00336 default: 00337 evt.status = (osStatus)osErrorValue; 00338 break; 00339 } 00340 } else { 00341 evt.status = (osStatus)osEventSignal; 00342 evt.value.signals = res; 00343 } 00344 00345 return evt; 00346 } 00347 00348 osStatus Thread::wait(uint32_t millisec) { 00349 return osDelay(millisec); 00350 } 00351 00352 osStatus Thread::yield() { 00353 return osThreadYield(); 00354 } 00355 00356 osThreadId Thread::gettid() { 00357 return osThreadGetId(); 00358 } 00359 00360 void Thread::attach_idle_hook(void (*fptr)(void)) { 00361 rtos_attach_idle_hook (fptr); 00362 } 00363 00364 void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) { 00365 terminate_hook = fptr; 00366 } 00367 00368 Thread::~Thread() { 00369 // terminate is thread safe 00370 terminate(); 00371 if (_dynamic_stack) { 00372 delete[] (uint32_t*)(_attr.stack_mem); 00373 _attr.stack_mem = (uint32_t*)NULL; 00374 } 00375 } 00376 00377 void Thread::_thunk(void * thread_ptr) 00378 { 00379 Thread *t = (Thread*)thread_ptr; 00380 t->_task(); 00381 t->_mutex.lock(); 00382 t->_tid = (osThreadId)NULL; 00383 t->_finished = true; 00384 t->_join_sem.release(); 00385 // rtos will release the mutex automatically 00386 } 00387 00388 }
Generated on Thu Jul 14 2022 14:36:23 by
