ChibiOS/RT Architecture - Reference Manual - Guides |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. 00003 00004 This file is part of ChibiOS/RT. 00005 00006 ChibiOS/RT is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 ChibiOS/RT is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 --- 00020 00021 A special exception to the GPL can be applied should you wish to distribute 00022 a combined work that includes ChibiOS/RT, without being obliged to provide 00023 the source code for any proprietary components. See the file exception.txt 00024 for full details of how and when the exception can be applied. 00025 */ 00026 00027 /** 00028 * @file chthreads.c 00029 * @brief Threads code. 00030 * 00031 * @addtogroup threads 00032 * @details Threads related APIs and services. 00033 * 00034 * <h2>Operation mode</h2> 00035 * A thread is an abstraction of an independent instructions flow. 00036 * In ChibiOS/RT a thread is represented by a "C" function owning 00037 * a processor context, state informations and a dedicated stack 00038 * area. In this scenario static variables are shared among all 00039 * threads while automatic variables are local to the thread.<br> 00040 * Operations defined for threads: 00041 * - <b>Init</b>, a thread is prepared and put in the suspended 00042 * state. 00043 * - <b>Create</b>, a thread is started on the specified thread 00044 * function. This operation is available in multiple variants, 00045 * both static and dynamic. 00046 * - <b>Exit</b>, a thread terminates by returning from its top 00047 * level function or invoking a specific API, the thread can 00048 * return a value that can be retrieved by other threads. 00049 * - <b>Wait</b>, a thread waits for the termination of another 00050 * thread and retrieves its return value. 00051 * - <b>Resume</b>, a thread created in suspended state is started. 00052 * - <b>Sleep</b>, the execution of a thread is suspended for the 00053 * specified amount of time or the specified future absolute time 00054 * is reached. 00055 * - <b>SetPriority</b>, a thread changes its own priority level. 00056 * - <b>Yield</b>, a thread voluntarily renounces to its time slot. 00057 * . 00058 * The threads subsystem is implicitly included in kernel however 00059 * some of its part may be excluded by disabling them in @p chconf.h, 00060 * see the @p CH_USE_WAITEXIT and @p CH_USE_DYNAMIC configuration 00061 * options. 00062 * @{ 00063 */ 00064 00065 #include "ch.h" 00066 00067 /** 00068 * @brief Initializes a thread structure. 00069 * 00070 * @param[in] tp pointer to the thread 00071 * @param[in] prio the priority level for the new thread 00072 * @return The same thread pointer passed as parameter. 00073 */ 00074 Thread *init_thread(Thread *tp, tprio_t prio) { 00075 00076 tp->p_prio = prio; 00077 tp->p_state = THD_STATE_SUSPENDED; 00078 tp->p_flags = THD_MEM_MODE_STATIC; 00079 #if CH_USE_MUTEXES 00080 tp->p_realprio = prio; 00081 tp->p_mtxlist = NULL; 00082 #endif 00083 #if CH_USE_EVENTS 00084 tp->p_epending = 0; 00085 #endif 00086 #if CH_USE_NESTED_LOCKS 00087 tp->p_locks = 0; 00088 #endif 00089 #if CH_DBG_THREADS_PROFILING 00090 tp->p_time = 0; 00091 #endif 00092 #if CH_USE_DYNAMIC 00093 tp->p_refs = 1; 00094 #endif 00095 #if CH_USE_WAITEXIT 00096 list_init(&tp->p_waiting); 00097 #endif 00098 #if CH_USE_MESSAGES 00099 queue_init(&tp->p_msgqueue); 00100 #endif 00101 #if CH_USE_REGISTRY 00102 REG_INSERT(tp); 00103 #endif 00104 #if defined(THREAD_EXT_INIT) 00105 THREAD_EXT_INIT(tp); 00106 #endif 00107 return tp; 00108 } 00109 00110 #if CH_DBG_FILL_THREADS 00111 static void memfill(uint8_t *startp, uint8_t *endp, uint8_t v) { 00112 00113 while (startp < endp) 00114 *startp++ = v; 00115 } 00116 #endif 00117 00118 /** 00119 * @brief Creates a new thread into a static memory area. 00120 * @details The new thread is initialized but not inserted in the ready list, 00121 * the initial state is @p THD_STATE_SUSPENDED. 00122 * @note A thread can terminate by calling @p chThdExit() or by simply 00123 * returning from its main function. 00124 * @note Threads created using this function do not obey to the 00125 * @p CH_DBG_FILL_THREADS debug option because it would keep 00126 * the kernel locked for too much time. 00127 * 00128 * @param[out] wsp pointer to a working area dedicated to the thread stack 00129 * @param[in] size size of the working area 00130 * @param[in] prio the priority level for the new thread 00131 * @param[in] pf the thread function 00132 * @param[in] arg an argument passed to the thread function. It can be 00133 * @p NULL. 00134 * @return The pointer to the @p Thread structure allocated for 00135 * the thread into the working space area. 00136 */ 00137 Thread *chThdCreateI(void *wsp, size_t size, 00138 tprio_t prio, tfunc_t pf, void *arg) { 00139 /* Thread structure is layed out in the lower part of the thread workspace */ 00140 Thread *tp = wsp; 00141 00142 chDbgCheck((wsp != NULL) && (size >= THD_WA_SIZE(0)) && 00143 (prio <= HIGHPRIO) && (pf != NULL), 00144 "chThdCreateI"); 00145 SETUP_CONTEXT(wsp, size, pf, arg); 00146 return init_thread(tp, prio); 00147 } 00148 00149 /** 00150 * @brief Creates a new thread into a static memory area. 00151 * @note A thread can terminate by calling @p chThdExit() or by simply 00152 * returning from its main function. 00153 * 00154 * @param[out] wsp pointer to a working area dedicated to the thread stack 00155 * @param[in] size size of the working area 00156 * @param[in] prio the priority level for the new thread 00157 * @param[in] pf the thread function 00158 * @param[in] arg an argument passed to the thread function. It can be 00159 * @p NULL. 00160 * @return The pointer to the @p Thread structure allocated for 00161 * the thread into the working space area. 00162 */ 00163 Thread *chThdCreateStatic(void *wsp, size_t size, 00164 tprio_t prio, tfunc_t pf, void *arg) { 00165 Thread *tp; 00166 00167 #if CH_DBG_FILL_THREADS 00168 memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE); 00169 memfill((uint8_t *)wsp + sizeof(Thread), 00170 (uint8_t *)wsp + size, STACK_FILL_VALUE); 00171 #endif 00172 chSysLock(); 00173 chSchWakeupS(tp = chThdCreateI(wsp, size, prio, pf, arg), RDY_OK); 00174 chSysUnlock(); 00175 return tp; 00176 } 00177 00178 #if CH_USE_DYNAMIC && CH_USE_HEAP 00179 /** 00180 * @brief Creates a new thread allocating the memory from the heap. 00181 * @note A thread can terminate by calling @p chThdExit() or by simply 00182 * returning from its main function. 00183 * @note The memory allocated for the thread is not released when the thread 00184 * terminates but when a @p chThdWait() is performed. 00185 * @note The function is available only if the @p CH_USE_DYNAMIC, 00186 * @p CH_USE_HEAP and @p CH_USE_WAITEXIT options are enabled 00187 * in @p chconf.h. 00188 * 00189 * @param[in] heapp heap from which allocate the memory or @p NULL for the 00190 * default heap 00191 * @param[in] size size of the working area to be allocated 00192 * @param[in] prio the priority level for the new thread 00193 * @param[in] pf the thread function 00194 * @param[in] arg an argument passed to the thread function. It can be 00195 * @p NULL. 00196 * @return The pointer to the @p Thread structure allocated for 00197 * the thread into the working space area. 00198 * @retval NULL if the memory cannot be allocated. 00199 */ 00200 Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size, 00201 tprio_t prio, tfunc_t pf, void *arg) { 00202 void *wsp; 00203 Thread *tp; 00204 00205 wsp = chHeapAlloc(heapp, size); 00206 if (wsp == NULL) 00207 return NULL; 00208 00209 #if CH_DBG_FILL_THREADS 00210 memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE); 00211 memfill((uint8_t *)wsp + sizeof(Thread), 00212 (uint8_t *)wsp + size, STACK_FILL_VALUE); 00213 #endif 00214 00215 chSysLock(); 00216 tp = chThdCreateI(wsp, size, prio, pf, arg); 00217 tp->p_flags = THD_MEM_MODE_HEAP; 00218 chSchWakeupS(tp, RDY_OK); 00219 chSysUnlock(); 00220 return tp; 00221 } 00222 #endif /* CH_USE_DYNAMIC && CH_USE_HEAP */ 00223 00224 #if CH_USE_DYNAMIC && CH_USE_MEMPOOLS 00225 /** 00226 * @brief Creates a new thread allocating the memory from the specified 00227 * memory pool. 00228 * @note A thread can terminate by calling @p chThdExit() or by simply 00229 * returning from its main function. 00230 * @note The memory allocated for the thread is not released when the thread 00231 * terminates but when a @p chThdWait() is performed. 00232 * @note The function is available only if the @p CH_USE_DYNAMIC, 00233 * @p CH_USE_MEMPOOLS and @p CH_USE_WAITEXIT options are enabled 00234 * in @p chconf.h. 00235 * 00236 * @param[in] mp pointer to the memory pool object 00237 * @param[in] prio the priority level for the new thread 00238 * @param[in] pf the thread function 00239 * @param[in] arg an argument passed to the thread function. It can be 00240 * @p NULL. 00241 * @return The pointer to the @p Thread structure allocated for 00242 * the thread into the working space area. 00243 * @retval NULL if the memory pool is empty. 00244 */ 00245 Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio, 00246 tfunc_t pf, void *arg) { 00247 void *wsp; 00248 Thread *tp; 00249 00250 chDbgCheck(mp != NULL, "chThdCreateFromMemoryPool"); 00251 00252 wsp = chPoolAlloc(mp); 00253 if (wsp == NULL) 00254 return NULL; 00255 00256 #if CH_DBG_FILL_THREADS 00257 memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE); 00258 memfill((uint8_t *)wsp + sizeof(Thread), 00259 (uint8_t *)wsp + mp->mp_object_size, STACK_FILL_VALUE); 00260 #endif 00261 00262 chSysLock(); 00263 tp = chThdCreateI(wsp, mp->mp_object_size, prio, pf, arg); 00264 tp->p_flags = THD_MEM_MODE_MEMPOOL; 00265 tp->p_mpool = mp; 00266 chSchWakeupS(tp, RDY_OK); 00267 chSysUnlock(); 00268 return tp; 00269 } 00270 #endif /* CH_USE_DYNAMIC && CH_USE_MEMPOOLS */ 00271 00272 /** 00273 * @brief Changes the running thread priority level then reschedules if 00274 * necessary. 00275 * @note The function returns the real thread priority regardless of the 00276 * current priority that could be higher than the real priority 00277 * because the priority inheritance mechanism. 00278 * 00279 * @param[in] newprio the new priority level of the running thread 00280 * @return The old priority level. 00281 */ 00282 tprio_t chThdSetPriority(tprio_t newprio) { 00283 tprio_t oldprio; 00284 00285 chDbgCheck((newprio >= LOWPRIO) && (newprio <= HIGHPRIO), 00286 "chThdSetPriority"); 00287 00288 chSysLock(); 00289 #if CH_USE_MUTEXES 00290 oldprio = currp->p_realprio; 00291 if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio)) 00292 currp->p_prio = newprio; 00293 currp->p_realprio = newprio; 00294 #else 00295 oldprio = currp->p_prio; 00296 currp->p_prio = newprio; 00297 #endif 00298 chSchRescheduleS(); 00299 chSysUnlock(); 00300 return oldprio; 00301 } 00302 00303 /** 00304 * @brief Resumes a suspended thread. 00305 * @note Use this function to resume threads created with @p chThdInit(). 00306 * 00307 * @param[in] tp pointer to the thread 00308 * @return The pointer to the thread. 00309 */ 00310 Thread *chThdResume(Thread *tp) { 00311 00312 chSysLock(); 00313 chDbgAssert(tp->p_state == THD_STATE_SUSPENDED, 00314 "chThdResume(), #1", 00315 "thread not in THD_STATE_SUSPENDED state"); 00316 chSchWakeupS(tp, RDY_OK); 00317 chSysUnlock(); 00318 return tp; 00319 } 00320 00321 /** 00322 * @brief Requests a thread termination. 00323 * @note The thread is not terminated but a termination request is added to 00324 * its @p p_flags field. The thread can read this status by 00325 * invoking @p chThdShouldTerminate() and then terminate cleanly. 00326 * 00327 * @param[in] tp pointer to the thread 00328 */ 00329 void chThdTerminate(Thread *tp) { 00330 00331 chSysLock(); 00332 tp->p_flags |= THD_TERMINATE; 00333 chSysUnlock(); 00334 } 00335 00336 /** 00337 * @brief Suspends the invoking thread for the specified time. 00338 * 00339 * @param[in] time the delay in system ticks, the special values are 00340 * handled as follow: 00341 * - @a TIME_INFINITE the thread enters an infinite sleep 00342 * state. 00343 * - @a TIME_IMMEDIATE this value is accepted but 00344 * interpreted as a normal time specification not as an 00345 * immediate timeout specification. 00346 * . 00347 */ 00348 void chThdSleep(systime_t time) { 00349 00350 chDbgCheck(time != TIME_INFINITE, "chThdSleep"); 00351 00352 chSysLock(); 00353 chThdSleepS(time); 00354 chSysUnlock(); 00355 } 00356 00357 /** 00358 * @brief Suspends the invoking thread until the system time arrives to the 00359 * specified value. 00360 * 00361 * @param[in] time absolute system time 00362 */ 00363 void chThdSleepUntil(systime_t time) { 00364 00365 chSysLock(); 00366 if ((time -= chTimeNow()) > 0) 00367 chThdSleepS(time); 00368 chSysUnlock(); 00369 } 00370 00371 /** 00372 * @brief Yields the time slot. 00373 * @details Yields the CPU control to the next thread in the ready list with 00374 * equal priority, if any. 00375 */ 00376 void chThdYield(void) { 00377 00378 chSysLock(); 00379 chSchDoYieldS(); 00380 chSysUnlock(); 00381 } 00382 00383 /** 00384 * @brief Terminates the current thread by specifying an exit status code. 00385 * 00386 * @param[in] msg thread exit code. The code can be retrieved by using 00387 * @p chThdWait(). 00388 */ 00389 void chThdExit(msg_t msg) { 00390 Thread *tp = currp; 00391 00392 chSysLock(); 00393 tp->p_u.exitcode = msg; 00394 #if defined(THREAD_EXT_EXIT) 00395 THREAD_EXT_EXIT(tp); 00396 #endif 00397 #if CH_USE_WAITEXIT 00398 while (notempty(&tp->p_waiting)) 00399 chSchReadyI(list_remove(&tp->p_waiting)); 00400 #endif 00401 #if CH_USE_REGISTRY 00402 /* Static threads are immediately removed from the registry because 00403 there is no memory to recover.*/ 00404 if ((tp->p_flags & THD_MEM_MODE_MASK) == THD_MEM_MODE_STATIC) 00405 REG_REMOVE(tp); 00406 #endif 00407 chSchGoSleepS(THD_STATE_FINAL); 00408 } 00409 00410 #if CH_USE_DYNAMIC || defined(__DOXYGEN__) 00411 /** 00412 * @brief Adds a reference to a thread object. 00413 * 00414 * @param[in] tp pointer to the thread 00415 * @return The same thread pointer passed as parameter 00416 * representing the new reference. 00417 */ 00418 Thread *chThdAddRef(Thread *tp) { 00419 00420 chSysLock(); 00421 chDbgAssert(tp->p_refs < 255, "chThdAddRef(), #1", "too many references"); 00422 tp->p_refs++; 00423 chSysUnlock(); 00424 return tp; 00425 } 00426 00427 /** 00428 * @brief Releases a reference to a thread object. 00429 * @details If the references counter reaches zero <b>and</b> the thread 00430 * is in the @p THD_STATE_FINAL state then the thread's memory is 00431 * returned to the proper allocator. 00432 * @note Static threads are not affected. 00433 * 00434 * @param[in] tp pointer to the thread 00435 */ 00436 void chThdRelease(Thread *tp) { 00437 trefs_t refs; 00438 00439 chSysLock(); 00440 chDbgAssert(tp->p_refs > 0, "chThdRelease(), #1", "not referenced"); 00441 refs = --tp->p_refs; 00442 chSysUnlock(); 00443 00444 /* If the references counter reaches zero and the thread is in its 00445 terminated state then the memory can be returned to the proper 00446 allocator. Of course static threads are not affected.*/ 00447 if ((refs == 0) && (tp->p_state == THD_STATE_FINAL)) { 00448 switch (tp->p_flags & THD_MEM_MODE_MASK) { 00449 #if CH_USE_HEAP 00450 case THD_MEM_MODE_HEAP: 00451 #if CH_USE_REGISTRY 00452 REG_REMOVE(tp); 00453 #endif 00454 chHeapFree(tp); 00455 break; 00456 #endif 00457 #if CH_USE_MEMPOOLS 00458 case THD_MEM_MODE_MEMPOOL: 00459 #if CH_USE_REGISTRY 00460 REG_REMOVE(tp); 00461 #endif 00462 chPoolFree(tp->p_mpool, tp); 00463 break; 00464 #endif 00465 } 00466 } 00467 } 00468 #endif /* CH_USE_DYNAMIC */ 00469 00470 #if CH_USE_WAITEXIT || defined(__DOXYGEN__) 00471 /** 00472 * @brief Blocks the execution of the invoking thread until the specified 00473 * thread terminates then the exit code is returned. 00474 * @details This function waits for the specified thread to terminate then 00475 * decrements its reference counter, if the counter reaches zero then 00476 * the thread working area is returned to the proper allocator.<br> 00477 * The memory used by the exited thread is handled in different ways 00478 * depending on the API that spawned the thread: 00479 * - If the thread was spawned by @p chThdCreateStatic() or by 00480 * @p chThdInit() then nothing happens and the thread working area 00481 * is not released or modified in any way. This is the default, 00482 * totally static, behavior. 00483 * - If the thread was spawned by @p chThdCreateFromHeap() then 00484 * the working area is returned to the system heap. 00485 * - If the thread was spawned by @p chThdCreateFromMemoryPool() 00486 * then the working area is returned to the owning memory pool. 00487 * . 00488 * Please read the @ref article_lifecycle article for more details. 00489 * @note After invoking @p chThdWait() the thread pointer becomes invalid 00490 * and must not be used as parameter for further system calls. 00491 * @note The function is available only if the @p CH_USE_WAITEXIT 00492 * option is enabled in @p chconf.h. 00493 * @note If @p CH_USE_DYNAMIC is not specified this function just waits for 00494 * the thread termination, no memory allocators are involved. 00495 * 00496 * @param[in] tp pointer to the thread 00497 * @return The exit code from the terminated thread. 00498 */ 00499 msg_t chThdWait(Thread *tp) { 00500 msg_t msg; 00501 00502 chDbgCheck(tp != NULL, "chThdWait"); 00503 00504 chSysLock(); 00505 chDbgAssert(tp != currp, "chThdWait(), #1", "waiting self"); 00506 #if CH_USE_DYNAMIC 00507 chDbgAssert(tp->p_refs > 0, "chThdWait(), #2", "not referenced"); 00508 #endif 00509 if (tp->p_state != THD_STATE_FINAL) { 00510 list_insert(currp, &tp->p_waiting); 00511 chSchGoSleepS(THD_STATE_WTEXIT); 00512 } 00513 msg = tp->p_u.exitcode; 00514 chSysUnlock(); 00515 #if CH_USE_DYNAMIC 00516 chThdRelease(tp); 00517 #endif 00518 return msg; 00519 } 00520 #endif /* CH_USE_WAITEXIT */ 00521 00522 /** @} */