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_flags = THD_MEM_MODE_STATIC; 00077 tp->p_prio = prio; 00078 tp->p_state = THD_STATE_SUSPENDED; 00079 #if CH_USE_REGISTRY 00080 REG_INSERT(tp); 00081 #endif 00082 #if CH_USE_DYNAMIC 00083 tp->p_refs = 1; 00084 #endif 00085 #if CH_USE_NESTED_LOCKS 00086 tp->p_locks = 0; 00087 #endif 00088 #if CH_DBG_THREADS_PROFILING 00089 tp->p_time = 0; 00090 #endif 00091 #if CH_USE_MUTEXES 00092 tp->p_realprio = prio; 00093 tp->p_mtxlist = NULL; 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_EVENTS 00102 tp->p_epending = 0; 00103 #endif 00104 THREAD_EXT_INIT(tp); 00105 return tp; 00106 } 00107 00108 #if CH_DBG_FILL_THREADS 00109 static void memfill(uint8_t *startp, uint8_t *endp, uint8_t v) { 00110 00111 while (startp < endp) 00112 *startp++ = v; 00113 } 00114 #endif 00115 00116 /** 00117 * @brief Initializes a new thread. 00118 * @details The new thread is initialized but not inserted in the ready list, 00119 * the initial state is @p THD_STATE_SUSPENDED. 00120 * @note A thread can terminate by calling @p chThdExit() or by simply 00121 * returning from its main function. 00122 * @note This function can be invoked from within an interrupt handler 00123 * even if it is not an I-Class API because it does not touch 00124 * any critical kernel data structure. 00125 * 00126 * @param[out] wsp pointer to a working area dedicated to the thread stack 00127 * @param[in] size size of the working area 00128 * @param[in] prio the priority level for the new thread 00129 * @param[in] pf the thread function 00130 * @param[in] arg an argument passed to the thread function. It can be 00131 * @p NULL. 00132 * @return The pointer to the @p Thread structure allocated for 00133 * the thread into the working space area. 00134 */ 00135 Thread *chThdInit(void *wsp, size_t size, tprio_t prio, tfunc_t pf, void *arg) { 00136 /* Thread structure is layed out in the lower part of the thread workspace */ 00137 Thread *tp = wsp; 00138 00139 chDbgCheck((wsp != NULL) && (size >= THD_WA_SIZE(0)) && 00140 (prio <= HIGHPRIO) && (pf != NULL), 00141 "chThdInit"); 00142 #if CH_DBG_FILL_THREADS 00143 memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE); 00144 memfill((uint8_t *)wsp + sizeof(Thread), 00145 (uint8_t *)wsp + size, STACK_FILL_VALUE); 00146 #endif 00147 SETUP_CONTEXT(wsp, size, pf, arg); 00148 return init_thread(tp, prio); 00149 } 00150 00151 /** 00152 * @brief Creates a new thread into a static memory area. 00153 * @note A thread can terminate by calling @p chThdExit() or by simply 00154 * returning from its main function. 00155 * 00156 * @param[out] wsp pointer to a working area dedicated to the thread stack 00157 * @param[in] size size of the working area 00158 * @param[in] prio the priority level for the new thread 00159 * @param[in] pf the thread function 00160 * @param[in] arg an argument passed to the thread function. It can be 00161 * @p NULL. 00162 * @return The pointer to the @p Thread structure allocated for 00163 * the thread into the working space area. 00164 */ 00165 Thread *chThdCreateStatic(void *wsp, size_t size, 00166 tprio_t prio, tfunc_t pf, void *arg) { 00167 00168 return chThdResume(chThdInit(wsp, size, prio, pf, arg)); 00169 } 00170 00171 #if CH_USE_DYNAMIC && CH_USE_HEAP 00172 /** 00173 * @brief Creates a new thread allocating the memory from the heap. 00174 * @note A thread can terminate by calling @p chThdExit() or by simply 00175 * returning from its main function. 00176 * @note The memory allocated for the thread is not released when the thread 00177 * terminates but when a @p chThdWait() is performed. 00178 * @note The function is available only if the @p CH_USE_DYNAMIC, 00179 * @p CH_USE_HEAP and @p CH_USE_WAITEXIT options are enabled 00180 * in @p chconf.h. 00181 * 00182 * @param[in] heapp heap from which allocate the memory or @p NULL for the 00183 * default heap 00184 * @param[in] size size of the working area to be allocated 00185 * @param[in] prio the priority level for the new thread 00186 * @param[in] pf the thread function 00187 * @param[in] arg an argument passed to the thread function. It can be 00188 * @p NULL. 00189 * @return The pointer to the @p Thread structure allocated for 00190 * the thread into the working space area. 00191 * @retval NULL if the memory cannot be allocated. 00192 */ 00193 Thread *chThdCreateFromHeap(MemoryHeap *heapp, size_t size, 00194 tprio_t prio, tfunc_t pf, void *arg) { 00195 void *wsp; 00196 Thread *tp; 00197 00198 wsp = chHeapAlloc(heapp, size); 00199 if (wsp == NULL) 00200 return NULL; 00201 tp = chThdInit(wsp, size, prio, pf, arg); 00202 tp->p_flags = THD_MEM_MODE_HEAP; 00203 return chThdResume(tp); 00204 } 00205 #endif /* CH_USE_DYNAMIC && CH_USE_HEAP */ 00206 00207 #if CH_USE_DYNAMIC && CH_USE_MEMPOOLS 00208 /** 00209 * @brief Creates a new thread allocating the memory from the specified 00210 * Memory Pool. 00211 * @note A thread can terminate by calling @p chThdExit() or by simply 00212 * returning from its main function. 00213 * @note The memory allocated for the thread is not released when the thread 00214 * terminates but when a @p chThdWait() is performed. 00215 * @note The function is available only if the @p CH_USE_DYNAMIC, 00216 * @p CH_USE_MEMPOOLS and @p CH_USE_WAITEXIT options are enabled 00217 * in @p chconf.h. 00218 * 00219 * @param[in] mp pointer to the memory pool object 00220 * @param[in] prio the priority level for the new thread 00221 * @param[in] pf the thread function 00222 * @param[in] arg an argument passed to the thread function. It can be 00223 * @p NULL. 00224 * @return The pointer to the @p Thread structure allocated for 00225 * the thread into the working space area. 00226 * @retval NULL if the memory pool is empty. 00227 */ 00228 Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio, 00229 tfunc_t pf, void *arg) { 00230 void *wsp; 00231 Thread *tp; 00232 00233 chDbgCheck(mp != NULL, "chThdCreateFromMemoryPool"); 00234 00235 wsp = chPoolAlloc(mp); 00236 if (wsp == NULL) 00237 return NULL; 00238 tp = chThdInit(wsp, mp->mp_object_size, prio, pf, arg); 00239 tp->p_flags = THD_MEM_MODE_MEMPOOL; 00240 tp->p_mpool = mp; 00241 return chThdResume(tp); 00242 } 00243 #endif /* CH_USE_DYNAMIC && CH_USE_MEMPOOLS */ 00244 00245 /** 00246 * @brief Changes the running thread priority level then reschedules if 00247 * necessary. 00248 * @note The function returns the real thread priority regardless of the 00249 * current priority that could be higher than the real priority 00250 * because the priority inheritance mechanism. 00251 * 00252 * @param[in] newprio the new priority level of the running thread 00253 * @return The old priority level. 00254 */ 00255 tprio_t chThdSetPriority(tprio_t newprio) { 00256 tprio_t oldprio; 00257 00258 chDbgCheck((newprio >= LOWPRIO) && (newprio <= HIGHPRIO), 00259 "chThdSetPriority"); 00260 00261 chSysLock(); 00262 #if CH_USE_MUTEXES 00263 oldprio = currp->p_realprio; 00264 if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio)) 00265 currp->p_prio = newprio; 00266 currp->p_realprio = newprio; 00267 #else 00268 oldprio = currp->p_prio; 00269 currp->p_prio = newprio; 00270 #endif 00271 chSchRescheduleS(); 00272 chSysUnlock(); 00273 return oldprio; 00274 } 00275 00276 /** 00277 * @brief Resumes a suspended thread. 00278 * @note Use this function to resume threads created with @p chThdInit(). 00279 * 00280 * @param[in] tp pointer to the thread 00281 * @return The pointer to the thread. 00282 */ 00283 Thread *chThdResume(Thread *tp) { 00284 00285 chSysLock(); 00286 chDbgAssert(tp->p_state == THD_STATE_SUSPENDED, 00287 "chThdResume(), #1", 00288 "thread not in THD_STATE_SUSPENDED state"); 00289 chSchWakeupS(tp, RDY_OK); 00290 chSysUnlock(); 00291 return tp; 00292 } 00293 00294 /** 00295 * @brief Requests a thread termination. 00296 * @note The thread is not terminated but a termination request is added to 00297 * its @p p_flags field. The thread can read this status by 00298 * invoking @p chThdShouldTerminate() and then terminate cleanly. 00299 * 00300 * @param[in] tp pointer to the thread 00301 */ 00302 void chThdTerminate(Thread *tp) { 00303 00304 chSysLock(); 00305 tp->p_flags |= THD_TERMINATE; 00306 chSysUnlock(); 00307 } 00308 00309 /** 00310 * @brief Suspends the invoking thread for the specified time. 00311 * 00312 * @param[in] time the delay in system ticks, the special values are 00313 * handled as follow: 00314 * - @a TIME_INFINITE the thread enters an infinite sleep 00315 * state. 00316 * - @a TIME_IMMEDIATE this value is accepted but 00317 * interpreted as a normal time specification not as an 00318 * immediate timeout specification. 00319 * . 00320 */ 00321 void chThdSleep(systime_t time) { 00322 00323 chDbgCheck(time != TIME_INFINITE, "chThdSleep"); 00324 00325 chSysLock(); 00326 chThdSleepS(time); 00327 chSysUnlock(); 00328 } 00329 00330 /** 00331 * @brief Suspends the invoking thread until the system time arrives to the 00332 * specified value. 00333 * 00334 * @param[in] time absolute system time 00335 */ 00336 void chThdSleepUntil(systime_t time) { 00337 00338 chSysLock(); 00339 if ((time -= chTimeNow()) > 0) 00340 chThdSleepS(time); 00341 chSysUnlock(); 00342 } 00343 00344 /** 00345 * @brief Yields the time slot. 00346 * @details Yields the CPU control to the next thread in the ready list with 00347 * equal priority, if any. 00348 */ 00349 void chThdYield(void) { 00350 00351 chSysLock(); 00352 chSchDoYieldS(); 00353 chSysUnlock(); 00354 } 00355 00356 /** 00357 * @brief Terminates the current thread by specifying an exit status code. 00358 * 00359 * @param[in] msg thread exit code. The code can be retrieved by using 00360 * @p chThdWait(). 00361 */ 00362 void chThdExit(msg_t msg) { 00363 Thread *tp = currp; 00364 00365 chSysLock(); 00366 tp->p_u.exitcode = msg; 00367 THREAD_EXT_EXIT(tp); 00368 #if CH_USE_WAITEXIT 00369 while (notempty(&tp->p_waiting)) 00370 chSchReadyI(list_remove(&tp->p_waiting)); 00371 #endif 00372 #if CH_USE_REGISTRY 00373 REG_REMOVE(tp); 00374 #endif 00375 chSchGoSleepS(THD_STATE_FINAL); 00376 } 00377 00378 #if CH_USE_DYNAMIC || defined(__DOXYGEN__) 00379 /** 00380 * @brief Adds a reference to a thread object. 00381 * 00382 * @param[in] tp pointer to the thread 00383 * @return The same thread pointer passed as parameter 00384 * representing the new reference. 00385 */ 00386 Thread *chThdAddRef(Thread *tp) { 00387 00388 chSysLock(); 00389 chDbgAssert(tp->p_refs < 255, "chThdAddRef(), #1", "too many references"); 00390 tp->p_refs++; 00391 chSysUnlock(); 00392 return tp; 00393 } 00394 00395 /** 00396 * @brief Releases a reference to a thread object. 00397 * @details If the references counter reaches zero <b>and</b> the thread 00398 * is in the @p THD_STATE_FINAL state then the thread's memory is 00399 * returned to the proper allocator. 00400 * @note Static threads are not affected. 00401 * 00402 * @param[in] tp pointer to the thread 00403 */ 00404 void chThdRelease(Thread *tp) { 00405 trefs_t refs; 00406 00407 chSysLock(); 00408 chDbgAssert(tp->p_refs > 0, "chThdRelease(), #1", "not referenced"); 00409 refs = --tp->p_refs; 00410 chSysUnlock(); 00411 00412 /* If the references counter reaches zero then the memory can be returned 00413 to the proper allocator. Of course static threads are not affected.*/ 00414 if (refs == 0) { 00415 switch (tp->p_flags & THD_MEM_MODE_MASK) { 00416 #if CH_USE_HEAP 00417 case THD_MEM_MODE_HEAP: 00418 chHeapFree(tp); 00419 break; 00420 #endif 00421 #if CH_USE_MEMPOOLS 00422 case THD_MEM_MODE_MEMPOOL: 00423 chPoolFree(tp->p_mpool, tp); 00424 break; 00425 #endif 00426 } 00427 } 00428 } 00429 #endif /* CH_USE_DYNAMIC */ 00430 00431 #if CH_USE_WAITEXIT || defined(__DOXYGEN__) 00432 /** 00433 * @brief Blocks the execution of the invoking thread until the specified 00434 * thread terminates then the exit code is returned. 00435 * @details This function waits for the specified thread to terminate then 00436 * decrements its reference counter, if the counter reaches zero then 00437 * the thread working area is returned to the proper allocator.<br> 00438 * The memory used by the exited thread is handled in different ways 00439 * depending on the API that spawned the thread: 00440 * - If the thread was spawned by @p chThdCreateStatic() or by 00441 * @p chThdInit() then nothing happens and the thread working area 00442 * is not released or modified in any way. This is the default, 00443 * totally static, behavior. 00444 * - If the thread was spawned by @p chThdCreateFromHeap() then 00445 * the working area is returned to the system heap. 00446 * - If the thread was spawned by @p chThdCreateFromMemoryPool() 00447 * then the working area is returned to the owning memory pool. 00448 * . 00449 * Please read the @ref article_lifecycle article for more details. 00450 * @note After invoking @p chThdWait() the thread pointer becomes invalid 00451 * and must not be used as parameter for further system calls. 00452 * @note The function is available only if the @p CH_USE_WAITEXIT 00453 * option is enabled in @p chconf.h. 00454 * @note If @p CH_USE_DYNAMIC is not specified this function just waits for 00455 * the thread termination, no memory allocators are involved. 00456 * 00457 * @param[in] tp pointer to the thread 00458 * @return The exit code from the terminated thread. 00459 */ 00460 msg_t chThdWait(Thread *tp) { 00461 msg_t msg; 00462 00463 chDbgCheck(tp != NULL, "chThdWait"); 00464 00465 chSysLock(); 00466 chDbgAssert(tp != currp, "chThdWait(), #1", "waiting self"); 00467 #if CH_USE_DYNAMIC 00468 chDbgAssert(tp->p_refs > 0, "chThdWait(), #2", "not referenced"); 00469 #endif 00470 if (tp->p_state != THD_STATE_FINAL) { 00471 list_insert(currp, &tp->p_waiting); 00472 chSchGoSleepS(THD_STATE_WTEXIT); 00473 } 00474 msg = tp->p_u.exitcode; 00475 chSysUnlock(); 00476 #if CH_USE_DYNAMIC 00477 chThdRelease(tp); 00478 #endif 00479 return msg; 00480 } 00481 #endif /* CH_USE_WAITEXIT */ 00482 00483 /** @} */