init
Embed:
(wiki syntax)
Show/hide line numbers
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:25:15 by
1.7.2