ChibiOS/RT  5.1.0
chcond.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
3 
4  This file is part of ChibiOS.
5 
6  ChibiOS is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
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 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  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 (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 (queue_notempty(&cp->queue)) {
117  thread_t *tp = queue_fifo_remove(&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 (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;
208  msg_t msg;
209 
211  chDbgCheck(cp != NULL);
212  chDbgAssert(ctp->mtxlist != NULL, "not owning a mutex");
213 
214  /* Getting "current" mutex and releasing it.*/
215  mp = chMtxGetNextMutexS();
216  chMtxUnlockS(mp);
217 
218  /* Start waiting on the condition variable, on exit the mutex is taken
219  again.*/
220  ctp->u.wtobjp = cp;
221  queue_prio_insert(ctp, &cp->queue);
223  msg = ctp->u.rdymsg;
224  chMtxLockS(mp);
225 
226  return msg;
227 }
228 
229 #if (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE) || defined(__DOXYGEN__)
230 /**
231  * @brief Waits on the condition variable releasing the mutex lock.
232  * @details Releases the currently owned mutex, waits on the condition
233  * variable, and finally acquires the mutex again. All the sequence
234  * is performed atomically.
235  * @pre The invoking thread <b>must</b> have at least one owned mutex.
236  * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled
237  * in order to use this function.
238  * @post Exiting the function because a timeout does not re-acquire the
239  * mutex, the mutex ownership is lost.
240  *
241  * @param[in] cp pointer to the @p condition_variable_t structure
242  * @param[in] timeout the number of ticks before the operation timeouts, the
243  * special values are handled as follow:
244  * - @a TIME_INFINITE no timeout.
245  * - @a TIME_IMMEDIATE this value is not allowed.
246  * .
247  * @return A message specifying how the invoking thread has been
248  * released from the condition variable.
249  * @retval MSG_OK if the condition variable has been signaled using
250  * @p chCondSignal().
251  * @retval MSG_RESET if the condition variable has been signaled using
252  * @p chCondBroadcast().
253  * @retval MSG_TIMEOUT if the condition variable has not been signaled within
254  * the specified timeout.
255  *
256  * @api
257  */
259  msg_t msg;
260 
261  chSysLock();
262  msg = chCondWaitTimeoutS(cp, timeout);
263  chSysUnlock();
264 
265  return msg;
266 }
267 
268 /**
269  * @brief Waits on the condition variable releasing the mutex lock.
270  * @details Releases the currently owned mutex, waits on the condition
271  * variable, and finally acquires the mutex again. All the sequence
272  * is performed atomically.
273  * @pre The invoking thread <b>must</b> have at least one owned mutex.
274  * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled
275  * in order to use this function.
276  * @post Exiting the function because a timeout does not re-acquire the
277  * mutex, the mutex ownership is lost.
278  *
279  * @param[in] cp pointer to the @p condition_variable_t structure
280  * @param[in] timeout the number of ticks before the operation timeouts, the
281  * special values are handled as follow:
282  * - @a TIME_INFINITE no timeout.
283  * - @a TIME_IMMEDIATE this value is not allowed.
284  * .
285  * @return A message specifying how the invoking thread has been
286  * released from the condition variable.
287  * @retval MSG_OK if the condition variable has been signaled using
288  * @p chCondSignal().
289  * @retval MSG_RESET if the condition variable has been signaled using
290  * @p chCondBroadcast().
291  * @retval MSG_TIMEOUT if the condition variable has not been signaled within
292  * the specified timeout.
293  *
294  * @sclass
295  */
297  mutex_t *mp;
298  msg_t msg;
299 
301  chDbgCheck((cp != NULL) && (timeout != TIME_IMMEDIATE));
302  chDbgAssert(currp->mtxlist != NULL, "not owning a mutex");
303 
304  /* Getting "current" mutex and releasing it.*/
305  mp = chMtxGetNextMutexS();
306  chMtxUnlockS(mp);
307 
308  /* Start waiting on the condition variable, on exit the mutex is taken
309  again.*/
310  currp->u.wtobjp = cp;
312  msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, timeout);
313  if (msg != MSG_TIMEOUT) {
314  chMtxLockS(mp);
315  }
316 
317  return msg;
318 }
319 #endif /* CH_CFG_USE_CONDVARS_TIMEOUT == TRUE */
320 
321 #endif /* CH_CFG_USE_CONDVARS == TRUE */
322 
323 /** @} */
void chCondObjectInit(condition_variable_t *cp)
Initializes s condition_variable_t structure.
Definition: chcond.c:75
void chDbgCheckClassS(void)
S-class functions context check.
Definition: chdebug.c:250
void chMtxUnlockS(mutex_t *mp)
Unlocks the specified mutex.
Definition: chmtx.c:410
void chCondBroadcast(condition_variable_t *cp)
Signals all threads that are waiting on the condition variable.
Definition: chcond.c:130
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:150
void chCondSignal(condition_variable_t *cp)
Signals one thread that is waiting on the condition variable.
Definition: chcond.c:89
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:353
void chCondSignalI(condition_variable_t *cp)
Signals one thread that is waiting on the condition variable.
Definition: chcond.c:111
struct ch_mutex * mtxlist
List of the mutexes owned by this thread.
Definition: chschd.h:294
thread_t * chSchReadyI(thread_t *tp)
Inserts a thread in the Ready List placing it behind its peers.
Definition: chschd.c:218
void queue_prio_insert(thread_t *tp, threads_queue_t *tqp)
Inserts a thread into a priority ordered queue.
Definition: chschd.c:86
#define currp
Current thread pointer access macro.
Definition: chschd.h:459
msg_t rdymsg
Thread wakeup code.
Definition: chschd.h:216
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:365
#define CH_STATE_WTCOND
On a cond.variable.
Definition: chschd.h:74
msg_t chCondWaitTimeout(condition_variable_t *cp, sysinterval_t timeout)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:258
msg_t chCondWait(condition_variable_t *cp)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:179
Mutex structure.
Definition: chmtx.h:57
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:235
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition: chschd.h:40
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:456
condition_variable_t structure.
Definition: chcond.h:59
static mutex_t * chMtxGetNextMutexS(void)
Returns the next mutex in the mutexes stack of the current thread.
Definition: chmtx.h:144
void chSchGoSleepS(tstate_t newstate)
Puts the current thread to sleep into the specified state.
Definition: chschd.c:289
static void queue_init(threads_queue_t *tqp)
Threads queue initialization.
Definition: chschd.h:548
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:101
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:375
#define MSG_OK
Normal wakeup message.
Definition: chschd.h:39
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:127
msg_t chCondWaitTimeoutS(condition_variable_t *cp, sysinterval_t timeout)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:296
void * wtobjp
Pointer to a generic "wait" object.
Definition: chschd.h:230
union ch_thread::@0 u
State-specific fields.
#define TIME_IMMEDIATE
Zero interval specification for some functions with a timeout specification.
Definition: chtime.h:45
static bool queue_notempty(const threads_queue_t *tqp)
Evaluates to true if the specified threads queue is not empty.
Definition: chschd.h:575
void chSchWakeupS(thread_t *ntp, msg_t msg)
Wakes up a thread.
Definition: chschd.c:412
threads_queue_t queue
Condition variable threads queue.
Definition: chcond.h:60
void chCondBroadcastI(condition_variable_t *cp)
Signals all threads that are waiting on the condition variable.
Definition: chcond.c:149
ChibiOS/RT main include file.
thread_t * queue_fifo_remove(threads_queue_t *tqp)
Removes the first-out thread from a queue and returns it.
Definition: chschd.c:124
#define MSG_RESET
Wakeup caused by a reset condition.
Definition: chschd.h:43
msg_t chCondWaitS(condition_variable_t *cp)
Waits on the condition variable releasing the mutex lock.
Definition: chcond.c:205
void chMtxLockS(mutex_t *mp)
Locks the specified mutex.
Definition: chmtx.c:139
Structure representing a thread.
Definition: chschd.h:153