ChibiOS/RT  6.1.4
chcond.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
3  2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
4 
5  This file is part of ChibiOS.
6 
7  ChibiOS is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation version 3 of the License.
10 
11  ChibiOS is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /*
20  Concepts and parts of this file have been contributed by Leon Woestenberg.
21  */
22 
23 /**
24  * @file rt/src/chcond.c
25  * @brief Condition Variables code.
26  *
27  * @addtogroup condvars
28  * @details This module implements the Condition Variables mechanism. Condition
29  * variables are an extensions to the mutex subsystem and cannot
30  * work alone.
31  * <h2>Operation mode</h2>
32  * The condition variable is a synchronization object meant to be
33  * used inside a zone protected by a mutex. Mutexes and condition
34  * variables together can implement a Monitor construct.
35  * @pre In order to use the condition variable APIs the @p CH_CFG_USE_CONDVARS
36  * option must be enabled in @p chconf.h.
37  * @{
38  */
39 
40 #include "ch.h"
41 
42 #if (CH_CFG_USE_CONDVARS == TRUE) || defined(__DOXYGEN__)
43 
44 /*===========================================================================*/
45 /* Module local definitions. */
46 /*===========================================================================*/
47 
48 /*===========================================================================*/
49 /* Module exported variables. */
50 /*===========================================================================*/
51 
52 /*===========================================================================*/
53 /* Module local types. */
54 /*===========================================================================*/
55 
56 /*===========================================================================*/
57 /* Module local variables. */
58 /*===========================================================================*/
59 
60 /*===========================================================================*/
61 /* Module local functions. */
62 /*===========================================================================*/
63 
64 /*===========================================================================*/
65 /* Module exported functions. */
66 /*===========================================================================*/
67 
68 /**
69  * @brief Initializes s @p condition_variable_t structure.
70  *
71  * @param[out] cp pointer to a @p condition_variable_t structure
72  *
73  * @init
74  */
76 
77  chDbgCheck(cp != NULL);
78 
79  ch_queue_init(&cp->queue);
80 }
81 
82 /**
83  * @brief Signals one thread that is waiting on the condition variable.
84  *
85  * @param[in] cp pointer to the @p condition_variable_t structure
86  *
87  * @api
88  */
90 
91  chDbgCheck(cp != NULL);
92 
93  chSysLock();
94  if (ch_queue_notempty(&cp->queue)) {
96  }
97  chSysUnlock();
98 }
99 
100 /**
101  * @brief Signals one thread that is waiting on the condition variable.
102  * @post This function does not reschedule so a call to a rescheduling
103  * function must be performed before unlocking the kernel. Note that
104  * interrupt handlers always reschedule on exit so an explicit
105  * reschedule must not be performed in ISRs.
106  *
107  * @param[in] cp pointer to the @p condition_variable_t structure
108  *
109  * @iclass
110  */
112 
114  chDbgCheck(cp != NULL);
115 
116  if (ch_queue_notempty(&cp->queue)) {
118  tp->u.rdymsg = MSG_OK;
119  (void) chSchReadyI(tp);
120  }
121 }
122 
123 /**
124  * @brief Signals all threads that are waiting on the condition variable.
125  *
126  * @param[in] cp pointer to the @p condition_variable_t structure
127  *
128  * @api
129  */
131 
132  chSysLock();
133  chCondBroadcastI(cp);
135  chSysUnlock();
136 }
137 
138 /**
139  * @brief Signals all threads that are waiting on the condition variable.
140  * @post This function does not reschedule so a call to a rescheduling
141  * function must be performed before unlocking the kernel. Note that
142  * interrupt handlers always reschedule on exit so an explicit
143  * reschedule must not be performed in ISRs.
144  *
145  * @param[in] cp pointer to the @p condition_variable_t structure
146  *
147  * @iclass
148  */
150 
152  chDbgCheck(cp != NULL);
153 
154  /* Empties the condition variable queue and inserts all the threads into the
155  ready list in FIFO order. The wakeup message is set to @p MSG_RESET in
156  order to make a chCondBroadcast() detectable from a chCondSignal().*/
157  while (ch_queue_notempty(&cp->queue)) {
159  }
160 }
161 
162 /**
163  * @brief Waits on the condition variable releasing the mutex lock.
164  * @details Releases the currently owned mutex, waits on the condition
165  * variable, and finally acquires the mutex again. All the sequence
166  * is performed atomically.
167  * @pre The invoking thread <b>must</b> have at least one owned mutex.
168  *
169  * @param[in] cp pointer to the @p condition_variable_t structure
170  * @return A message specifying how the invoking thread has been
171  * released from the condition variable.
172  * @retval MSG_OK if the condition variable has been signaled using
173  * @p chCondSignal().
174  * @retval MSG_RESET if the condition variable has been signaled using
175  * @p chCondBroadcast().
176  *
177  * @api
178  */
180  msg_t msg;
181 
182  chSysLock();
183  msg = chCondWaitS(cp);
184  chSysUnlock();
185  return msg;
186 }
187 
188 /**
189  * @brief Waits on the condition variable releasing the mutex lock.
190  * @details Releases the currently owned mutex, waits on the condition
191  * variable, and finally acquires the mutex again. All the sequence
192  * is performed atomically.
193  * @pre The invoking thread <b>must</b> have at least one owned mutex.
194  *
195  * @param[in] cp pointer to the @p condition_variable_t structure
196  * @return A message specifying how the invoking thread has been
197  * released from the condition variable.
198  * @retval MSG_OK if the condition variable has been signaled using
199  * @p chCondSignal().
200  * @retval MSG_RESET if the condition variable has been signaled using
201  * @p chCondBroadcast().
202  *
203  * @sclass
204  */
206  thread_t *ctp = currp;
207  mutex_t *mp = chMtxGetNextMutexX();
208  msg_t msg;
209 
211  chDbgCheck(cp != NULL);
212  chDbgAssert(mp != NULL, "not owning a mutex");
213 
214  /* Releasing "current" mutex.*/
215  chMtxUnlockS(mp);
216 
217  /* Start waiting on the condition variable, on exit the mutex is taken
218  again.*/
219  ctp->u.wtobjp = cp;
220  ch_sch_prio_insert(&ctp->hdr.queue, &cp->queue);
222  msg = ctp->u.rdymsg;
223  chMtxLockS(mp);
224 
225  return msg;
226 }
227 
228 #if (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE) || defined(__DOXYGEN__)
229 /**
230  * @brief Waits on the condition variable releasing the mutex lock.
231  * @details Releases the currently owned mutex, waits on the condition
232  * variable, and finally acquires the mutex again. All the sequence
233  * is performed atomically.
234  * @pre The invoking thread <b>must</b> have at least one owned mutex.
235  * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled
236  * in order to use this function.
237  * @post Exiting the function because a timeout does not re-acquire the
238  * mutex, the mutex ownership is lost.
239  *
240  * @param[in] cp pointer to the @p condition_variable_t structure
241  * @param[in] timeout the number of ticks before the operation timeouts, the
242  * special values are handled as follow:
243  * - @a TIME_INFINITE no timeout.
244  * - @a TIME_IMMEDIATE this value is not allowed.
245  * .
246  * @return A message specifying how the invoking thread has been
247  * released from the condition variable.
248  * @retval MSG_OK if the condition variable has been signaled using
249  * @p chCondSignal().
250  * @retval MSG_RESET if the condition variable has been signaled using
251  * @p chCondBroadcast().
252  * @retval MSG_TIMEOUT if the condition variable has not been signaled within
253  * the specified timeout.
254  *
255  * @api
256  */
258  msg_t msg;
259 
260  chSysLock();
261  msg = chCondWaitTimeoutS(cp, timeout);
262  chSysUnlock();
263 
264  return msg;
265 }
266 
267 /**
268  * @brief Waits on the condition variable releasing the mutex lock.
269  * @details Releases the currently owned mutex, waits on the condition
270  * variable, and finally acquires the mutex again. All the sequence
271  * is performed atomically.
272  * @pre The invoking thread <b>must</b> have at least one owned mutex.
273  * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled
274  * in order to use this function.
275  * @post Exiting the function because a timeout does not re-acquire the
276  * mutex, the mutex ownership is lost.
277  *
278  * @param[in] cp pointer to the @p condition_variable_t structure
279  * @param[in] timeout the number of ticks before the operation timeouts, the
280  * special values are handled as follow:
281  * - @a TIME_INFINITE no timeout.
282  * - @a TIME_IMMEDIATE this value is not allowed.
283  * .
284  * @return A message specifying how the invoking thread has been
285  * released from the condition variable.
286  * @retval MSG_OK if the condition variable has been signaled using
287  * @p chCondSignal().
288  * @retval MSG_RESET if the condition variable has been signaled using
289  * @p chCondBroadcast().
290  * @retval MSG_TIMEOUT if the condition variable has not been signaled within
291  * the specified timeout.
292  *
293  * @sclass
294  */
296  mutex_t *mp = chMtxGetNextMutexX();
297  msg_t msg;
298 
300  chDbgCheck((cp != NULL) && (timeout != TIME_IMMEDIATE));
301  chDbgAssert(mp != NULL, "not owning a mutex");
302 
303  /* Releasing "current" mutex.*/
304  chMtxUnlockS(mp);
305 
306  /* Start waiting on the condition variable, on exit the mutex is taken
307  again.*/
308  currp->u.wtobjp = cp;
309  ch_sch_prio_insert(&currp->hdr.queue, &cp->queue);
310  msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, timeout);
311  if (msg != MSG_TIMEOUT) {
312  chMtxLockS(mp);
313  }
314 
315  return msg;
316 }
317 #endif /* CH_CFG_USE_CONDVARS_TIMEOUT == TRUE */
318 
319 #endif /* CH_CFG_USE_CONDVARS == TRUE */
320 
321 /** @} */
chCondSignal
void chCondSignal(condition_variable_t *cp)
Signals one thread that is waiting on the condition variable.
Definition: chcond.c:89
chSysLock
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:355
chCondBroadcast
void chCondBroadcast(condition_variable_t *cp)
Signals all threads that are waiting on the condition variable.
Definition: chcond.c:130
chSchReadyI
thread_t * chSchReadyI(thread_t *tp)
Inserts a thread in the Ready List placing it behind its peers.
Definition: chschd.c:153
currp
#define currp
Current thread pointer access macro.
Definition: chschd.h:462
ch_thread::rdymsg
msg_t rdymsg
Thread wakeup code.
Definition: chschd.h:201
MSG_RESET
#define MSG_RESET
Wakeup caused by a reset condition.
Definition: chschd.h:42
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:127
chCondSignalI
void chCondSignalI(condition_variable_t *cp)
Signals one thread that is waiting on the condition variable.
Definition: chcond.c:111
ch_sch_prio_insert
void ch_sch_prio_insert(ch_queue_t *tp, ch_queue_t *qp)
Inserts a thread into a priority ordered queue.
Definition: chschd.c:109
ch_queue_notempty
static bool ch_queue_notempty(const ch_queue_t *qp)
Evaluates to true if the specified queue is not empty.
Definition: chlists.h:234
CH_STATE_WTCOND
#define CH_STATE_WTCOND
On a cond.variable.
Definition: chschd.h:70
chSchGoSleepTimeoutS
msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout)
Puts the current thread to sleep into the specified state with timeout specification.
Definition: chschd.c:258
chDbgCheck
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:101
condition_variable::queue
ch_queue_t queue
Condition variable threads queue.
Definition: chcond.h:60
TIME_IMMEDIATE
#define TIME_IMMEDIATE
Zero interval specification for some functions with a timeout specification.
Definition: chtime.h:47
ch_thread
Structure representing a thread.
Definition: chschd.h:134
chCondWaitTimeout
msg_t chCondWaitTimeout(condition_variable_t *cp, sysinterval_t timeout)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:257
chSchGoSleepS
void chSchGoSleepS(tstate_t newstate)
Puts the current thread to sleep into the specified state.
Definition: chschd.c:210
chCondWait
msg_t chCondWait(condition_variable_t *cp)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:179
ch_queue_fifo_remove
static ch_queue_t * ch_queue_fifo_remove(ch_queue_t *qp)
Removes the first-out element from a queue and returns it.
Definition: chlists.h:265
chMtxGetNextMutexX
static mutex_t * chMtxGetNextMutexX(void)
Returns the next mutex in the mutexes stack of the current thread.
Definition: chmtx.h:159
ch_thread::u
union ch_thread::@1 u
State-specific fields.
ch_thread::wtobjp
void * wtobjp
Pointer to a generic "wait" object.
Definition: chschd.h:215
chSchRescheduleS
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:339
ch_queue_init
static void ch_queue_init(ch_queue_t *qp)
Queue initialization.
Definition: chlists.h:207
chDbgCheckClassI
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:233
chCondWaitTimeoutS
msg_t chCondWaitTimeoutS(condition_variable_t *cp, sysinterval_t timeout)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:295
MSG_OK
#define MSG_OK
Normal wakeup message.
Definition: chschd.h:39
ch_mutex
Mutex structure.
Definition: chmtx.h:57
sysinterval_t
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
chMtxUnlockS
void chMtxUnlockS(mutex_t *mp)
Unlocks the specified mutex.
Definition: chmtx.c:413
ch_thread::queue
ch_queue_t queue
Threads queues element.
Definition: chschd.h:137
chMtxLockS
void chMtxLockS(mutex_t *mp)
Locks the specified mutex.
Definition: chmtx.c:139
ch.h
ChibiOS/RT main include file.
condition_variable
condition_variable_t structure.
Definition: chcond.h:59
MSG_TIMEOUT
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition: chschd.h:40
chSysUnlock
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:367
chCondBroadcastI
void chCondBroadcastI(condition_variable_t *cp)
Signals all threads that are waiting on the condition variable.
Definition: chcond.c:149
chDbgCheckClassS
void chDbgCheckClassS(void)
S-class functions context check.
Definition: chdebug.c:248
chCondWaitS
msg_t chCondWaitS(condition_variable_t *cp)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:205
chCondObjectInit
void chCondObjectInit(condition_variable_t *cp)
Initializes s condition_variable_t structure.
Definition: chcond.c:75
chSchWakeupS
void chSchWakeupS(thread_t *ntp, msg_t msg)
Wakes up a thread.
Definition: chschd.c:295