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