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 REG_REMOVE(tp); 00403 #endif 00404 chSchGoSleepS(THD_STATE_FINAL); 00405 } 00406 00407 #if CH_USE_DYNAMIC || defined(__DOXYGEN__) 00408 /** 00409 * @brief Adds a reference to a thread object. 00410 * 00411 * @param[in] tp pointer to the thread 00412 * @return The same thread pointer passed as parameter 00413 * representing the new reference. 00414 */ 00415 Thread *chThdAddRef(Thread *tp) { 00416 00417 chSysLock(); 00418 chDbgAssert(tp->p_refs < 255, "chThdAddRef(), #1", "too many references"); 00419 tp->p_refs++; 00420 chSysUnlock(); 00421 return tp; 00422 } 00423 00424 /** 00425 * @brief Releases a reference to a thread object. 00426 * @details If the references counter reaches zero <b>and</b> the thread 00427 * is in the @p THD_STATE_FINAL state then the thread's memory is 00428 * returned to the proper allocator. 00429 * @note Static threads are not affected. 00430 * 00431 * @param[in] tp pointer to the thread 00432 */ 00433 void chThdRelease(Thread *tp) { 00434 trefs_t refs; 00435 00436 chSysLock(); 00437 chDbgAssert(tp->p_refs > 0, "chThdRelease(), #1", "not referenced"); 00438 refs = --tp->p_refs; 00439 chSysUnlock(); 00440 00441 /* If the references counter reaches zero then the memory can be returned 00442 to the proper allocator. Of course static threads are not affected.*/ 00443 if (refs == 0) { 00444 switch (tp->p_flags & THD_MEM_MODE_MASK) { 00445 #if CH_USE_HEAP 00446 case THD_MEM_MODE_HEAP: 00447 chHeapFree(tp); 00448 break; 00449 #endif 00450 #if CH_USE_MEMPOOLS 00451 case THD_MEM_MODE_MEMPOOL: 00452 chPoolFree(tp->p_mpool, tp); 00453 break; 00454 #endif 00455 } 00456 } 00457 } 00458 #endif /* CH_USE_DYNAMIC */ 00459 00460 #if CH_USE_WAITEXIT || defined(__DOXYGEN__) 00461 /** 00462 * @brief Blocks the execution of the invoking thread until the specified 00463 * thread terminates then the exit code is returned. 00464 * @details This function waits for the specified thread to terminate then 00465 * decrements its reference counter, if the counter reaches zero then 00466 * the thread working area is returned to the proper allocator.<br> 00467 * The memory used by the exited thread is handled in different ways 00468 * depending on the API that spawned the thread: 00469 * - If the thread was spawned by @p chThdCreateStatic() or by 00470 * @p chThdInit() then nothing happens and the thread working area 00471 * is not released or modified in any way. This is the default, 00472 * totally static, behavior. 00473 * - If the thread was spawned by @p chThdCreateFromHeap() then 00474 * the working area is returned to the system heap. 00475 * - If the thread was spawned by @p chThdCreateFromMemoryPool() 00476 * then the working area is returned to the owning memory pool. 00477 * . 00478 * Please read the @ref article_lifecycle article for more details. 00479 * @note After invoking @p chThdWait() the thread pointer becomes invalid 00480 * and must not be used as parameter for further system calls. 00481 * @note The function is available only if the @p CH_USE_WAITEXIT 00482 * option is enabled in @p chconf.h. 00483 * @note If @p CH_USE_DYNAMIC is not specified this function just waits for 00484 * the thread termination, no memory allocators are involved. 00485 * 00486 * @param[in] tp pointer to the thread 00487 * @return The exit code from the terminated thread. 00488 */ 00489 msg_t chThdWait(Thread *tp) { 00490 msg_t msg; 00491 00492 chDbgCheck(tp != NULL, "chThdWait"); 00493 00494 chSysLock(); 00495 chDbgAssert(tp != currp, "chThdWait(), #1", "waiting self"); 00496 #if CH_USE_DYNAMIC 00497 chDbgAssert(tp->p_refs > 0, "chThdWait(), #2", "not referenced"); 00498 #endif 00499 if (tp->p_state != THD_STATE_FINAL) { 00500 list_insert(currp, &tp->p_waiting); 00501 chSchGoSleepS(THD_STATE_WTEXIT); 00502 } 00503 msg = tp->p_u.exitcode; 00504 chSysUnlock(); 00505 #if CH_USE_DYNAMIC 00506 chThdRelease(tp); 00507 #endif 00508 return msg; 00509 } 00510 #endif /* CH_USE_WAITEXIT */ 00511 00512 /** @} */