ChibiOS  21.6.0
chmtx.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 /**
21  * @file rt/src/chmtx.c
22  * @brief Mutexes code.
23  *
24  * @addtogroup mutexes
25  * @details Mutexes related APIs and services.
26  * <h2>Operation mode</h2>
27  * A mutex is a threads synchronization object that can be in two
28  * distinct states:
29  * - Not owned (unlocked).
30  * - Owned by a thread (locked).
31  * .
32  * Operations defined for mutexes:
33  * - <b>Lock</b>: The mutex is checked, if the mutex is not owned by
34  * some other thread then it is associated to the locking thread
35  * else the thread is queued on the mutex in a list ordered by
36  * priority.
37  * - <b>Unlock</b>: The mutex is released by the owner and the highest
38  * priority thread waiting in the queue, if any, is resumed and made
39  * owner of the mutex.
40  * .
41  * <h2>Constraints</h2>
42  * In ChibiOS/RT the Unlock operations must always be performed
43  * in lock-reverse order. This restriction both improves the
44  * performance and is required for an efficient implementation
45  * of the priority inheritance mechanism.<br>
46  * Operating under this restriction also ensures that deadlocks
47  * are no possible.
48  *
49  * <h2>Recursive mode</h2>
50  * By default mutexes are not recursive, this mean that it is not
51  * possible to take a mutex already owned by the same thread.
52  * It is possible to enable the recursive behavior by enabling the
53  * option @p CH_CFG_USE_MUTEXES_RECURSIVE.
54  *
55  * <h2>The priority inversion problem</h2>
56  * The mutexes in ChibiOS/RT implements the <b>full</b> priority
57  * inheritance mechanism in order handle the priority inversion
58  * problem.<br>
59  * When a thread is queued on a mutex, any thread, directly or
60  * indirectly, holding the mutex gains the same priority of the
61  * waiting thread (if their priority was not already equal or higher).
62  * The mechanism works with any number of nested mutexes and any
63  * number of involved threads. The algorithm complexity (worst case)
64  * is N with N equal to the number of nested mutexes.
65  * @pre In order to use the mutex APIs the @p CH_CFG_USE_MUTEXES option
66  * must be enabled in @p chconf.h.
67  * @post Enabling mutexes requires 5-12 (depending on the architecture)
68  * extra bytes in the @p thread_t structure.
69  * @{
70  */
71 
72 #include "ch.h"
73 
74 #if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
75 
76 /*===========================================================================*/
77 /* Module exported variables. */
78 /*===========================================================================*/
79 
80 /*===========================================================================*/
81 /* Module local types. */
82 /*===========================================================================*/
83 
84 /*===========================================================================*/
85 /* Module local variables. */
86 /*===========================================================================*/
87 
88 /*===========================================================================*/
89 /* Module local functions. */
90 /*===========================================================================*/
91 
92 /*===========================================================================*/
93 /* Module exported functions. */
94 /*===========================================================================*/
95 
96 /**
97  * @brief Initializes s @p mutex_t structure.
98  *
99  * @param[out] mp pointer to a @p mutex_t structure
100  *
101  * @init
102  */
104 
105  chDbgCheck(mp != NULL);
106 
107  ch_queue_init(&mp->queue);
108  mp->owner = NULL;
109 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
110  mp->cnt = (cnt_t)0;
111 #endif
112 }
113 
114 /**
115  * @brief Locks the specified mutex.
116  * @post The mutex is locked and inserted in the per-thread stack of owned
117  * mutexes.
118  *
119  * @param[in] mp pointer to the @p mutex_t structure
120  *
121  * @api
122  */
123 void chMtxLock(mutex_t *mp) {
124 
125  chSysLock();
126  chMtxLockS(mp);
127  chSysUnlock();
128 }
129 
130 /**
131  * @brief Locks the specified mutex.
132  * @post The mutex is locked and inserted in the per-thread stack of owned
133  * mutexes.
134  *
135  * @param[in] mp pointer to the @p mutex_t structure
136  *
137  * @sclass
138  */
139 void chMtxLockS(mutex_t *mp) {
140  thread_t *currtp = chThdGetSelfX();
141 
142  chDbgCheckClassS();
143  chDbgCheck(mp != NULL);
144 
145  /* Is the mutex already locked? */
146  if (mp->owner != NULL) {
147 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
148 
149  chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
150 
151  /* If the mutex is already owned by this thread, the counter is increased
152  and there is no need of more actions.*/
153  if (mp->owner == currtp) {
154  mp->cnt++;
155  }
156  else {
157 #endif
158  /* Priority inheritance protocol; explores the thread-mutex dependencies
159  boosting the priority of all the affected threads to equal the
160  priority of the running thread requesting the mutex.*/
161  thread_t *tp = mp->owner;
162 
163  /* Does the running thread have higher priority than the mutex
164  owning thread? */
165  while (tp->hdr.pqueue.prio < currtp->hdr.pqueue.prio) {
166  /* Make priority of thread tp match the running thread's priority.*/
167  tp->hdr.pqueue.prio = currtp->hdr.pqueue.prio;
168 
169  /* The following states need priority queues reordering.*/
170  switch (tp->state) {
171  case CH_STATE_WTMTX:
172  /* Re-enqueues the mutex owner with its new priority.*/
174  ch_queue_dequeue(&tp->hdr.queue));
175  tp = tp->u.wtmtxp->owner;
176  /*lint -e{9042} [16.1] Continues the while.*/
177  continue;
178 #if (CH_CFG_USE_CONDVARS == TRUE) || \
179  ((CH_CFG_USE_SEMAPHORES == TRUE) && \
180  (CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE)) || \
181  ((CH_CFG_USE_MESSAGES == TRUE) && \
182  (CH_CFG_USE_MESSAGES_PRIORITY == TRUE))
183 #if CH_CFG_USE_CONDVARS == TRUE
184  case CH_STATE_WTCOND:
185 #endif
186 #if (CH_CFG_USE_SEMAPHORES == TRUE) && \
187  (CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE)
188  case CH_STATE_WTSEM:
189 #endif
190 #if (CH_CFG_USE_MESSAGES == TRUE) && (CH_CFG_USE_MESSAGES_PRIORITY == TRUE)
191  case CH_STATE_SNDMSGQ:
192 #endif
193  /* Re-enqueues tp with its new priority on the queue.*/
195  ch_queue_dequeue(&tp->hdr.queue));
196  break;
197 #endif
198  case CH_STATE_READY:
199 #if CH_DBG_ENABLE_ASSERTS == TRUE
200  /* Prevents an assertion in chSchReadyI().*/
201  tp->state = CH_STATE_CURRENT;
202 #endif
203  /* Re-enqueues tp with its new priority on the ready list.*/
204  (void) chSchReadyI((thread_t *)ch_queue_dequeue(&tp->hdr.queue));
205  break;
206  default:
207  /* Nothing to do for other states.*/
208  break;
209  }
210  break;
211  }
212 
213  /* Sleep on the mutex.*/
214  ch_sch_prio_insert(&mp->queue, &currtp->hdr.queue);
215  currtp->u.wtmtxp = mp;
217 
218  /* It is assumed that the thread performing the unlock operation assigns
219  the mutex to this thread.*/
220  chDbgAssert(mp->owner == currtp, "not owner");
221  chDbgAssert(currtp->mtxlist == mp, "not owned");
222 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
223  chDbgAssert(mp->cnt == (cnt_t)1, "counter is not one");
224  }
225 #endif
226  }
227  else {
228 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
229  chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero");
230 
231  mp->cnt++;
232 #endif
233  /* It was not owned, inserted in the owned mutexes list.*/
234  mp->owner = currtp;
235  mp->next = currtp->mtxlist;
236  currtp->mtxlist = mp;
237  }
238 }
239 
240 /**
241  * @brief Tries to lock a mutex.
242  * @details This function attempts to lock a mutex, if the mutex is already
243  * locked by another thread then the function exits without waiting.
244  * @post The mutex is locked and inserted in the per-thread stack of owned
245  * mutexes.
246  * @note This function does not have any overhead related to the
247  * priority inheritance mechanism because it does not try to
248  * enter a sleep state.
249  *
250  * @param[in] mp pointer to the @p mutex_t structure
251  * @return The operation status.
252  * @retval true if the mutex has been successfully acquired
253  * @retval false if the lock attempt failed.
254  *
255  * @api
256  */
258  bool b;
259 
260  chSysLock();
261  b = chMtxTryLockS(mp);
262  chSysUnlock();
263 
264  return b;
265 }
266 
267 /**
268  * @brief Tries to lock a mutex.
269  * @details This function attempts to lock a mutex, if the mutex is already
270  * taken by another thread then the function exits without waiting.
271  * @post The mutex is locked and inserted in the per-thread stack of owned
272  * mutexes.
273  * @note This function does not have any overhead related to the
274  * priority inheritance mechanism because it does not try to
275  * enter a sleep state.
276  *
277  * @param[in] mp pointer to the @p mutex_t structure
278  * @return The operation status.
279  * @retval true if the mutex has been successfully acquired
280  * @retval false if the lock attempt failed.
281  *
282  * @sclass
283  */
285  thread_t *currtp = chThdGetSelfX();
286 
287  chDbgCheckClassS();
288  chDbgCheck(mp != NULL);
289 
290  if (mp->owner != NULL) {
291 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
292 
293  chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
294 
295  if (mp->owner == currtp) {
296  mp->cnt++;
297  return true;
298  }
299 #endif
300  return false;
301  }
302 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
303 
304  chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero");
305 
306  mp->cnt++;
307 #endif
308  mp->owner = currtp;
309  mp->next = currtp->mtxlist;
310  currtp->mtxlist = mp;
311  return true;
312 }
313 
314 /**
315  * @brief Unlocks the specified mutex.
316  * @note Mutexes must be unlocked in reverse lock order. Violating this
317  * rules will result in a panic if assertions are enabled.
318  * @pre The invoking thread <b>must</b> have at least one owned mutex.
319  * @post The mutex is unlocked and removed from the per-thread stack of
320  * owned mutexes.
321  *
322  * @param[in] mp pointer to the @p mutex_t structure
323  *
324  * @api
325  */
326 void chMtxUnlock(mutex_t *mp) {
327  thread_t *currtp = chThdGetSelfX();
328  mutex_t *lmp;
329 
330  chDbgCheck(mp != NULL);
331 
332  chSysLock();
333 
334  chDbgAssert(currtp->mtxlist != NULL, "owned mutexes list empty");
335  chDbgAssert(currtp->mtxlist->owner == currtp, "ownership failure");
336 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
337  chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
338 
339  if (--mp->cnt == (cnt_t)0) {
340 #endif
341 
342  chDbgAssert(currtp->mtxlist == mp, "not next in list");
343 
344  /* Removes the top mutex from the thread's owned mutexes list and marks
345  it as not owned. Note, it is assumed to be the same mutex passed as
346  parameter of this function.*/
347  currtp->mtxlist = mp->next;
348 
349  /* If a thread is waiting on the mutex then the fun part begins.*/
350  if (chMtxQueueNotEmptyS(mp)) {
351  thread_t *tp;
352 
353  /* Recalculates the optimal thread priority by scanning the owned
354  mutexes list.*/
355  tprio_t newprio = currtp->realprio;
356  lmp = currtp->mtxlist;
357  while (lmp != NULL) {
358  /* If the highest priority thread waiting in the mutexes list has a
359  greater priority than the current thread base priority then the
360  final priority will have at least that priority.*/
361  if (chMtxQueueNotEmptyS(lmp) &&
362  (((thread_t *)lmp->queue.next)->hdr.pqueue.prio > newprio)) {
363  newprio = ((thread_t *)lmp->queue.next)->hdr.pqueue.prio;
364  }
365  lmp = lmp->next;
366  }
367 
368  /* Assigns to the current thread the highest priority among all the
369  waiting threads.*/
370  currtp->hdr.pqueue.prio = newprio;
371 
372  /* Awakens the highest priority thread waiting for the unlocked mutex and
373  assigns the mutex to it.*/
374 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
375  mp->cnt = (cnt_t)1;
376 #endif
377  tp = (thread_t *)ch_queue_fifo_remove(&mp->queue);
378  mp->owner = tp;
379  mp->next = tp->mtxlist;
380  tp->mtxlist = mp;
381 
382  /* Note, not using chSchWakeupS() because that function expects the
383  current thread to have the higher or equal priority than the ones
384  in the ready list. This is not necessarily true here because we
385  just changed priority.*/
386  (void) chSchReadyI(tp);
388  }
389  else {
390  mp->owner = NULL;
391  }
392 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
393  }
394 #endif
395 
396  chSysUnlock();
397 }
398 
399 /**
400  * @brief Unlocks the specified mutex.
401  * @note Mutexes must be unlocked in reverse lock order. Violating this
402  * rules will result in a panic if assertions are enabled.
403  * @pre The invoking thread <b>must</b> have at least one owned mutex.
404  * @post The mutex is unlocked and removed from the per-thread stack of
405  * owned mutexes.
406  * @post This function does not reschedule so a call to a rescheduling
407  * function must be performed before unlocking the kernel.
408  *
409  * @param[in] mp pointer to the @p mutex_t structure
410  *
411  * @sclass
412  */
414  thread_t *currtp = chThdGetSelfX();
415  mutex_t *lmp;
416 
417  chDbgCheckClassS();
418  chDbgCheck(mp != NULL);
419 
420  chDbgAssert(currtp->mtxlist != NULL, "owned mutexes list empty");
421  chDbgAssert(currtp->mtxlist->owner == currtp, "ownership failure");
422 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
423  chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
424 
425  if (--mp->cnt == (cnt_t)0) {
426 #endif
427 
428  chDbgAssert(currtp->mtxlist == mp, "not next in list");
429 
430  /* Removes the top mutex from the thread's owned mutexes list and marks
431  it as not owned. Note, it is assumed to be the same mutex passed as
432  parameter of this function.*/
433  currtp->mtxlist = mp->next;
434 
435  /* If a thread is waiting on the mutex then the fun part begins.*/
436  if (chMtxQueueNotEmptyS(mp)) {
437  thread_t *tp;
438 
439  /* Recalculates the optimal thread priority by scanning the owned
440  mutexes list.*/
441  tprio_t newprio = currtp->realprio;
442  lmp = currtp->mtxlist;
443  while (lmp != NULL) {
444  /* If the highest priority thread waiting in the mutexes list has a
445  greater priority than the current thread base priority then the
446  final priority will have at least that priority.*/
447  if (chMtxQueueNotEmptyS(lmp) &&
448  (((thread_t *)lmp->queue.next)->hdr.pqueue.prio > newprio)) {
449  newprio = ((thread_t *)lmp->queue.next)->hdr.pqueue.prio;
450  }
451  lmp = lmp->next;
452  }
453 
454  /* Assigns to the current thread the highest priority among all the
455  waiting threads.*/
456  currtp->hdr.pqueue.prio = newprio;
457 
458  /* Awakens the highest priority thread waiting for the unlocked mutex and
459  assigns the mutex to it.*/
460 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
461  mp->cnt = (cnt_t)1;
462 #endif
463  tp = (thread_t *)ch_queue_fifo_remove(&mp->queue);
464  mp->owner = tp;
465  mp->next = tp->mtxlist;
466  tp->mtxlist = mp;
467  (void) chSchReadyI(tp);
468  }
469  else {
470  mp->owner = NULL;
471  }
472 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
473  }
474 #endif
475 }
476 
477 /**
478  * @brief Unlocks all mutexes owned by the invoking thread.
479  * @post The stack of owned mutexes is emptied and all the found
480  * mutexes are unlocked.
481  * @post This function does not reschedule so a call to a rescheduling
482  * function must be performed before unlocking the kernel.
483  * @note This function is <b>MUCH MORE</b> efficient than releasing the
484  * mutexes one by one and not just because the call overhead,
485  * this function does not have any overhead related to the priority
486  * inheritance mechanism.
487  *
488  * @sclass
489  */
490 void chMtxUnlockAllS(void) {
491  thread_t *currtp = chThdGetSelfX();
492 
493  if (currtp->mtxlist != NULL) {
494  do {
495  mutex_t *mp = currtp->mtxlist;
496  currtp->mtxlist = mp->next;
497  if (chMtxQueueNotEmptyS(mp)) {
498  thread_t *tp;
499 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
500  mp->cnt = (cnt_t)1;
501 #endif
502  tp = (thread_t *)ch_queue_fifo_remove(&mp->queue);
503  mp->owner = tp;
504  mp->next = tp->mtxlist;
505  tp->mtxlist = mp;
506  (void) chSchReadyI(tp);
507  }
508  else {
509 #if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
510  mp->cnt = (cnt_t)0;
511 #endif
512  mp->owner = NULL;
513  }
514  } while (currtp->mtxlist != NULL);
515  currtp->hdr.pqueue.prio = currtp->realprio;
517  }
518 }
519 
520 /**
521  * @brief Unlocks all mutexes owned by the invoking thread.
522  * @post The stack of owned mutexes is emptied and all the found
523  * mutexes are unlocked.
524  * @note This function is <b>MUCH MORE</b> efficient than releasing the
525  * mutexes one by one and not just because the call overhead,
526  * this function does not have any overhead related to the priority
527  * inheritance mechanism.
528  *
529  * @api
530  */
531 void chMtxUnlockAll(void) {
532 
533  chSysLock();
534  chMtxUnlockAllS();
535  chSysUnlock();
536 }
537 
538 #endif /* CH_CFG_USE_MUTEXES == TRUE */
539 
540 /** @} */
CH_STATE_READY
#define CH_STATE_READY
Waiting on the ready list.
Definition: chschd.h:62
tprio_t
uint32_t tprio_t
Definition: chearly.h:87
ch_queue::next
ch_queue_t * next
Next in the list/queue.
Definition: chlists.h:70
ch_mutex::cnt
cnt_t cnt
Mutex recursion counter.
Definition: chmtx.h:65
chSchReadyI
thread_t * chSchReadyI(thread_t *tp)
Inserts a thread in the Ready List placing it behind its peers.
Definition: chschd.c:276
ch_thread::realprio
tprio_t realprio
Thread's own, non-inherited, priority.
Definition: chobjects.h:324
ch_thread::pqueue
ch_priority_queue_t pqueue
Threads ordered queues element.
Definition: chobjects.h:172
CH_STATE_WTMTX
#define CH_STATE_WTMTX
On a mutex.
Definition: chschd.h:69
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:144
ch_thread::mtxlist
struct ch_mutex * mtxlist
List of the mutexes owned by this thread.
Definition: chobjects.h:320
CH_STATE_WTCOND
#define CH_STATE_WTCOND
On a cond.variable.
Definition: chschd.h:70
chMtxLock
void chMtxLock(mutex_t *mp)
Locks the specified mutex.
Definition: chmtx.c:123
chMtxUnlockAll
void chMtxUnlockAll(void)
Unlocks all mutexes owned by the invoking thread.
Definition: chmtx.c:531
chDbgCheck
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:118
ch_thread::wtmtxp
struct ch_mutex * wtmtxp
Pointer to a generic mutex object.
Definition: chobjects.h:286
chMtxTryLock
bool chMtxTryLock(mutex_t *mp)
Tries to lock a mutex.
Definition: chmtx.c:257
chMtxTryLockS
bool chMtxTryLockS(mutex_t *mp)
Tries to lock a mutex.
Definition: chmtx.c:284
CH_STATE_SNDMSGQ
#define CH_STATE_SNDMSGQ
Sending a message, in queue.
Definition: chschd.h:75
ch_thread
Structure representing a thread.
Definition: chobjects.h:156
chSchGoSleepS
void chSchGoSleepS(tstate_t newstate)
Puts the current thread to sleep into the specified state.
Definition: chschd.c:301
cnt_t
int32_t cnt_t
Definition: chearly.h:92
CH_STATE_CURRENT
#define CH_STATE_CURRENT
Currently running.
Definition: chschd.h:64
ch_thread::hdr
union ch_thread::@0 hdr
Shared list headers.
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:280
chMtxObjectInit
void chMtxObjectInit(mutex_t *mp)
Initializes s mutex_t structure.
Definition: chmtx.c:103
ch_thread::u
union ch_thread::@1 u
State-specific fields.
ch_mutex::owner
thread_t * owner
Owner thread_t pointer or NULL.
Definition: chmtx.h:60
chSchRescheduleS
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:454
chMtxUnlockAllS
void chMtxUnlockAllS(void)
Unlocks all mutexes owned by the invoking thread.
Definition: chmtx.c:490
ch_queue_init
static void ch_queue_init(ch_queue_t *qp)
Queue initialization.
Definition: chlists.h:222
ch_sch_prio_insert
void ch_sch_prio_insert(ch_queue_t *qp, ch_queue_t *tp)
Inserts a thread into a priority ordered queue.
Definition: chschd.c:246
chMtxUnlock
void chMtxUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition: chmtx.c:326
ch_mutex::next
mutex_t * next
Next mutex_t into an owner-list or NULL.
Definition: chmtx.h:62
ch_mutex
Mutex structure.
Definition: chmtx.h:57
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: chobjects.h:168
ch_thread::state
tstate_t state
Current thread state.
Definition: chobjects.h:206
chMtxLockS
void chMtxLockS(mutex_t *mp)
Locks the specified mutex.
Definition: chmtx.c:139
ch_queue_dequeue
static ch_queue_t * ch_queue_dequeue(ch_queue_t *p)
Removes an element from a queue and returns it.
Definition: chlists.h:318
ch_mutex::queue
ch_queue_t queue
Queue of the threads sleeping on this mutex.
Definition: chmtx.h:58
ch_priority_queue::prio
tprio_t prio
Priority of this element.
Definition: chlists.h:88
chSysUnlock
#define chSysUnlock()
Leaves the kernel lock state.
Definition: nil/include/ch.h:1053
CH_STATE_WTSEM
#define CH_STATE_WTSEM
On a semaphore.
Definition: chschd.h:68
chMtxQueueNotEmptyS
static bool chMtxQueueNotEmptyS(mutex_t *mp)
Returns true if the mutex queue contains at least a waiting thread.
Definition: chmtx.h:128
chThdGetSelfX
#define chThdGetSelfX()
Returns a pointer to the current thread_t.
Definition: nil/include/ch.h:1132
chSysLock
#define chSysLock()
Enters the kernel lock state.
Definition: nil/include/ch.h:1043