ChibiOS/RT
2.5.1
chthreads.c
Go to the documentation of this file.
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 /** @} */