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