|
ChibiOS/RT
2.5.1 |
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 /** @} */