ChibiOS/RT
2.5.1
chcond.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    Concepts and parts of this file have been contributed by Leon Woestenberg.
00022  */
00023 
00024 /**
00025  * @file    chcond.c
00026  * @brief   Condition Variables code.
00027  *
00028  * @addtogroup condvars Condition Variables
00029  * @details This module implements the Condition Variables mechanism. Condition
00030  *          variables are an extensions to the Mutex subsystem and cannot
00031  *          work alone.
00032  *          <h2>Operation mode</h2>
00033  *          The condition variable is a synchronization object meant to be
00034  *          used inside a zone protected by a @p Mutex. Mutexes and CondVars
00035  *          together can implement a Monitor construct.
00036  * @pre     In order to use the condition variable APIs the @p CH_USE_CONDVARS
00037  *          option must be enabled in @p chconf.h.
00038  * @{
00039  */
00040 
00041 #include "ch.h"
00042 
00043 #if (CH_USE_CONDVARS && CH_USE_MUTEXES) || defined(__DOXYGEN__)
00044 
00045 /**
00046  * @brief   Initializes s @p CondVar structure.
00047  *
00048  * @param[out] cp       pointer to a @p CondVar structure
00049  *
00050  * @init
00051  */
00052 void chCondInit(CondVar *cp) {
00053 
00054   chDbgCheck(cp != NULL, "chCondInit");
00055 
00056   queue_init(&cp->c_queue);
00057 }
00058 
00059 /**
00060  * @brief   Signals one thread that is waiting on the condition variable.
00061  *
00062  * @param[in] cp        pointer to the @p CondVar structure
00063  *
00064  * @api
00065  */
00066 void chCondSignal(CondVar *cp) {
00067 
00068   chDbgCheck(cp != NULL, "chCondSignal");
00069 
00070   chSysLock();
00071   if (notempty(&cp->c_queue))
00072     chSchWakeupS(fifo_remove(&cp->c_queue), RDY_OK);
00073   chSysUnlock();
00074 }
00075 
00076 /**
00077  * @brief   Signals one thread that is waiting on the condition variable.
00078  * @post    This function does not reschedule so a call to a rescheduling
00079  *          function must be performed before unlocking the kernel. Note that
00080  *          interrupt handlers always reschedule on exit so an explicit
00081  *          reschedule must not be performed in ISRs.
00082  *
00083  * @param[in] cp        pointer to the @p CondVar structure
00084  *
00085  * @iclass
00086  */
00087 void chCondSignalI(CondVar *cp) {
00088 
00089   chDbgCheckClassI();
00090   chDbgCheck(cp != NULL, "chCondSignalI");
00091 
00092   if (notempty(&cp->c_queue))
00093     chSchReadyI(fifo_remove(&cp->c_queue))->p_u.rdymsg = RDY_OK;
00094 }
00095 
00096 /**
00097  * @brief   Signals all threads that are waiting on the condition variable.
00098  *
00099  * @param[in] cp        pointer to the @p CondVar structure
00100  *
00101  * @api
00102  */
00103 void chCondBroadcast(CondVar *cp) {
00104 
00105   chSysLock();
00106   chCondBroadcastI(cp);
00107   chSchRescheduleS();
00108   chSysUnlock();
00109 }
00110 
00111 /**
00112  * @brief   Signals all threads that are waiting on the condition variable.
00113  * @post    This function does not reschedule so a call to a rescheduling
00114  *          function must be performed before unlocking the kernel. Note that
00115  *          interrupt handlers always reschedule on exit so an explicit
00116  *          reschedule must not be performed in ISRs.
00117  *
00118  * @param[in] cp        pointer to the @p CondVar structure
00119  *
00120  * @iclass
00121  */
00122 void chCondBroadcastI(CondVar *cp) {
00123 
00124   chDbgCheckClassI();
00125   chDbgCheck(cp != NULL, "chCondBroadcastI");
00126 
00127   /* Empties the condition variable queue and inserts all the Threads into the
00128      ready list in FIFO order. The wakeup message is set to @p RDY_RESET in
00129      order to make a chCondBroadcast() detectable from a chCondSignal().*/
00130   while (cp->c_queue.p_next != (void *)&cp->c_queue)
00131     chSchReadyI(fifo_remove(&cp->c_queue))->p_u.rdymsg = RDY_RESET;
00132 }
00133 
00134 /**
00135  * @brief   Waits on the condition variable releasing the mutex lock.
00136  * @details Releases the currently owned mutex, waits on the condition
00137  *          variable, and finally acquires the mutex again. All the sequence
00138  *          is performed atomically.
00139  * @pre     The invoking thread <b>must</b> have at least one owned mutex.
00140  *
00141  * @param[in] cp        pointer to the @p CondVar structure
00142  * @return              A message specifying how the invoking thread has been
00143  *                      released from the condition variable.
00144  * @retval RDY_OK       if the condvar has been signaled using
00145  *                      @p chCondSignal().
00146  * @retval RDY_RESET    if the condvar has been signaled using
00147  *                      @p chCondBroadcast().
00148  *
00149  * @api
00150  */
00151 msg_t chCondWait(CondVar *cp) {
00152   msg_t msg;
00153 
00154   chSysLock();
00155   msg = chCondWaitS(cp);
00156   chSysUnlock();
00157   return msg;
00158 }
00159 
00160 /**
00161  * @brief   Waits on the condition variable releasing the mutex lock.
00162  * @details Releases the currently owned mutex, waits on the condition
00163  *          variable, and finally acquires the mutex again. All the sequence
00164  *          is performed atomically.
00165  * @pre     The invoking thread <b>must</b> have at least one owned mutex.
00166  *
00167  * @param[in] cp        pointer to the @p CondVar structure
00168  * @return              A message specifying how the invoking thread has been
00169  *                      released from the condition variable.
00170  * @retval RDY_OK       if the condvar has been signaled using
00171  *                      @p chCondSignal().
00172  * @retval RDY_RESET    if the condvar has been signaled using
00173  *                      @p chCondBroadcast().
00174  *
00175  * @sclass
00176  */
00177 msg_t chCondWaitS(CondVar *cp) {
00178   Thread *ctp = currp;
00179   Mutex *mp;
00180   msg_t msg;
00181 
00182   chDbgCheckClassS();
00183   chDbgCheck(cp != NULL, "chCondWaitS");
00184   chDbgAssert(ctp->p_mtxlist != NULL,
00185               "chCondWaitS(), #1",
00186               "not owning a mutex");
00187 
00188   mp = chMtxUnlockS();
00189   ctp->p_u.wtobjp = cp;
00190   prio_insert(ctp, &cp->c_queue);
00191   chSchGoSleepS(THD_STATE_WTCOND);
00192   msg = ctp->p_u.rdymsg;
00193   chMtxLockS(mp);
00194   return msg;
00195 }
00196 
00197 #if CH_USE_CONDVARS_TIMEOUT || defined(__DOXYGEN__)
00198 /**
00199  * @brief   Waits on the condition variable releasing the mutex lock.
00200  * @details Releases the currently owned mutex, waits on the condition
00201  *          variable, and finally acquires the mutex again. All the sequence
00202  *          is performed atomically.
00203  * @pre     The invoking thread <b>must</b> have at least one owned mutex.
00204  * @pre     The configuration option @p CH_USE_CONDVARS_TIMEOUT must be enabled
00205  *          in order to use this function.
00206  * @post    Exiting the function because a timeout does not re-acquire the
00207  *          mutex, the mutex ownership is lost.
00208  *
00209  * @param[in] cp        pointer to the @p CondVar structure
00210  * @param[in] time      the number of ticks before the operation timeouts, the
00211  *                      special values are handled as follow:
00212  *                      - @a TIME_INFINITE no timeout.
00213  *                      - @a TIME_IMMEDIATE this value is not allowed.
00214  *                      .
00215  * @return              A message specifying how the invoking thread has been
00216  *                      released from the condition variable.
00217  * @retval RDY_OK       if the condvar has been signaled using
00218  *                      @p chCondSignal().
00219  * @retval RDY_RESET    if the condvar has been signaled using
00220  *                      @p chCondBroadcast().
00221  * @retval RDY_TIMEOUT  if the condvar has not been signaled within the
00222  *                      specified timeout.
00223  *
00224  * @api
00225  */
00226 msg_t chCondWaitTimeout(CondVar *cp, systime_t time) {
00227   msg_t msg;
00228 
00229   chSysLock();
00230   msg = chCondWaitTimeoutS(cp, time);
00231   chSysUnlock();
00232   return msg;
00233 }
00234 
00235 /**
00236  * @brief   Waits on the condition variable releasing the mutex lock.
00237  * @details Releases the currently owned mutex, waits on the condition
00238  *          variable, and finally acquires the mutex again. All the sequence
00239  *          is performed atomically.
00240  * @pre     The invoking thread <b>must</b> have at least one owned mutex.
00241  * @pre     The configuration option @p CH_USE_CONDVARS_TIMEOUT must be enabled
00242  *          in order to use this function.
00243  * @post    Exiting the function because a timeout does not re-acquire the
00244  *          mutex, the mutex ownership is lost.
00245  *
00246  * @param[in] cp        pointer to the @p CondVar structure
00247  * @param[in] time      the number of ticks before the operation timeouts, the
00248  *                      special values are handled as follow:
00249  *                      - @a TIME_INFINITE no timeout.
00250  *                      - @a TIME_IMMEDIATE this value is not allowed.
00251  *                      .
00252  * @return              A message specifying how the invoking thread has been
00253  *                      released from the condition variable.
00254  * @retval RDY_OK       if the condvar has been signaled using
00255  *                      @p chCondSignal().
00256  * @retval RDY_RESET    if the condvar has been signaled using
00257  *                      @p chCondBroadcast().
00258  * @retval RDY_TIMEOUT  if the condvar has not been signaled within the
00259  *                      specified timeout.
00260  *
00261  * @sclass
00262  */
00263 msg_t chCondWaitTimeoutS(CondVar *cp, systime_t time) {
00264   Mutex *mp;
00265   msg_t msg;
00266 
00267   chDbgCheckClassS();
00268   chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE), "chCondWaitTimeoutS");
00269   chDbgAssert(currp->p_mtxlist != NULL,
00270               "chCondWaitTimeoutS(), #1",
00271               "not owning a mutex");
00272 
00273   mp = chMtxUnlockS();
00274   currp->p_u.wtobjp = cp;
00275   prio_insert(currp, &cp->c_queue);
00276   msg = chSchGoSleepTimeoutS(THD_STATE_WTCOND, time);
00277   if (msg != RDY_TIMEOUT)
00278     chMtxLockS(mp);
00279   return msg;
00280 }
00281 #endif /* CH_USE_CONDVARS_TIMEOUT */
00282 
00283 #endif /* CH_USE_CONDVARS && CH_USE_MUTEXES */
00284 
00285 /** @} */