ChibiOS  21.6.0
chthreads.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/chthreads.c
22  * @brief Threads code.
23  *
24  * @addtogroup threads
25  * @details Threads related APIs and services.
26  * <h2>Operation mode</h2>
27  * A thread is an abstraction of an independent instructions flow.
28  * In ChibiOS/RT a thread is represented by a "C" function owning
29  * a processor context, state informations and a dedicated stack
30  * area. In this scenario static variables are shared among all
31  * threads while automatic variables are local to the thread.<br>
32  * Operations defined for threads:
33  * - <b>Create</b>, a thread is started on the specified thread
34  * function. This operation is available in multiple variants,
35  * both static and dynamic.
36  * - <b>Exit</b>, a thread terminates by returning from its top
37  * level function or invoking a specific API, the thread can
38  * return a value that can be retrieved by other threads.
39  * - <b>Wait</b>, a thread waits for the termination of another
40  * thread and retrieves its return value.
41  * - <b>Resume</b>, a thread created in suspended state is started.
42  * - <b>Sleep</b>, the execution of a thread is suspended for the
43  * specified amount of time or the specified future absolute time
44  * is reached.
45  * - <b>SetPriority</b>, a thread changes its own priority level.
46  * - <b>Yield</b>, a thread voluntarily renounces to its time slot.
47  * .
48  * @{
49  */
50 
51 #include "ch.h"
52 
53 /*===========================================================================*/
54 /* Module local definitions. */
55 /*===========================================================================*/
56 
57 /*===========================================================================*/
58 /* Module exported variables. */
59 /*===========================================================================*/
60 
61 /*===========================================================================*/
62 /* Module local types. */
63 /*===========================================================================*/
64 
65 /*===========================================================================*/
66 /* Module local variables. */
67 /*===========================================================================*/
68 
69 /*===========================================================================*/
70 /* Module local functions. */
71 /*===========================================================================*/
72 
73 /*===========================================================================*/
74 /* Module exported functions. */
75 /*===========================================================================*/
76 
77 /**
78  * @brief Initializes a thread structure.
79  * @note This is an internal functions, do not use it in application code.
80  *
81  * @param[in] oip pointer to the OS instance
82  * @param[in] tp pointer to the thread
83  * @param[in] name thread name
84  * @param[in] prio the priority level for the new thread
85  * @return The same thread pointer passed as parameter.
86  *
87  * @notapi
88  */
90  thread_t *tp,
91  const char *name,
92  tprio_t prio) {
93 
94  tp->hdr.pqueue.prio = prio;
95  tp->state = CH_STATE_WTSTART;
97  tp->owner = oip;
98 #if CH_CFG_TIME_QUANTUM > 0
100 #endif
101 #if CH_CFG_USE_MUTEXES == TRUE
102  tp->realprio = prio;
103  tp->mtxlist = NULL;
104 #endif
105 #if CH_CFG_USE_EVENTS == TRUE
106  tp->epending = (eventmask_t)0;
107 #endif
108 #if CH_DBG_THREADS_PROFILING == TRUE
109  tp->time = (systime_t)0;
110 #endif
111 #if CH_CFG_USE_REGISTRY == TRUE
112  tp->refs = (trefs_t)1;
113  tp->name = name;
114  REG_INSERT(oip, tp);
115 #else
116  (void)name;
117 #endif
118 #if CH_CFG_USE_WAITEXIT == TRUE
119  ch_list_init(&tp->waiting);
120 #endif
121 #if CH_CFG_USE_MESSAGES == TRUE
122  ch_queue_init(&tp->msgqueue);
123 #endif
124 #if CH_DBG_STATISTICS == TRUE
125  chTMObjectInit(&tp->stats);
126 #endif
128  return tp;
129 }
130 
131 #if (CH_DBG_FILL_THREADS == TRUE) || defined(__DOXYGEN__)
132 /**
133  * @brief Memory fill utility.
134  *
135  * @param[in] startp first address to fill
136  * @param[in] endp last address to fill +1
137  * @param[in] v filler value
138  *
139  * @notapi
140  */
141 void __thd_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
142 
143  while (startp < endp) {
144  *startp++ = v;
145  }
146 }
147 #endif /* CH_DBG_FILL_THREADS */
148 
149 /**
150  * @brief Creates a new thread into a static memory area.
151  * @details The new thread is initialized but not inserted in the ready list,
152  * the initial state is @p CH_STATE_WTSTART.
153  * @post The created thread has a reference counter set to one, it is
154  * caller responsibility to call @p chThdRelease() or @p chthdWait()
155  * in order to release the reference. The thread persists in the
156  * registry until its reference counter reaches zero.
157  * @post The initialized thread can be subsequently started by invoking
158  * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
159  * depending on the execution context.
160  * @note A thread can terminate by calling @p chThdExit() or by simply
161  * returning from its main function.
162  * @note Threads created using this function do not obey to the
163  * @p CH_DBG_FILL_THREADS debug option because it would keep
164  * the kernel locked for too much time.
165  *
166  * @param[out] tdp pointer to the thread descriptor
167  * @return The pointer to the @p thread_t structure allocated for
168  * the thread into the working space area.
169  *
170  * @iclass
171  */
173  thread_t *tp;
174 
175  chDbgCheckClassI();
176  chDbgCheck(tdp != NULL);
179  (tdp->wend > tdp->wbase) &&
180  (((size_t)tdp->wend - (size_t)tdp->wbase) >= THD_WORKING_AREA_SIZE(0)));
181  chDbgCheck((tdp->prio <= HIGHPRIO) && (tdp->funcp != NULL));
182 
183  /* The thread structure is laid out in the upper part of the thread
184  workspace. The thread position structure is aligned to the required
185  stack alignment because it represents the stack top.*/
186  tp = (thread_t *)((uint8_t *)tdp->wend -
188 
189 #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
190  /* Stack boundary.*/
191  tp->wabase = tdp->wbase;
192 #endif
193 
194  /* Setting up the port-dependent part of the working area.*/
195  PORT_SETUP_CONTEXT(tp, tdp->wbase, tp, tdp->funcp, tdp->arg);
196 
197  /* The thread object is initialized but not started.*/
198 #if CH_CFG_SMP_MODE != FALSE
199  if (tdp->instance != NULL) {
200  return __thd_object_init(tdp->instance, tp, tdp->name, tdp->prio);
201  }
202 #endif
203 
204  return __thd_object_init(currcore, tp, tdp->name, tdp->prio);
205 }
206 
207 /**
208  * @brief Creates a new thread into a static memory area.
209  * @details The new thread is initialized but not inserted in the ready list,
210  * the initial state is @p CH_STATE_WTSTART.
211  * @post The created thread has a reference counter set to one, it is
212  * caller responsibility to call @p chThdRelease() or @p chthdWait()
213  * in order to release the reference. The thread persists in the
214  * registry until its reference counter reaches zero.
215  * @post The initialized thread can be subsequently started by invoking
216  * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
217  * depending on the execution context.
218  * @note A thread can terminate by calling @p chThdExit() or by simply
219  * returning from its main function.
220  *
221  * @param[out] tdp pointer to the thread descriptor
222  * @return The pointer to the @p thread_t structure allocated for
223  * the thread into the working space area.
224  *
225  * @api
226  */
228  thread_t *tp;
229 
230 #if CH_CFG_USE_REGISTRY == TRUE
232  "working area in use");
233 #endif
234 
235 #if CH_DBG_FILL_THREADS == TRUE
236  __thd_memfill((uint8_t *)tdp->wbase,
237  (uint8_t *)tdp->wend,
239 #endif
240 
241  chSysLock();
242  tp = chThdCreateSuspendedI(tdp);
243  chSysUnlock();
244 
245  return tp;
246 }
247 
248 /**
249  * @brief Creates a new thread into a static memory area.
250  * @details The new thread is initialized and make ready to execute.
251  * @post The created thread has a reference counter set to one, it is
252  * caller responsibility to call @p chThdRelease() or @p chthdWait()
253  * in order to release the reference. The thread persists in the
254  * registry until its reference counter reaches zero.
255  * @post The initialized thread can be subsequently started by invoking
256  * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
257  * depending on the execution context.
258  * @note A thread can terminate by calling @p chThdExit() or by simply
259  * returning from its main function.
260  * @note Threads created using this function do not obey to the
261  * @p CH_DBG_FILL_THREADS debug option because it would keep
262  * the kernel locked for too much time.
263  *
264  * @param[out] tdp pointer to the thread descriptor
265  * @return The pointer to the @p thread_t structure allocated for
266  * the thread into the working space area.
267  *
268  * @iclass
269  */
271 
272  return chSchReadyI(chThdCreateSuspendedI(tdp));
273 }
274 
275 /**
276  * @brief Creates a new thread into a static memory area.
277  * @details The new thread is initialized and make ready to execute.
278  * @post The created thread has a reference counter set to one, it is
279  * caller responsibility to call @p chThdRelease() or @p chthdWait()
280  * in order to release the reference. The thread persists in the
281  * registry until its reference counter reaches zero.
282  * @note A thread can terminate by calling @p chThdExit() or by simply
283  * returning from its main function.
284  *
285  * @param[out] tdp pointer to the thread descriptor
286  * @return The pointer to the @p thread_t structure allocated for
287  * the thread into the working space area.
288  *
289  * @iclass
290  */
292  thread_t *tp;
293 
294 #if (CH_CFG_USE_REGISTRY == TRUE) && \
295  ((CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE))
297  "working area in use");
298 #endif
299 
300 #if CH_DBG_FILL_THREADS == TRUE
301  __thd_memfill((uint8_t *)tdp->wbase,
302  (uint8_t *)tdp->wend,
304 #endif
305 
306  chSysLock();
307  tp = chThdCreateSuspendedI(tdp);
308  chSchWakeupS(tp, MSG_OK);
309  chSysUnlock();
310 
311  return tp;
312 }
313 
314 /**
315  * @brief Creates a new thread into a static memory area.
316  * @post The created thread has a reference counter set to one, it is
317  * caller responsibility to call @p chThdRelease() or @p chthdWait()
318  * in order to release the reference. The thread persists in the
319  * registry until its reference counter reaches zero.
320  * @note A thread can terminate by calling @p chThdExit() or by simply
321  * returning from its main function.
322  *
323  * @param[out] wsp pointer to a working area dedicated to the thread stack
324  * @param[in] size size of the working area
325  * @param[in] prio the priority level for the new thread
326  * @param[in] pf the thread function
327  * @param[in] arg an argument passed to the thread function. It can be
328  * @p NULL.
329  * @return The pointer to the @p thread_t structure allocated for
330  * the thread into the working space area.
331  *
332  * @api
333  */
334 thread_t *chThdCreateStatic(void *wsp, size_t size,
335  tprio_t prio, tfunc_t pf, void *arg) {
336  thread_t *tp;
337 
338  chDbgCheck((wsp != NULL) &&
340  (size >= THD_WORKING_AREA_SIZE(0)) &&
342  (prio <= HIGHPRIO) && (pf != NULL));
343 
344 #if (CH_CFG_USE_REGISTRY == TRUE) && \
345  ((CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE))
347  "working area in use");
348 #endif
349 
350 #if CH_DBG_FILL_THREADS == TRUE
351  __thd_memfill((uint8_t *)wsp,
352  (uint8_t *)wsp + size,
354 #endif
355 
356  chSysLock();
357 
358  /* The thread structure is laid out in the upper part of the thread
359  workspace. The thread position structure is aligned to the required
360  stack alignment because it represents the stack top.*/
361  tp = (thread_t *)((uint8_t *)wsp + size -
363 
364 #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
365  /* Stack boundary.*/
366  tp->wabase = (stkalign_t *)wsp;
367 #endif
368 
369  /* Setting up the port-dependent part of the working area.*/
370  PORT_SETUP_CONTEXT(tp, wsp, tp, pf, arg);
371 
372  tp = __thd_object_init(currcore, tp, "noname", prio);
373 
374  /* Starting the thread immediately.*/
375  chSchWakeupS(tp, MSG_OK);
376  chSysUnlock();
377 
378  return tp;
379 }
380 
381 /**
382  * @brief Resumes a thread created with @p chThdCreateI().
383  *
384  * @param[in] tp pointer to the thread
385  * @return The pointer to the @p thread_t structure allocated for
386  * the thread into the working space area.
387  *
388  * @api
389  */
391 
392  chSysLock();
393  chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state");
394  chSchWakeupS(tp, MSG_OK);
395  chSysUnlock();
396 
397  return tp;
398 }
399 
400 #if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
401 /**
402  * @brief Adds a reference to a thread object.
403  * @pre The configuration option @p CH_CFG_USE_REGISTRY must be enabled in
404  * order to use this function.
405  *
406  * @param[in] tp pointer to the thread
407  * @return The same thread pointer passed as parameter
408  * representing the new reference.
409  *
410  * @api
411  */
413 
414  chSysLock();
415  chDbgAssert(tp->refs < (trefs_t)255, "too many references");
416  tp->refs++;
417  chSysUnlock();
418 
419  return tp;
420 }
421 
422 /**
423  * @brief Releases a reference to a thread object.
424  * @details If the references counter reaches zero <b>and</b> the thread
425  * is in the @p CH_STATE_FINAL state then the thread's memory is
426  * returned to the proper allocator and the thread is removed
427  * from the registry.<br>
428  * Threads whose counter reaches zero and are still active become
429  * "detached" and will be removed from registry on termination.
430  * @pre The configuration option @p CH_CFG_USE_REGISTRY must be enabled in
431  * order to use this function.
432  * @note Static threads are not affected.
433  *
434  * @param[in] tp pointer to the thread
435  *
436  * @api
437  */
439 
440  chSysLock();
441  chDbgAssert(tp->refs > (trefs_t)0, "not referenced");
442  tp->refs--;
443 
444  /* If the references counter reaches zero and the thread is in its
445  terminated state then the memory can be returned to the proper
446  allocator.*/
447  if ((tp->refs == (trefs_t)0) && (tp->state == CH_STATE_FINAL)) {
448  REG_REMOVE(tp);
449  chSysUnlock();
450 
451 #if CH_CFG_USE_DYNAMIC == TRUE
452  switch (tp->flags & CH_FLAG_MODE_MASK) {
453 #if CH_CFG_USE_HEAP == TRUE
454  case CH_FLAG_MODE_HEAP:
456  break;
457 #endif
458 #if CH_CFG_USE_MEMPOOLS == TRUE
459  case CH_FLAG_MODE_MPOOL:
461  break;
462 #endif
463  default:
464  /* Nothing else to do for static threads.*/
465  break;
466  }
467 #endif /* CH_CFG_USE_DYNAMIC == TRUE */
468  return;
469  }
470  chSysUnlock();
471 }
472 #endif /* CH_CFG_USE_REGISTRY == TRUE */
473 
474 /**
475  * @brief Terminates the current thread.
476  * @details The thread goes in the @p CH_STATE_FINAL state holding the
477  * specified exit status code, other threads can retrieve the
478  * exit status code by invoking the function @p chThdWait().
479  * @post Eventual code after this function will never be executed,
480  * this function never returns. The compiler has no way to
481  * know this so do not assume that the compiler would remove
482  * the dead code.
483  *
484  * @param[in] msg thread exit code
485  *
486  * @api
487  */
488 void chThdExit(msg_t msg) {
489 
490  chSysLock();
491  chThdExitS(msg);
492  /* The thread never returns here.*/
493 }
494 
495 /**
496  * @brief Terminates the current thread.
497  * @details The thread goes in the @p CH_STATE_FINAL state holding the
498  * specified exit status code, other threads can retrieve the
499  * exit status code by invoking the function @p chThdWait().
500  * @post Exiting a non-static thread that does not have references
501  * (detached) causes the thread to remain in the registry.
502  * It can only be removed by performing a registry scan operation.
503  * @post Eventual code after this function will never be executed,
504  * this function never returns. The compiler has no way to
505  * know this so do not assume that the compiler would remove
506  * the dead code.
507  *
508  * @param[in] msg thread exit code
509  *
510  * @sclass
511  */
512 void chThdExitS(msg_t msg) {
513  thread_t *currtp = chThdGetSelfX();
514 
515  /* Storing exit message.*/
516  currtp->u.exitcode = msg;
517 
518  /* Exit handler hook.*/
520 
521 #if CH_CFG_USE_WAITEXIT == TRUE
522  /* Waking up any waiting thread.*/
523  while (unlikely(ch_list_notempty(&currtp->waiting))) {
524  (void) chSchReadyI((thread_t *)ch_list_unlink(&currtp->waiting));
525  }
526 #endif
527 
528 #if CH_CFG_USE_REGISTRY == TRUE
529  if (unlikely(currtp->refs == (trefs_t)0)) {
530 #if CH_CFG_USE_DYNAMIC == TRUE
531  /* Static threads are immediately removed from the registry because there
532  is no memory to recover.*/
533  if (unlikely(((currtp->flags & CH_FLAG_MODE_MASK) == CH_FLAG_MODE_STATIC))) {
534  REG_REMOVE(currtp);
535  }
536 #else
537  REG_REMOVE(currtp);
538 #endif
539  }
540 #endif
541 
542  /* Going into final state.*/
544 
545  /* The thread never returns here.*/
546  chDbgAssert(false, "zombies apocalypse");
547 }
548 
549 #if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__)
550 /**
551  * @brief Blocks the execution of the invoking thread until the specified
552  * thread terminates then the exit code is returned.
553  * @details This function waits for the specified thread to terminate then
554  * decrements its reference counter, if the counter reaches zero then
555  * the thread working area is returned to the proper allocator and
556  * the thread is removed from registry.
557  * @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in
558  * order to use this function.
559  * @post Enabling @p chThdWait() requires 2-4 (depending on the
560  * architecture) extra bytes in the @p thread_t structure.
561  * @note If @p CH_CFG_USE_DYNAMIC is not specified this function just waits
562  * for the thread termination, no memory allocators are involved.
563  *
564  * @param[in] tp pointer to the thread
565  * @return The exit code from the terminated thread.
566  *
567  * @api
568  */
570  thread_t *currtp = chThdGetSelfX();
571  msg_t msg;
572 
573  chDbgCheck(tp != NULL);
574 
575  chSysLock();
576  chDbgAssert(tp != currtp, "waiting self");
577 #if CH_CFG_USE_REGISTRY == TRUE
578  chDbgAssert(tp->refs > (trefs_t)0, "no references");
579 #endif
580 
581  if (likely(tp->state != CH_STATE_FINAL)) {
582  ch_list_link(&tp->waiting, &currtp->hdr.list);
584  }
585  msg = tp->u.exitcode;
586  chSysUnlock();
587 
588 #if CH_CFG_USE_REGISTRY == TRUE
589  /* Releasing a reference to the thread.*/
590  chThdRelease(tp);
591 #endif
592 
593  return msg;
594 }
595 #endif /* CH_CFG_USE_WAITEXIT */
596 
597 /**
598  * @brief Changes the running thread priority level then reschedules if
599  * necessary.
600  * @note The function returns the real thread priority regardless of the
601  * current priority that could be higher than the real priority
602  * because the priority inheritance mechanism.
603  *
604  * @param[in] newprio the new priority level of the running thread
605  * @return The old priority level.
606  *
607  * @api
608  */
610  thread_t *currtp = chThdGetSelfX();
611  tprio_t oldprio;
612 
613  chDbgCheck(newprio <= HIGHPRIO);
614 
615  chSysLock();
616 #if CH_CFG_USE_MUTEXES == TRUE
617  oldprio = currtp->realprio;
618  if ((currtp->hdr.pqueue.prio == currtp->realprio) ||
619  (newprio > currtp->hdr.pqueue.prio)) {
620  currtp->hdr.pqueue.prio = newprio;
621  }
622  currtp->realprio = newprio;
623 #else
624  oldprio = currtp->hdr.pqueue.prio;
625  currtp->hdr.pqueue.prio = newprio;
626 #endif
628  chSysUnlock();
629 
630  return oldprio;
631 }
632 
633 /**
634  * @brief Requests a thread termination.
635  * @pre The target thread must be written to invoke periodically
636  * @p chThdShouldTerminate() and terminate cleanly if it returns
637  * @p true.
638  * @post The specified thread will terminate after detecting the termination
639  * condition.
640  *
641  * @param[in] tp pointer to the thread
642  *
643  * @api
644  */
646 
647  chSysLock();
648  tp->flags |= CH_FLAG_TERMINATE;
649  chSysUnlock();
650 }
651 
652 /**
653  * @brief Suspends the invoking thread for the specified time.
654  *
655  * @param[in] time the delay in system ticks, the special values are
656  * handled as follow:
657  * - @a TIME_INFINITE the thread enters an infinite sleep
658  * state.
659  * - @a TIME_IMMEDIATE this value is not allowed.
660  * .
661  *
662  * @api
663  */
665 
666  chSysLock();
667  chThdSleepS(time);
668  chSysUnlock();
669 }
670 
671 /**
672  * @brief Suspends the invoking thread until the system time arrives to the
673  * specified value.
674  * @note The function has no concept of "past", all specifiable times
675  * are in the future, this means that if you call this function
676  * exceeding your calculated intervals then the function will
677  * return in a far future time, not immediately.
678  * @see chThdSleepUntilWindowed()
679  *
680  * @param[in] time absolute system time
681  *
682  * @api
683  */
685  sysinterval_t interval;
686 
687  chSysLock();
688  interval = chTimeDiffX(chVTGetSystemTimeX(), time);
689  if (likely(interval > (sysinterval_t)0)) {
690  chThdSleepS(interval);
691  }
692  chSysUnlock();
693 }
694 
695 /**
696  * @brief Suspends the invoking thread until the system time arrives to the
697  * specified value.
698  * @note The system time is assumed to be between @p prev and @p next
699  * else the call is assumed to have been called outside the
700  * allowed time interval, in this case no sleep is performed.
701  * @see chThdSleepUntil()
702  *
703  * @param[in] prev absolute system time of the previous deadline
704  * @param[in] next absolute system time of the next deadline
705  * @return the @p next parameter
706  *
707  * @api
708  */
710  systime_t time;
711 
712  chSysLock();
713  time = chVTGetSystemTimeX();
714  if (likely(chTimeIsInRangeX(time, prev, next))) {
715  chThdSleepS(chTimeDiffX(time, next));
716  }
717  chSysUnlock();
718 
719  return next;
720 }
721 
722 /**
723  * @brief Yields the time slot.
724  * @details Yields the CPU control to the next thread in the ready list with
725  * equal priority, if any.
726  *
727  * @api
728  */
729 void chThdYield(void) {
730 
731  chSysLock();
732  chSchDoYieldS();
733  chSysUnlock();
734 }
735 
736 /**
737  * @brief Sends the current thread sleeping and sets a reference variable.
738  * @note This function must reschedule, it can only be called from thread
739  * context.
740  *
741  * @param[in] trp a pointer to a thread reference object
742  * @return The wake up message.
743  *
744  * @sclass
745  */
747  thread_t *tp = chThdGetSelfX();
748 
749  chDbgAssert(*trp == NULL, "not NULL");
750 
751  *trp = tp;
752  tp->u.wttrp = trp;
754 
755  return chThdGetSelfX()->u.rdymsg;
756 }
757 
758 /**
759  * @brief Sends the current thread sleeping and sets a reference variable.
760  * @note This function must reschedule, it can only be called from thread
761  * context.
762  *
763  * @param[in] trp a pointer to a thread reference object
764  * @param[in] timeout the timeout in system ticks, the special values are
765  * handled as follow:
766  * - @a TIME_INFINITE the thread enters an infinite sleep
767  * state.
768  * - @a TIME_IMMEDIATE the thread is not suspended and
769  * the function returns @p MSG_TIMEOUT as if a timeout
770  * occurred.
771  * .
772  * @return The wake up message.
773  * @retval MSG_TIMEOUT if the operation timed out.
774  *
775  * @sclass
776  */
778  thread_t *tp = chThdGetSelfX();
779 
780  chDbgAssert(*trp == NULL, "not NULL");
781 
782  if (unlikely(TIME_IMMEDIATE == timeout)) {
783  return MSG_TIMEOUT;
784  }
785 
786  *trp = tp;
787  tp->u.wttrp = trp;
788 
789  return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout);
790 }
791 
792 /**
793  * @brief Wakes up a thread waiting on a thread reference object.
794  * @note This function must not reschedule because it can be called from
795  * ISR context.
796  *
797  * @param[in] trp a pointer to a thread reference object
798  * @param[in] msg the message code
799  *
800  * @iclass
801  */
803 
804  if (*trp != NULL) {
805  thread_t *tp = *trp;
806 
807  chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
808 
809  *trp = NULL;
810  tp->u.rdymsg = msg;
811  (void) chSchReadyI(tp);
812  }
813 }
814 
815 /**
816  * @brief Wakes up a thread waiting on a thread reference object.
817  * @note This function must reschedule, it can only be called from thread
818  * context.
819  *
820  * @param[in] trp a pointer to a thread reference object
821  * @param[in] msg the message code
822  *
823  * @iclass
824  */
826 
827  if (*trp != NULL) {
828  thread_t *tp = *trp;
829 
830  chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
831 
832  *trp = NULL;
833  chSchWakeupS(tp, msg);
834  }
835 }
836 
837 /**
838  * @brief Wakes up a thread waiting on a thread reference object.
839  * @note This function must reschedule, it can only be called from thread
840  * context.
841  *
842  * @param[in] trp a pointer to a thread reference object
843  * @param[in] msg the message code
844  *
845  * @api
846  */
848 
849  chSysLock();
850  chThdResumeS(trp, msg);
851  chSysUnlock();
852 }
853 
854 /**
855  * @brief Enqueues the caller thread on a threads queue object.
856  * @details The caller thread is enqueued and put to sleep until it is
857  * dequeued or the specified timeouts expires.
858  *
859  * @param[in] tqp pointer to the threads queue object
860  * @param[in] timeout the timeout in system ticks, the special values are
861  * handled as follow:
862  * - @a TIME_INFINITE the thread enters an infinite sleep
863  * state.
864  * - @a TIME_IMMEDIATE the thread is not enqueued and
865  * the function returns @p MSG_TIMEOUT as if a timeout
866  * occurred.
867  * .
868  * @return The message from @p osalQueueWakeupOneI() or
869  * @p osalQueueWakeupAllI() functions.
870  * @retval MSG_TIMEOUT if the thread has not been dequeued within the
871  * specified timeout or if the function has been
872  * invoked with @p TIME_IMMEDIATE as timeout
873  * specification.
874  *
875  * @sclass
876  */
878  thread_t *currtp = chThdGetSelfX();
879 
880  if (unlikely(TIME_IMMEDIATE == timeout)) {
881  return MSG_TIMEOUT;
882  }
883 
884  ch_queue_insert(&tqp->queue, (ch_queue_t *)currtp);
885 
886  return chSchGoSleepTimeoutS(CH_STATE_QUEUED, timeout);
887 }
888 
889 /**
890  * @brief Dequeues and wakes up one thread from the threads queue object,
891  * if any.
892  *
893  * @param[in] tqp pointer to the threads queue object
894  * @param[in] msg the message code
895  *
896  * @iclass
897  */
899 
900  if (ch_queue_notempty(&tqp->queue)) {
901  chThdDoDequeueNextI(tqp, msg);
902  }
903 }
904 
905 /**
906  * @brief Dequeues and wakes up all threads from the threads queue object.
907  *
908  * @param[in] tqp pointer to the threads queue object
909  * @param[in] msg the message code
910  *
911  * @iclass
912  */
914 
915  while (ch_queue_notempty(&tqp->queue)) {
916  chThdDoDequeueNextI(tqp, msg);
917  }
918 }
919 
920 /** @} */
ch_thread::wttrp
thread_reference_t * wttrp
Pointer to a generic thread reference object.
Definition: chobjects.h:263
chThdCreateSuspended
thread_t * chThdCreateSuspended(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:227
chThdSuspendTimeoutS
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition: chthreads.c:777
tprio_t
uint32_t tprio_t
Definition: chearly.h:87
chVTGetSystemTimeX
#define chVTGetSystemTimeX()
Current system time.
Definition: nil/include/ch.h:1254
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::epending
eventmask_t epending
Pending events mask.
Definition: chobjects.h:313
CH_FLAG_MODE_MASK
#define CH_FLAG_MODE_MASK
Thread memory mode mask.
Definition: chschd.h:98
ch_thread::pqueue
ch_priority_queue_t pqueue
Threads ordered queues element.
Definition: chobjects.h:172
THD_WORKING_AREA_SIZE
#define THD_WORKING_AREA_SIZE(n)
Calculates the total Working Area size.
Definition: chthreads.h:130
chTimeDiffX
#define chTimeDiffX(start, end)
Subtracts two system times returning an interval.
Definition: nil/include/ch.h:1307
stkalign_t
port_stkalign_t stkalign_t
Definition: chearly.h:80
chPoolFree
void chPoolFree(memory_pool_t *mp, void *objp)
Releases an object into a memory pool.
Definition: chmempools.c:207
CH_STATE_WTSTART
#define CH_STATE_WTSTART
Just created.
Definition: chschd.h:65
currcore
#define currcore
Access to current core's instance structure.
Definition: chsys.h:90
ch_thread::rdymsg
msg_t rdymsg
Thread wakeup code.
Definition: chobjects.h:242
CH_CFG_TIME_QUANTUM
#define CH_CFG_TIME_QUANTUM
Round robin interval.
Definition: rt/templates/chconf.h:128
chThdAddRef
thread_t * chThdAddRef(thread_t *tp)
Adds a reference to a thread object.
Definition: chthreads.c:412
chThdCreateStatic
thread_t * chThdCreateStatic(void *wsp, size_t size, tprio_t prio, tfunc_t pf, void *arg)
Creates a new thread into a static memory area.
Definition: chthreads.c:334
systime_t
uint64_t systime_t
Type of system time.
Definition: chtime.h:107
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:144
CH_STATE_SUSPENDED
#define CH_STATE_SUSPENDED
Suspended state.
Definition: chschd.h:66
thread_descriptor_t::wend
stkalign_t * wend
Pointer to the working area end.
Definition: chthreads.h:69
ch_os_instance
System instance data structure.
Definition: chobjects.h:394
chThdCreateSuspendedI
thread_t * chThdCreateSuspendedI(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:172
tfunc_t
void(* tfunc_t)(void *p)
Thread function.
Definition: chthreads.h:52
ch_thread::mtxlist
struct ch_mutex * mtxlist
List of the mutexes owned by this thread.
Definition: chobjects.h:320
ch_queue_insert
static void ch_queue_insert(ch_queue_t *qp, ch_queue_t *p)
Inserts an element into a queue.
Definition: chlists.h:262
CH_DBG_STACK_FILL_VALUE
#define CH_DBG_STACK_FILL_VALUE
Fill value for thread stack area in debug mode.
Definition: chdebug.h:47
chHeapFree
void chHeapFree(void *p)
Frees a previously allocated memory block.
Definition: chmemheaps.c:293
chThdResumeS
void chThdResumeS(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:825
eventmask_t
uint32_t eventmask_t
Definition: chearly.h:90
CH_CFG_THREAD_EXIT_HOOK
#define CH_CFG_THREAD_EXIT_HOOK(tp)
Threads finalization hook.
Definition: rt/templates/chconf.h:718
chThdCreateI
thread_t * chThdCreateI(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:270
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:249
chThdGetWorkingAreaX
static stkalign_t * chThdGetWorkingAreaX(thread_t *tp)
Returns the working area base of the specified thread.
Definition: chthreads.h:386
CH_CFG_THREAD_INIT_HOOK
#define CH_CFG_THREAD_INIT_HOOK(tp)
Threads initialization hook.
Definition: rt/templates/chconf.h:708
msg_t
int32_t msg_t
Definition: chearly.h:88
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:355
CH_FLAG_MODE_MPOOL
#define CH_FLAG_MODE_MPOOL
Thread allocated from a Memory Pool.
Definition: chschd.h:103
ch_list_unlink
static ch_list_t * ch_list_unlink(ch_list_t *lp)
Pops an element from the top of a stack list and returns it.
Definition: chlists.h:207
thread_descriptor_t::wbase
stkalign_t * wbase
Pointer to the working area base.
Definition: chthreads.h:65
chThdDequeueAllI
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the threads queue object.
Definition: chthreads.c:913
chThdTerminate
void chThdTerminate(thread_t *tp)
Requests a thread termination.
Definition: chthreads.c:645
chThdEnqueueTimeoutS
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread on a threads queue object.
Definition: chthreads.c:877
likely
#define likely(x)
Marks a boolean expression as likely true.
Definition: chearly.h:178
chDbgCheck
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:118
ch_thread::refs
trefs_t refs
References to this thread.
Definition: chobjects.h:215
TIME_IMMEDIATE
#define TIME_IMMEDIATE
Zero interval specification for some functions with a timeout specification.
Definition: chtime.h:47
chThdDoDequeueNextI
void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object.
Definition: ch.c:1032
chSchDoYieldS
void chSchDoYieldS(void)
Yields the time slot.
Definition: chschd.c:598
ch_thread::name
const char * name
Thread name or NULL.
Definition: chobjects.h:192
MEM_IS_ALIGNED
#define MEM_IS_ALIGNED(p, a)
Returns whatever a pointer or memory size is aligned.
Definition: chalign.h:91
thread_descriptor_t::funcp
tfunc_t funcp
Thread function pointer.
Definition: chthreads.h:77
chThdResumeI
void chThdResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:802
ch_list_notempty
static bool ch_list_notempty(ch_list_t *lp)
Evaluates to true if the specified list is not empty.
Definition: chlists.h:179
HIGHPRIO
#define HIGHPRIO
Highest priority.
Definition: chschd.h:55
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
REG_INSERT
#define REG_INSERT(oip, tp)
Adds a thread to the registry list.
Definition: chregistry.h:101
ch_thread::wabase
stkalign_t * wabase
Working area base address.
Definition: chobjects.h:201
chRegFindThreadByWorkingArea
thread_t * chRegFindThreadByWorkingArea(stkalign_t *wa)
Confirms that a working area is being used by some active thread.
Definition: chregistry.c:255
ch_thread::hdr
union ch_thread::@0 hdr
Shared list headers.
ch_thread::ticks
tslices_t ticks
Number of ticks remaining to this thread.
Definition: chobjects.h:221
chThdWait
msg_t chThdWait(thread_t *tp)
Blocks the execution of the invoking thread until the specified thread terminates then the exit code ...
Definition: chthreads.c:569
CH_FLAG_MODE_HEAP
#define CH_FLAG_MODE_HEAP
Thread allocated from a Memory Heap.
Definition: chschd.h:101
__thd_memfill
void __thd_memfill(uint8_t *startp, uint8_t *endp, uint8_t v)
Memory fill utility.
Definition: chthreads.c:141
tslices_t
uint8_t tslices_t
Definition: chearly.h:86
CH_STATE_FINAL
#define CH_STATE_FINAL
Thread terminated.
Definition: chschd.h:81
ch_thread::msgqueue
ch_queue_t msgqueue
Messages queue.
Definition: chobjects.h:307
ch_thread::u
union ch_thread::@1 u
State-specific fields.
thread_descriptor_t
Type of a thread descriptor.
Definition: chthreads.h:57
ch_queue
Structure representing a generic bidirectional linked list header and element.
Definition: chlists.h:69
chThdSleepS
#define chThdSleepS(timeout)
Suspends the invoking thread for the specified time.
Definition: nil/include/ch.h:1204
chThdSetPriority
tprio_t chThdSetPriority(tprio_t newprio)
Changes the running thread priority level then reschedules if necessary.
Definition: chthreads.c:609
MEM_ALIGN_NEXT
#define MEM_ALIGN_NEXT(p, a)
Aligns to the next aligned memory address.
Definition: chalign.h:80
thread_descriptor_t::arg
void * arg
Thread argument.
Definition: chthreads.h:81
chThdSuspendS
msg_t chThdSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition: chthreads.c:746
thread_descriptor_t::instance
os_instance_t * instance
OS instance affinity or NULL for current one.
Definition: chthreads.h:86
chSchRescheduleS
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:454
threads_queue_t
Type of a thread queue.
Definition: osal.h:238
ch_queue_init
static void ch_queue_init(ch_queue_t *qp)
Queue initialization.
Definition: chlists.h:222
PORT_SETUP_CONTEXT
#define PORT_SETUP_CONTEXT(tp, wbase, wtop, pf, arg)
Platform dependent part of the chThdCreateI() API.
Definition: chcore.h:189
CH_FLAG_TERMINATE
#define CH_FLAG_TERMINATE
Termination requested flag.
Definition: chschd.h:105
MSG_OK
#define MSG_OK
Normal wakeup message.
Definition: chschd.h:39
chTMObjectInit
void chTMObjectInit(time_measurement_t *tmp)
Initializes a TimeMeasurement object.
Definition: chtm.c:79
ch_thread::time
volatile systime_t time
Thread consumed time in ticks.
Definition: chobjects.h:228
chThdYield
void chThdYield(void)
Yields the time slot.
Definition: chthreads.c:729
CH_FLAG_MODE_STATIC
#define CH_FLAG_MODE_STATIC
Static thread.
Definition: chschd.h:100
chThdSleepUntilWindowed
systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: chthreads.c:709
sysinterval_t
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
chThdSleep
void chThdSleep(sysinterval_t time)
Suspends the invoking thread for the specified time.
Definition: chthreads.c:664
trefs_t
uint8_t trefs_t
Definition: chearly.h:85
ch_thread::mpool
void * mpool
Memory Pool where the thread workspace is returned.
Definition: chobjects.h:331
chThdCreate
thread_t * chThdCreate(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:291
chThdDequeueNextI
void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object, if any.
Definition: chthreads.c:898
CH_STATE_QUEUED
#define CH_STATE_QUEUED
On a queue.
Definition: chschd.h:67
thread_descriptor_t::name
const char * name
Thread name.
Definition: chthreads.h:61
ch_thread::state
tstate_t state
Current thread state.
Definition: chobjects.h:206
ch_list_link
static void ch_list_link(ch_list_t *lp, ch_list_t *p)
Pushes an element on top of a stack list.
Definition: chlists.h:192
PORT_WORKING_AREA_ALIGN
#define PORT_WORKING_AREA_ALIGN
Working Areas alignment constant.
Definition: chcore.h:62
__thd_object_init
thread_t * __thd_object_init(os_instance_t *oip, thread_t *tp, const char *name, tprio_t prio)
Initializes a thread structure.
Definition: chthreads.c:89
unlikely
#define unlikely(x)
Marks a boolean expression as likely false.
Definition: chearly.h:191
MSG_TIMEOUT
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition: chschd.h:40
ch_thread::stats
time_measurement_t stats
Thread statistics.
Definition: chobjects.h:337
chThdResume
void chThdResume(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:847
REG_REMOVE
#define REG_REMOVE(tp)
Removes a thread from the registry list.
Definition: chregistry.h:92
ch_thread::exitcode
msg_t exitcode
Thread exit code.
Definition: chobjects.h:249
ch_thread::waiting
ch_list_t waiting
Termination waiting list.
Definition: chobjects.h:301
chThdExitS
void chThdExitS(msg_t msg)
Terminates the current thread.
Definition: chthreads.c:512
ch_thread::owner
os_instance_t * owner
OS instance owner of this thread.
Definition: chobjects.h:187
ch_priority_queue::prio
tprio_t prio
Priority of this element.
Definition: chlists.h:88
chThdStart
thread_t * chThdStart(thread_t *tp)
Resumes a thread created with chThdCreateI().
Definition: chthreads.c:390
chTimeIsInRangeX
bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end)
Checks if the specified time is within the specified time range.
Definition: ch.c:743
chThdRelease
void chThdRelease(thread_t *tp)
Releases a reference to a thread object.
Definition: chthreads.c:438
ch_thread::list
ch_list_t list
Threads lists element.
Definition: chobjects.h:164
thread_descriptor_t::prio
tprio_t prio
Thread priority.
Definition: chthreads.h:73
chThdSleepUntil
void chThdSleepUntil(systime_t time)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: chthreads.c:684
chSysUnlock
#define chSysUnlock()
Leaves the kernel lock state.
Definition: nil/include/ch.h:1053
ch_thread::flags
tmode_t flags
Various thread flags.
Definition: chobjects.h:210
chSchWakeupS
void chSchWakeupS(thread_t *ntp, msg_t msg)
Wakes up a thread.
Definition: chschd.c:393
CH_STATE_WTEXIT
#define CH_STATE_WTEXIT
Waiting a thread.
Definition: chschd.h:72
chThdExit
void chThdExit(msg_t msg)
Terminates the current thread.
Definition: chthreads.c:488
chThdGetSelfX
#define chThdGetSelfX()
Returns a pointer to the current thread_t.
Definition: nil/include/ch.h:1132
PORT_STACK_ALIGN
#define PORT_STACK_ALIGN
Stack alignment constant.
Definition: chcore.h:56
ch_list_init
static void ch_list_init(ch_list_t *lp)
List initialization.
Definition: chlists.h:153
chSysLock
#define chSysLock()
Enters the kernel lock state.
Definition: nil/include/ch.h:1043