|
ChibiOS/RT
2.5.1 |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012 Giovanni Di Sirio. 00004 00005 This file is part of ChibiOS/RT. 00006 00007 ChibiOS/RT is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 ChibiOS/RT is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 /** 00022 * @file chthreads.c 00023 * @brief Threads code. 00024 * 00025 * @addtogroup threads 00026 * @details Threads related APIs and services. 00027 * 00028 * <h2>Operation mode</h2> 00029 * A thread is an abstraction of an independent instructions flow. 00030 * In ChibiOS/RT a thread is represented by a "C" function owning 00031 * a processor context, state informations and a dedicated stack 00032 * area. In this scenario static variables are shared among all 00033 * threads while automatic variables are local to the thread.<br> 00034 * Operations defined for threads: 00035 * - <b>Create</b>, a thread is started on the specified thread 00036 * function. This operation is available in multiple variants, 00037 * both static and dynamic. 00038 * - <b>Exit</b>, a thread terminates by returning from its top 00039 * level function or invoking a specific API, the thread can 00040 * return a value that can be retrieved by other threads. 00041 * - <b>Wait</b>, a thread waits for the termination of another 00042 * thread and retrieves its return value. 00043 * - <b>Resume</b>, a thread created in suspended state is started. 00044 * - <b>Sleep</b>, the execution of a thread is suspended for the 00045 * specified amount of time or the specified future absolute time 00046 * is reached. 00047 * - <b>SetPriority</b>, a thread changes its own priority level. 00048 * - <b>Yield</b>, a thread voluntarily renounces to its time slot. 00049 * . 00050 * The threads subsystem is implicitly included in kernel however 00051 * some of its part may be excluded by disabling them in @p chconf.h, 00052 * see the @p CH_USE_WAITEXIT and @p CH_USE_DYNAMIC configuration 00053 * options. 00054 * @{ 00055 */ 00056 00057 #include "ch.h" 00058 00059 /** 00060 * @brief Initializes a thread structure. 00061 * @note This is an internal functions, do not use it in application code. 00062 * 00063 * @param[in] tp pointer to the thread 00064 * @param[in] prio the priority level for the new thread 00065 * @return The same thread pointer passed as parameter. 00066 * 00067 * @notapi 00068 */ 00069 Thread *_thread_init(Thread *tp, tprio_t prio) { 00070 00071 tp->p_prio = prio; 00072 tp->p_state = THD_STATE_SUSPENDED; 00073 tp->p_flags = THD_MEM_MODE_STATIC; 00074 #if CH_TIME_QUANTUM > 0 00075 tp->p_preempt = CH_TIME_QUANTUM; 00076 #endif 00077 #if CH_USE_MUTEXES 00078 tp->p_realprio = prio; 00079 tp->p_mtxlist = NULL; 00080 #endif 00081 #if CH_USE_EVENTS 00082 tp->p_epending = 0; 00083 #endif 00084 #if CH_DBG_THREADS_PROFILING 00085 tp->p_time = 0; 00086 #endif 00087 #if CH_USE_DYNAMIC 00088 tp->p_refs = 1; 00089 #endif 00090 #if CH_USE_REGISTRY 00091 tp->p_name = NULL; 00092 REG_INSERT(tp); 00093 #endif 00094 #if CH_USE_WAITEXIT 00095 list_init(&tp->p_waiting); 00096 #endif 00097 #if CH_USE_MESSAGES 00098 queue_init(&tp->p_msgqueue); 00099 #endif 00100 #if CH_DBG_ENABLE_STACK_CHECK 00101 tp->p_stklimit = (stkalign_t *)(tp + 1); 00102 #endif 00103 #if defined(THREAD_EXT_INIT_HOOK) 00104 THREAD_EXT_INIT_HOOK(tp); 00105 #endif 00106 return tp; 00107 } 00108 00109 #if CH_DBG_FILL_THREADS || defined(__DOXYGEN__) 00110 /** 00111 * @brief Memory fill utility. 00112 * 00113 * @param[in] startp first address to fill 00114 * @param[in] endp last address to fill +1 00115 * @param[in] v filler value 00116 * 00117 * @notapi 00118 */ 00119 void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) { 00120 00121 while (startp < endp) 00122 *startp++ = v; 00123 } 00124 #endif /* CH_DBG_FILL_THREADS */ 00125 00126 /** 00127 * @brief Creates a new thread into a static memory area. 00128 * @details The new thread is initialized but not inserted in the ready list, 00129 * the initial state is @p THD_STATE_SUSPENDED. 00130 * @post The initialized thread can be subsequently started by invoking 00131 * @p chThdResume(), @p chThdResumeI() or @p chSchWakeupS() 00132 * depending on the execution context. 00133 * @note A thread can terminate by calling @p chThdExit() or by simply 00134 * returning from its main function. 00135 * @note Threads created using this function do not obey to the 00136 * @p CH_DBG_FILL_THREADS debug option because it would keep 00137 * the kernel locked for too much time. 00138 * 00139 * @param[out] wsp pointer to a working area dedicated to the thread stack 00140 * @param[in] size size of the working area 00141 * @param[in] prio the priority level for the new thread 00142 * @param[in] pf the thread function 00143 * @param[in] arg an argument passed to the thread function. It can be 00144 * @p NULL. 00145 * @return The pointer to the @p Thread structure allocated for 00146 * the thread into the working space area. 00147 * 00148 * @iclass 00149 */ 00150 Thread *chThdCreateI(void *wsp, size_t size, 00151 tprio_t prio, tfunc_t pf, void *arg) { 00152 /* Thread structure is layed out in the lower part of the thread workspace.*/ 00153 Thread *tp = wsp; 00154 00155 chDbgCheckClassI(); 00156 00157 chDbgCheck((wsp != NULL) && (size >= THD_WA_SIZE(0)) && 00158 (prio <= HIGHPRIO) && (pf != NULL), 00159 "chThdCreateI"); 00160 SETUP_CONTEXT(wsp, size, pf, arg); 00161 return _thread_init(tp, prio); 00162 } 00163 00164 /** 00165 * @brief Creates a new thread into a static memory area. 00166 * @note A thread can terminate by calling @p chThdExit() or by simply 00167 * returning from its main function. 00168 * 00169 * @param[out] wsp pointer to a working area dedicated to the thread stack 00170 * @param[in] size size of the working area 00171 * @param[in] prio the priority level for the new thread 00172 * @param[in] pf the thread function 00173 * @param[in] arg an argument passed to the thread function. It can be 00174 * @p NULL. 00175 * @return The pointer to the @p Thread structure allocated for 00176 * the thread into the working space area. 00177 * 00178 * @api 00179 */ 00180 Thread *chThdCreateStatic(void *wsp, size_t size, 00181 tprio_t prio, tfunc_t pf, void *arg) { 00182 Thread *tp; 00183 00184 #if CH_DBG_FILL_THREADS 00185 _thread_memfill((uint8_t *)wsp, 00186 (uint8_t *)wsp + sizeof(Thread), 00187 CH_THREAD_FILL_VALUE); 00188 _thread_memfill((uint8_t *)wsp + sizeof(Thread), 00189 (uint8_t *)wsp + size, 00190 CH_STACK_FILL_VALUE); 00191 #endif 00192 chSysLock(); 00193 chSchWakeupS(tp = chThdCreateI(wsp, size, prio, pf, arg), RDY_OK); 00194 chSysUnlock(); 00195 return tp; 00196 } 00197 00198 /** 00199 * @brief Changes the running thread priority level then reschedules if 00200 * necessary. 00201 * @note The function returns the real thread priority regardless of the 00202 * current priority that could be higher than the real priority 00203 * because the priority inheritance mechanism. 00204 * 00205 * @param[in] newprio the new priority level of the running thread 00206 * @return The old priority level. 00207 * 00208 * @api 00209 */ 00210 tprio_t chThdSetPriority(tprio_t newprio) { 00211 tprio_t oldprio; 00212 00213 chDbgCheck(newprio <= HIGHPRIO, "chThdSetPriority"); 00214 00215 chSysLock(); 00216 #if CH_USE_MUTEXES 00217 oldprio = currp->p_realprio; 00218 if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio)) 00219 currp->p_prio = newprio; 00220 currp->p_realprio = newprio; 00221 #else 00222 oldprio = currp->p_prio; 00223 currp->p_prio = newprio; 00224 #endif 00225 chSchRescheduleS(); 00226 chSysUnlock(); 00227 return oldprio; 00228 } 00229 00230 /** 00231 * @brief Resumes a suspended thread. 00232 * @pre The specified thread pointer must refer to an initialized thread 00233 * in the @p THD_STATE_SUSPENDED state. 00234 * @post The specified thread is immediately started or put in the ready 00235 * list depending on the relative priority levels. 00236 * @note Use this function to start threads created with @p chThdInit(). 00237 * 00238 * @param[in] tp pointer to the thread 00239 * @return The pointer to the thread. 00240 * 00241 * @api 00242 */ 00243 Thread *chThdResume(Thread *tp) { 00244 00245 chSysLock(); 00246 chDbgAssert(tp->p_state == THD_STATE_SUSPENDED, 00247 "chThdResume(), #1", 00248 "thread not in THD_STATE_SUSPENDED state"); 00249 chSchWakeupS(tp, RDY_OK); 00250 chSysUnlock(); 00251 return tp; 00252 } 00253 00254 /** 00255 * @brief Requests a thread termination. 00256 * @pre The target thread must be written to invoke periodically 00257 * @p chThdShouldTerminate() and terminate cleanly if it returns 00258 * @p TRUE. 00259 * @post The specified thread will terminate after detecting the termination 00260 * condition. 00261 * 00262 * @param[in] tp pointer to the thread 00263 * 00264 * @api 00265 */ 00266 void chThdTerminate(Thread *tp) { 00267 00268 chSysLock(); 00269 tp->p_flags |= THD_TERMINATE; 00270 chSysUnlock(); 00271 } 00272 00273 /** 00274 * @brief Suspends the invoking thread for the specified time. 00275 * 00276 * @param[in] time the delay in system ticks, the special values are 00277 * handled as follow: 00278 * - @a TIME_INFINITE the thread enters an infinite sleep 00279 * state. 00280 * - @a TIME_IMMEDIATE this value is not allowed. 00281 * . 00282 * 00283 * @api 00284 */ 00285 void chThdSleep(systime_t time) { 00286 00287 chDbgCheck(time != TIME_IMMEDIATE, "chThdSleep"); 00288 00289 chSysLock(); 00290 chThdSleepS(time); 00291 chSysUnlock(); 00292 } 00293 00294 /** 00295 * @brief Suspends the invoking thread until the system time arrives to the 00296 * specified value. 00297 * 00298 * @param[in] time absolute system time 00299 * 00300 * @api 00301 */ 00302 void chThdSleepUntil(systime_t time) { 00303 00304 chSysLock(); 00305 if ((time -= chTimeNow()) > 0) 00306 chThdSleepS(time); 00307 chSysUnlock(); 00308 } 00309 00310 /** 00311 * @brief Yields the time slot. 00312 * @details Yields the CPU control to the next thread in the ready list with 00313 * equal priority, if any. 00314 * 00315 * @api 00316 */ 00317 void chThdYield(void) { 00318 00319 chSysLock(); 00320 chSchDoYieldS(); 00321 chSysUnlock(); 00322 } 00323 00324 /** 00325 * @brief Terminates the current thread. 00326 * @details The thread goes in the @p THD_STATE_FINAL state holding the 00327 * specified exit status code, other threads can retrieve the 00328 * exit status code by invoking the function @p chThdWait(). 00329 * @post Eventual code after this function will never be executed, 00330 * this function never returns. The compiler has no way to 00331 * know this so do not assume that the compiler would remove 00332 * the dead code. 00333 * 00334 * @param[in] msg thread exit code 00335 * 00336 * @api 00337 */ 00338 void chThdExit(msg_t msg) { 00339 00340 chSysLock(); 00341 chThdExitS(msg); 00342 /* The thread never returns here.*/ 00343 } 00344 00345 /** 00346 * @brief Terminates the current thread. 00347 * @details The thread goes in the @p THD_STATE_FINAL state holding the 00348 * specified exit status code, other threads can retrieve the 00349 * exit status code by invoking the function @p chThdWait(). 00350 * @post Eventual code after this function will never be executed, 00351 * this function never returns. The compiler has no way to 00352 * know this so do not assume that the compiler would remove 00353 * the dead code. 00354 * 00355 * @param[in] msg thread exit code 00356 * 00357 * @sclass 00358 */ 00359 void chThdExitS(msg_t msg) { 00360 Thread *tp = currp; 00361 00362 tp->p_u.exitcode = msg; 00363 #if defined(THREAD_EXT_EXIT_HOOK) 00364 THREAD_EXT_EXIT_HOOK(tp); 00365 #endif 00366 #if CH_USE_WAITEXIT 00367 while (notempty(&tp->p_waiting)) 00368 chSchReadyI(list_remove(&tp->p_waiting)); 00369 #endif 00370 #if CH_USE_REGISTRY 00371 /* Static threads are immediately removed from the registry because 00372 there is no memory to recover.*/ 00373 if ((tp->p_flags & THD_MEM_MODE_MASK) == THD_MEM_MODE_STATIC) 00374 REG_REMOVE(tp); 00375 #endif 00376 chSchGoSleepS(THD_STATE_FINAL); 00377 /* The thread never returns here.*/ 00378 chDbgAssert(FALSE, "chThdExitS(), #1", "zombies apocalypse"); 00379 } 00380 00381 #if CH_USE_WAITEXIT || defined(__DOXYGEN__) 00382 /** 00383 * @brief Blocks the execution of the invoking thread until the specified 00384 * thread terminates then the exit code is returned. 00385 * @details This function waits for the specified thread to terminate then 00386 * decrements its reference counter, if the counter reaches zero then 00387 * the thread working area is returned to the proper allocator.<br> 00388 * The memory used by the exited thread is handled in different ways 00389 * depending on the API that spawned the thread: 00390 * - If the thread was spawned by @p chThdCreateStatic() or by 00391 * @p chThdInit() then nothing happens and the thread working area 00392 * is not released or modified in any way. This is the default, 00393 * totally static, behavior. 00394 * - If the thread was spawned by @p chThdCreateFromHeap() then 00395 * the working area is returned to the system heap. 00396 * - If the thread was spawned by @p chThdCreateFromMemoryPool() 00397 * then the working area is returned to the owning memory pool. 00398 * . 00399 * @pre The configuration option @p CH_USE_WAITEXIT must be enabled in 00400 * order to use this function. 00401 * @post Enabling @p chThdWait() requires 2-4 (depending on the 00402 * architecture) extra bytes in the @p Thread structure. 00403 * @post After invoking @p chThdWait() the thread pointer becomes invalid 00404 * and must not be used as parameter for further system calls. 00405 * @note If @p CH_USE_DYNAMIC is not specified this function just waits for 00406 * the thread termination, no memory allocators are involved. 00407 * 00408 * @param[in] tp pointer to the thread 00409 * @return The exit code from the terminated thread. 00410 * 00411 * @api 00412 */ 00413 msg_t chThdWait(Thread *tp) { 00414 msg_t msg; 00415 00416 chDbgCheck(tp != NULL, "chThdWait"); 00417 00418 chSysLock(); 00419 chDbgAssert(tp != currp, "chThdWait(), #1", "waiting self"); 00420 #if CH_USE_DYNAMIC 00421 chDbgAssert(tp->p_refs > 0, "chThdWait(), #2", "not referenced"); 00422 #endif 00423 if (tp->p_state != THD_STATE_FINAL) { 00424 list_insert(currp, &tp->p_waiting); 00425 chSchGoSleepS(THD_STATE_WTEXIT); 00426 } 00427 msg = tp->p_u.exitcode; 00428 chSysUnlock(); 00429 #if CH_USE_DYNAMIC 00430 chThdRelease(tp); 00431 #endif 00432 return msg; 00433 } 00434 #endif /* CH_USE_WAITEXIT */ 00435 00436 /** @} */