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