ChibiOS 21.11.5
ch.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 nil/src/ch.c
21 * @brief Nil RTOS main source file.
22 *
23 * @addtogroup NIL_KERNEL
24 * @{
25 */
26
27#include "ch.h"
28
29/*===========================================================================*/
30/* Module local definitions. */
31/*===========================================================================*/
32
33/*===========================================================================*/
34/* Module exported variables. */
35/*===========================================================================*/
36
37/**
38 * @brief System data structures.
39 */
41
42/*===========================================================================*/
43/* Module local variables. */
44/*===========================================================================*/
45
46/*===========================================================================*/
47/* Module local functions. */
48/*===========================================================================*/
49
50/*===========================================================================*/
51/* Module interrupt handlers. */
52/*===========================================================================*/
53
54/*===========================================================================*/
55/* Module exported functions. */
56/*===========================================================================*/
57
58/**
59 * @brief Retrieves the highest priority thread in the specified state and
60 * associated to the specified object.
61 *
62 * @param[in] state thread state
63 * @param[in] p object pointer
64 * @return The pointer to the found thread.
65 * @retval NULL if the thread is not found.
66 *
67 * @notapi
68 */
70 thread_t *tp = nil.threads;
71
72 while (tp < &nil.threads[CH_CFG_MAX_THREADS]) {
73 /* Is this thread matching?*/
74 if ((tp->state == state) && (tp->u1.p == p)) {
75 return tp;
76 }
77 tp++;
78 }
79 return NULL;
80}
81
82/**
83 * @brief Puts in ready state all thread matching the specified status and
84 * associated object.
85 *
86 * @param[in] p object pointer
87 * @param[in] cnt number of threads to be readied as a negative number,
88 * non negative numbers are ignored
89 * @param[in] msg the wakeup message
90 * @return The number of readied threads.
91 *
92 * @notapi
93 */
94cnt_t nil_ready_all(void *p, cnt_t cnt, msg_t msg) {
95 thread_t *tp = nil.threads;;
96
97 while (cnt < (cnt_t)0) {
98
99 chDbgAssert(tp < &nil.threads[CH_CFG_MAX_THREADS],
100 "pointer out of range");
101
102 /* Is this thread waiting on this queue?*/
103 if ((tp->state == NIL_STATE_WTQUEUE) && (tp->u1.p == p)) {
104 cnt++;
105 (void) chSchReadyI(tp, msg);
106 }
107 tp++;
108 }
109
110 return cnt;
111}
112
113#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__)
114/**
115 * @brief Guard code for @p chSysDisable().
116 *
117 * @notapi
118 */
120
121 if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
122 chSysHalt("SV#1");
123 }
124}
125
126/**
127 * @brief Guard code for @p chSysSuspend().
128 *
129 * @notapi
130 */
132
133 if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
134 chSysHalt("SV#2");
135 }
136}
137
138/**
139 * @brief Guard code for @p chSysEnable().
140 *
141 * @notapi
142 */
144
145 if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
146 chSysHalt("SV#3");
147 }
148}
149
150/**
151 * @brief Guard code for @p chSysLock().
152 *
153 * @notapi
154 */
156
157 if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
158 chSysHalt("SV#4");
159 }
161}
162
163/**
164 * @brief Guard code for @p chSysUnlock().
165 *
166 * @notapi
167 */
169
170 if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
171 chSysHalt("SV#5");
172 }
174}
175
176/**
177 * @brief Guard code for @p chSysLockFromIsr().
178 *
179 * @notapi
180 */
182
183 if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
184 chSysHalt("SV#6");
185 }
187}
188
189/**
190 * @brief Guard code for @p chSysUnlockFromIsr().
191 *
192 * @notapi
193 */
195
196 if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
197 chSysHalt("SV#7");
198 }
200}
201
202/**
203 * @brief Guard code for @p CH_IRQ_PROLOGUE().
204 *
205 * @notapi
206 */
208
210 if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
211 chSysHalt("SV#8");
212 }
213 nil.isr_cnt++;
215}
216
217/**
218 * @brief Guard code for @p CH_IRQ_EPILOGUE().
219 *
220 * @notapi
221 */
223
225 if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
226 chSysHalt("SV#9");
227 }
228 nil.isr_cnt--;
230}
231
232/**
233 * @brief I-class functions context check.
234 * @details Verifies that the system is in an appropriate state for invoking
235 * an I-class API function. A panic is generated if the state is
236 * not compatible.
237 *
238 * @api
239 */
241
242 if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
243 chSysHalt("SV#10");
244 }
245}
246
247/**
248 * @brief S-class functions context check.
249 * @details Verifies that the system is in an appropriate state for invoking
250 * an S-class API function. A panic is generated if the state is
251 * not compatible.
252 *
253 * @api
254 */
256
257 if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
258 chSysHalt("SV#11");
259 }
260}
261#endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */
262
263/**
264 * @brief Initializes the kernel.
265 * @details Initializes the kernel structures, the current instructions flow
266 * becomes the idle thread upon return. The idle thread must not
267 * invoke any kernel primitive able to change state to not runnable.
268 * @note This function assumes that the @p nil global variable has been
269 * zeroed by the runtime environment. If this is not the case then
270 * make sure to clear it before calling this function.
271 *
272 * @special
273 */
274void chSysInit(void) {
275 const thread_descriptor_t *tdp;
276
277 /* Optional library modules.*/
278 __oslib_init();
279
280 /* Architecture layer initialization.*/
281 port_init(&nil);
282
283 /* System initialization hook.*/
285
286 /* Making idle the current thread, this may change after rescheduling.*/
287 nil.next = nil.current = &nil.threads[CH_CFG_MAX_THREADS];
288 nil.current->state = NIL_STATE_READY;
289
290#if CH_DBG_ENABLE_STACK_CHECK == TRUE
291 /* The idle thread is a special case because its stack is set up by the
292 runtime environment.*/
293 nil.threads[CH_CFG_MAX_THREADS].wabase = THD_IDLE_BASE;
294#endif
295
296 /* Interrupts partially enabled. It is equivalent to entering the
297 kernel critical zone.*/
298 chSysSuspend();
299#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
300 nil.lock_cnt = (cnt_t)1;
301#endif
302
303#if CH_CFG_AUTOSTART_THREADS == TRUE
304 /* Iterates through the list of threads to be auto-started.*/
305 tdp = nil_thd_configs;
306 do {
307 (void) chThdCreateI(tdp);
308 tdp++;
309 } while (tdp->funcp != NULL);
310#endif
311
312 /* Starting the dance.*/
314 chSysUnlock();
315}
316
317/**
318 * @brief Halts the system.
319 * @details This function is invoked by the operating system when an
320 * unrecoverable error is detected, for example because a programming
321 * error in the application code that triggers an assertion while
322 * in debug mode.
323 * @note Can be invoked from any system state.
324 *
325 * @param[in] reason pointer to an error string
326 *
327 * @special
328 */
329void chSysHalt(const char *reason) {
330
331 port_disable();
332
333#if NIL_DBG_ENABLED
334 nil.dbg_panic_msg = reason;
335#else
336 (void)reason;
337#endif
338
339 /* Halt hook code, usually empty.*/
341
342 /* Harmless infinite loop.*/
343 while (true) {
344 }
345}
346
347/**
348 * @brief Time management handler.
349 * @note This handler has to be invoked by a periodic ISR in order to
350 * reschedule the waiting threads.
351 *
352 * @iclass
353 */
355
357
358#if CH_CFG_ST_TIMEDELTA == 0
359 thread_t *tp = &nil.threads[0];
360 nil.systime++;
361 do {
362 /* Is the thread in a wait state with timeout?.*/
363 if (tp->timeout > (sysinterval_t)0) {
364
365 chDbgAssert(!NIL_THD_IS_READY(tp), "is ready");
366
367 /* Did the timer reach zero?*/
368 if (--tp->timeout == (sysinterval_t)0) {
369 /* Timeout on queues/semaphores requires a special handling because
370 the counter must be incremented.*/
371 /*lint -save -e9013 [15.7] There is no else because it is not needed.*/
372 if (NIL_THD_IS_WTQUEUE(tp)) {
373 tp->u1.tqp->cnt++;
374 }
375 else if (NIL_THD_IS_SUSPENDED(tp)) {
376 *tp->u1.trp = NULL;
377 }
378 /*lint -restore*/
379 (void) chSchReadyI(tp, MSG_TIMEOUT);
380 }
381 }
382 /* Lock released in order to give a preemption chance on those
383 architectures supporting IRQ preemption.*/
385 tp++;
387 } while (tp < &nil.threads[CH_CFG_MAX_THREADS]);
388#else
389 thread_t *tp = &nil.threads[0];
391
392 chDbgAssert(nil.nexttime == port_timer_get_alarm(), "time mismatch");
393
394 do {
395 sysinterval_t timeout = tp->timeout;
396
397 /* Is the thread in a wait state with timeout?.*/
398 if (timeout > (sysinterval_t)0) {
399
400 chDbgAssert(!NIL_THD_IS_READY(tp), "is ready");
401 chDbgAssert(timeout >= chTimeDiffX(nil.lasttime, nil.nexttime),
402 "skipped one");
403
404 /* The volatile field is updated once, here.*/
405 timeout -= chTimeDiffX(nil.lasttime, nil.nexttime);
406 tp->timeout = timeout;
407
408 if (timeout == (sysinterval_t)0) {
409 /* Timeout on thread queues requires a special handling because the
410 counter must be incremented.*/
411 if (NIL_THD_IS_WTQUEUE(tp)) {
412 tp->u1.tqp->cnt++;
413 }
414 else {
415 if (NIL_THD_IS_SUSPENDED(tp)) {
416 *tp->u1.trp = NULL;
417 }
418 }
419 (void) chSchReadyI(tp, MSG_TIMEOUT);
420 }
421 else {
422 if (timeout <= (sysinterval_t)(next - (sysinterval_t)1)) {
423 next = timeout;
424 }
425 }
426 }
427
428 /* Lock released in order to give a preemption chance on those
429 architectures supporting IRQ preemption.*/
431 tp++;
433 } while (tp < &nil.threads[CH_CFG_MAX_THREADS]);
434
435 nil.lasttime = nil.nexttime;
436 if (next > (sysinterval_t)0) {
437 nil.nexttime = chTimeAddX(nil.nexttime, next);
438 port_timer_set_alarm(nil.nexttime);
439 }
440 else {
441 /* No tick event needed.*/
442 port_timer_stop_alarm();
443 }
444#endif
445}
446
447#if (CH_PORT_SUPPORTS_RECURSIVE_LOCKS == TRUE) || defined(__DOXYGEN__)
448/**
449 * @brief Unconditionally enters the kernel lock state.
450 * @note Can be called without previous knowledge of the current lock state.
451 * The final state is "s-locked".
452 *
453 * @special
454 */
456
458 chSysLock();
459 }
460}
461
462/**
463 * @brief Unconditionally leaves the kernel lock state.
464 * @note Can be called without previous knowledge of the current lock state.
465 * The final state is "normal".
466 *
467 * @special
468 */
470
472 chSysUnlock();
473 }
474}
475
476/**
477 * @brief Returns the execution status and enters a critical zone.
478 * @details This functions enters into a critical zone and can be called
479 * from any context. Because its flexibility it is less efficient
480 * than @p chSysLock() which is preferable when the calling context
481 * is known.
482 * @post The system is in a critical zone.
483 * @note This function is only available if the underlying port supports
484 * @p port_get_lock_status() and @p port_is_locked().
485 *
486 * @return The previous system status, the encoding of this
487 * status word is architecture-dependent and opaque.
488 *
489 * @xclass
490 */
492
494 if (!port_is_locked(sts)) {
495 if (port_is_isr_context()) {
497 }
498 else {
499 chSysLock();
500 }
501 }
502 return sts;
503}
504
505/**
506 * @brief Restores the specified execution status and leaves a critical zone.
507 * @note A call to @p chSchRescheduleS() is automatically performed
508 * if exiting the critical zone and if not in ISR context.
509 * @note This function is only available if the underlying port supports
510 * @p port_get_lock_status() and @p port_is_locked().
511 *
512 * @param[in] sts the system status to be restored.
513 *
514 * @xclass
515 */
517
518 if (!port_is_locked(sts)) {
519 if (port_is_isr_context()) {
521 }
522 else {
524 chSysUnlock();
525 }
526 }
527}
528#endif /* CH_PORT_SUPPORTS_RECURSIVE_LOCKS == TRUE */
529
530#if (PORT_SUPPORTS_RT == TRUE) || defined(__DOXYGEN__)
531/**
532 * @brief Realtime window test.
533 * @details This function verifies if the current realtime counter value
534 * lies within the specified range or not. The test takes care
535 * of the realtime counter wrapping to zero on overflow.
536 * @note When start==end then the function returns always false because a
537 * null time range is specified.
538 * @note This function is only available if the port layer supports the
539 * option @p PORT_SUPPORTS_RT.
540 *
541 * @param[in] cnt the counter value to be tested
542 * @param[in] start the start of the time window (inclusive)
543 * @param[in] end the end of the time window (non inclusive)
544 * @retval true current time within the specified time window.
545 * @retval false current time not within the specified time window.
546 *
547 * @xclass
548 */
550
551 return (bool)(((rtcnt_t)cnt - (rtcnt_t)start) <
552 ((rtcnt_t)end - (rtcnt_t)start));
553}
554
555/**
556 * @brief Polled delay.
557 * @note The real delay is always few cycles in excess of the specified
558 * value.
559 * @note This function is only available if the port layer supports the
560 * option @p PORT_SUPPORTS_RT.
561 *
562 * @param[in] cycles number of cycles
563 *
564 * @xclass
565 */
568 rtcnt_t end = start + cycles;
569
570 while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
571 }
572}
573#endif /* PORT_SUPPORTS_RT == TRUE */
574
575/**
576 * @brief Makes the specified thread ready for execution.
577 *
578 * @param[in] tp pointer to the @p thread_t object
579 * @param[in] msg the wakeup message
580 *
581 * @return The same reference passed as parameter.
582 */
584
586 chDbgCheck((tp >= nil.threads) && (tp < &nil.threads[CH_CFG_MAX_THREADS]));
587 chDbgAssert(!NIL_THD_IS_READY(tp), "already ready");
588 chDbgAssert(nil.next <= nil.current, "priority ordering");
589
590 tp->u1.msg = msg;
592 tp->timeout = (sysinterval_t)0;
593 if (tp < nil.next) {
594 nil.next = tp;
595 }
596 return tp;
597}
598
599/**
600 * @brief Evaluates if preemption is required.
601 * @details The decision is taken by comparing the relative priorities and
602 * depending on the state of the round robin timeout counter.
603 * @note Not a user function, it is meant to be invoked by the scheduler
604 * itself or from within the port layer.
605 *
606 * @retval true if there is a thread that must go in running state
607 * immediately.
608 * @retval false if preemption is not required.
609 *
610 * @special
611 */
613
614 return chSchIsRescRequiredI();
615}
616
617/**
618 * @brief Switches to the first thread on the runnable queue.
619 * @note Not a user function, it is meant to be invoked by the scheduler
620 * itself or from within the port layer.
621 *
622 * @special
623 */
625 thread_t *otp = nil.current;
626
627 nil.current = nil.next;
628 if (otp == &nil.threads[CH_CFG_MAX_THREADS]) {
630 }
631 port_switch(nil.next, otp);
632}
633
634/**
635 * @brief Reschedules if needed.
636 *
637 * @sclass
638 */
640
642
643 if (chSchIsRescRequiredI()) {
645 }
646}
647
648/**
649 * @brief Puts the current thread to sleep into the specified state with
650 * timeout specification.
651 * @details The thread goes into a sleeping state, if it is not awakened
652 * explicitly within the specified system time then it is forcibly
653 * awakened with a @p MSG_TIMEOUT low level message.
654 *
655 * @param[in] newstate the new thread state or a semaphore pointer
656 * @param[in] timeout the number of ticks before the operation timeouts.
657 * the following special values are allowed:
658 * - @a TIME_INFINITE no timeout.
659 * .
660 * @return The wakeup message.
661 * @retval MSG_TIMEOUT if a timeout occurred.
662 *
663 * @sclass
664 */
666 thread_t *ntp, *otp = nil.current;
667
669
670 chDbgAssert(otp != &nil.threads[CH_CFG_MAX_THREADS],
671 "idle cannot sleep");
672
673 /* Storing the wait object for the current thread.*/
674 otp->state = newstate;
675
676#if CH_CFG_ST_TIMEDELTA > 0
677 if (timeout != TIME_INFINITE) {
678 systime_t abstime;
679
680 /* TIMEDELTA makes sure to have enough time to reprogram the timer
681 before the free-running timer counter reaches the selected timeout.*/
682 if (timeout < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {
684 }
685
686 /* Absolute time of the timeout event.*/
687 abstime = chTimeAddX(chVTGetSystemTimeX(), timeout);
688
689 if (nil.lasttime == nil.nexttime) {
690 /* Special case, first thread asking for a timeout.*/
691 port_timer_start_alarm(abstime);
692 nil.nexttime = abstime;
693 }
694 else {
695 /* Special case, there are already other threads with a timeout
696 activated, evaluating the order.*/
697 if (chTimeIsInRangeX(abstime, nil.lasttime, nil.nexttime)) {
698 port_timer_set_alarm(abstime);
699 nil.nexttime = abstime;
700 }
701 }
702
703 /* Timeout settings.*/
704 otp->timeout = abstime - nil.lasttime;
705 }
706#else
707
708 /* Timeout settings.*/
709 otp->timeout = timeout;
710#endif
711
712 /* Scanning the whole threads array.*/
713 ntp = nil.threads;
714 while (true) {
715 /* Is this thread ready to execute?*/
716 if (NIL_THD_IS_READY(ntp)) {
717 nil.current = nil.next = ntp;
718 if (ntp == &nil.threads[CH_CFG_MAX_THREADS]) {
720 }
721 port_switch(ntp, otp);
722 return nil.current->u1.msg;
723 }
724
725 /* Points to the next thread in lowering priority order.*/
726 ntp++;
727 chDbgAssert(ntp <= &nil.threads[CH_CFG_MAX_THREADS],
728 "pointer out of range");
729 }
730}
731
732/**
733 * @brief Checks if the specified time is within the specified time range.
734 * @note When start==end then the function returns always false because the
735 * time window has zero size.
736 *
737 * @param[in] time the time to be verified
738 * @param[in] start the start of the time window (inclusive)
739 * @param[in] end the end of the time window (non inclusive)
740 * @retval true current time within the specified time window.
741 * @retval false current time not within the specified time window.
742 *
743 * @xclass
744 */
746
747 return (bool)((systime_t)((systime_t)(time) - (systime_t)(start)) <
748 (systime_t)((systime_t)(end) - (systime_t)(start)));
749}
750
751/**
752 * @brief Creates a new thread into a static memory area.
753 * @details The new thread is initialized and make ready to execute.
754 * @note A thread can terminate by calling @p chThdExit() or by simply
755 * returning from its main function.
756 *
757 * @param[out] tdp pointer to the thread descriptor structure
758 * @return The pointer to the @p thread_t structure allocated for
759 * the thread.
760 *
761 * @iclass
762 */
764 thread_t *tp;
765
767 (tdp->wbase != NULL) &&
769 (tdp->wend > tdp->wbase) &&
771 (tdp->funcp != NULL));
772
774
775 /* Pointer to the thread slot to be used.*/
776 tp = &nil.threads[tdp->prio];
778 "priority slot taken");
779
780#if CH_CFG_USE_EVENTS == TRUE
781 tp->epmask = (eventmask_t)0;
782#endif
783#if CH_DBG_ENABLE_STACK_CHECK == TRUE
784 tp->wabase = (stkalign_t *)tdp->wbase;
785#endif
786
787 /* Port dependent thread initialization.*/
788 PORT_SETUP_CONTEXT(tp, tdp->wbase, tdp->wend, tdp->funcp, tdp->arg);
789
790 /* Initialization hook.*/
792
793 /* Readying up thread.*/
794 return chSchReadyI(tp, MSG_OK);
795}
796
797/**
798 * @brief Creates a new thread into a static memory area.
799 * @details The new thread is initialized and make ready to execute.
800 * @note A thread can terminate by calling @p chThdExit() or by simply
801 * returning from its main function.
802 *
803 * @param[out] tdp pointer to the thread descriptor structure
804 * @return The pointer to the @p thread_t structure allocated for
805 * the thread.
806 *
807 * @api
808 */
810 thread_t *tp;
811
812 chSysLock();
813 tp = chThdCreateI(tdp);
815 chSysUnlock();
816
817 return tp;
818}
819
820/**
821 * @brief Terminates the current thread.
822 * @details The thread goes in the @p CH_STATE_FINAL state holding the
823 * specified exit status code, other threads can retrieve the
824 * exit status code by invoking the function @p chThdWait().
825 * @post Eventual code after this function will never be executed,
826 * this function never returns. The compiler has no way to
827 * know this so do not assume that the compiler would remove
828 * the dead code.
829 *
830 * @param[in] msg thread exit code
831 *
832 * @api
833 */
834void chThdExit(msg_t msg) {
835
836 chSysLock();
837
838 /* Exit handler hook.*/
840
841#if CH_CFG_USE_WAITEXIT == TRUE
842 {
843 /* Waking up any waiting thread.*/
844 thread_t *tp = nil.threads;
845 while (tp < &nil.threads[CH_CFG_MAX_THREADS]) {
846 /* Is this thread waiting for current thread termination?*/
847 if ((tp->state == NIL_STATE_WTEXIT) && (tp->u1.tp == nil.current)) {
848 (void) chSchReadyI(tp, msg);
849 }
850 tp++;
851 }
852 }
853#endif
854
855 /* Going into final state with exit message stored.*/
856 nil.current->u1.msg = msg;
858
859 /* The thread never returns here.*/
860 chDbgAssert(false, "zombies apocalypse");
861}
862
863/**
864 * @brief Blocks the execution of the invoking thread until the specified
865 * thread terminates then the exit code is returned.
866 *
867 * @param[in] tp pointer to the thread
868 * @return The exit code from the terminated thread.
869 *
870 * @api
871 */
873 msg_t msg;
874
875 chSysLock();
876 if (NIL_THD_IS_FINAL(tp)) {
877 msg = tp->u1.msg;
878 }
879 else {
880 nil.current->u1.tp = tp;
882 }
883 chSysUnlock();
884
885 return msg;
886}
887
888/**
889 * @brief Sends the current thread sleeping and sets a reference variable.
890 * @note This function must reschedule, it can only be called from thread
891 * context.
892 *
893 * @param[in] trp a pointer to a thread reference object
894 * @param[in] timeout the number of ticks before the operation timeouts,
895 * the following special values are allowed:
896 * - @a TIME_IMMEDIATE immediate timeout.
897 * - @a TIME_INFINITE no timeout.
898 * .
899 * @return The wake up message.
900 *
901 * @sclass
902 */
904
905 chDbgAssert(*trp == NULL, "not NULL");
906
907 if (TIME_IMMEDIATE == timeout) {
908 return MSG_TIMEOUT;
909 }
910
911 *trp = nil.current;
912 nil.current->u1.trp = trp;
914}
915
916/**
917 * @brief Wakes up a thread waiting on a thread reference object.
918 * @note This function must not reschedule because it can be called from
919 * ISR context.
920 *
921 * @param[in] trp a pointer to a thread reference object
922 * @param[in] msg the message code
923 *
924 * @iclass
925 */
927
928 if (*trp != NULL) {
929 thread_reference_t tr = *trp;
930
931 chDbgAssert(NIL_THD_IS_SUSPENDED(tr), "not suspended");
932
933 *trp = NULL;
934 (void) chSchReadyI(tr, msg);
935 }
936}
937
938/**
939 * @brief Wakes up a thread waiting on a thread reference object.
940 * @note This function must reschedule, it can only be called from thread
941 * context.
942 *
943 * @param[in] trp a pointer to a thread reference object
944 * @param[in] msg the message code
945 *
946 * @api
947 */
949
950 chSysLock();
951 chThdResumeS(trp, msg);
952 chSysUnlock();
953}
954
955/**
956 * @brief Suspends the invoking thread for the specified time.
957 *
958 * @param[in] timeout the delay in system ticks
959 *
960 * @api
961 */
963
964 chSysLock();
965 chThdSleepS(timeout);
966 chSysUnlock();
967}
968
969/**
970 * @brief Suspends the invoking thread until the system time arrives to the
971 * specified value.
972 *
973 * @param[in] abstime absolute system time
974 *
975 * @api
976 */
978
979 chSysLock();
980 chThdSleepUntilS(abstime);
981 chSysUnlock();
982}
983
984/**
985 * @brief Enqueues the caller thread on a threads queue object.
986 * @details The caller thread is enqueued and put to sleep until it is
987 * dequeued or the specified timeouts expires.
988 *
989 * @param[in] tqp pointer to a @p threads_queue_t structure
990 * @param[in] timeout the timeout in system ticks, the special values are
991 * handled as follow:
992 * - @a TIME_IMMEDIATE immediate timeout.
993 * - @a TIME_INFINITE no timeout.
994 * .
995 * @return The message from @p osalQueueWakeupOneI() or
996 * @p osalQueueWakeupAllI() functions.
997 * @retval MSG_TIMEOUT if the thread has not been dequeued within the
998 * specified timeout or if the function has been
999 * invoked with @p TIME_IMMEDIATE as timeout
1000 * specification.
1001 *
1002 * @sclass
1003 */
1005
1007 chDbgCheck(tqp != NULL);
1008
1009 chDbgAssert(tqp->cnt <= (cnt_t)0, "invalid counter");
1010
1011 if (TIME_IMMEDIATE == timeout) {
1012 return MSG_TIMEOUT;
1013 }
1014
1015 tqp->cnt--;
1016 nil.current->u1.tqp = tqp;
1017 return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout);
1018}
1019
1020/**
1021 * @brief Dequeues and wakes up one thread from the threads queue object.
1022 * @details Dequeues one thread from the queue without checking if the queue
1023 * is empty.
1024 * @pre The queue must contain at least an object.
1025 *
1026 * @param[in] tqp pointer to a @p threads_queue_t structure
1027 * @param[in] msg the message code
1028 *
1029 * @iclass
1030 */
1032 thread_t *tp;
1033
1034 chDbgAssert(tqp->cnt < (cnt_t)0, "empty queue");
1035
1036 tqp->cnt++;
1037 tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)tqp);
1038
1039 chDbgAssert(tp != NULL, "thread not found");
1040
1041 (void) chSchReadyI(tp, msg);
1042}
1043
1044/**
1045 * @brief Dequeues and wakes up one thread from the threads queue object,
1046 * if any.
1047 *
1048 * @param[in] tqp pointer to a @p threads_queue_t structure
1049 * @param[in] msg the message code
1050 *
1051 * @iclass
1052 */
1054
1056 chDbgCheck(tqp != NULL);
1057
1058 if (tqp->cnt < (cnt_t)0) {
1059 chThdDoDequeueNextI(tqp, msg);
1060 }
1061}
1062
1063/**
1064 * @brief Dequeues and wakes up all threads from the threads queue object.
1065 *
1066 * @param[in] tqp pointer to a @p threads_queue_t structure
1067 * @param[in] msg the message code
1068 *
1069 * @iclass
1070 */
1072
1074 chDbgCheck(tqp != NULL);
1075
1076 tqp->cnt = nil_ready_all((void *)tqp, tqp->cnt, msg);
1077}
1078
1079/** @} */
#define CH_CFG_THREAD_EXT_INIT_HOOK(tr)
Threads initialization hook.
#define CH_CFG_MAX_THREADS
Maximum number of user threads in the application.
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread on a threads queue object.
Definition ch.c:1004
syssts_t chSysGetStatusAndLockX(void)
Returns the execution status and enters a critical zone.
Definition ch.c:491
#define NIL_STATE_READY
Thread ready or executing.
#define chSchIsRescRequiredI()
Evaluates if a reschedule is required.
void chDbgCheckClassS(void)
S-class functions context check.
Definition ch.c:255
void __dbg_check_disable(void)
Guard code for chSysDisable().
Definition ch.c:119
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end)
Realtime window test.
Definition ch.c:549
void chSysTimerHandlerI(void)
Time management handler.
Definition ch.c:354
#define THD_IDLE_BASE
void chThdExit(msg_t msg)
Terminates the current thread.
Definition ch.c:834
void __dbg_check_unlock(void)
Guard code for chSysUnlock().
Definition ch.c:168
#define chSysSuspend()
Raises the system interrupt priority mask to system level.
#define __dbg_enter_lock()
#define NIL_STATE_WTEXIT
Waiting a thread.
void chDbgCheckClassI(void)
I-class functions context check.
Definition ch.c:240
msg_t chThdWait(thread_t *tp)
Blocks the execution of the invoking thread until the specified thread terminates then the exit code ...
Definition ch.c:872
void chThdResume(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition ch.c:948
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition ch.c:903
#define chSysLockFromISR()
Enters the kernel lock state from within an interrupt handler.
void chSchRescheduleS(void)
Reschedules if needed.
Definition ch.c:639
void chSysPolledDelayX(rtcnt_t cycles)
Polled delay.
Definition ch.c:566
thread_t * chThdCreateI(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition ch.c:763
void chThdResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition ch.c:926
#define chTimeAddX(systime, interval)
Adds an interval to a system time returning a system time.
#define chSysUnlock()
Leaves the kernel lock state.
os_instance_t nil
System data structures.
Definition ch.c:40
cnt_t nil_ready_all(void *p, cnt_t cnt, msg_t msg)
Puts in ready state all thread matching the specified status and associated object.
Definition ch.c:94
#define NIL_STATE_WTQUEUE
On queue or semaph.
#define NIL_STATE_SUSPENDED
Thread suspended.
void chThdSleepUntil(systime_t abstime)
Suspends the invoking thread until the system time arrives to the specified value.
Definition ch.c:977
void __dbg_check_lock(void)
Guard code for chSysLock().
Definition ch.c:155
#define NIL_THD_IS_FINAL(tp)
#define chThdSleepUntilS(abstime)
Suspends the invoking thread until the system time arrives to the specified value.
void chSysRestoreStatusX(syssts_t sts)
Restores the specified execution status and leaves a critical zone.
Definition ch.c:516
#define chThdResumeS(trp, msg)
Wakes up a thread waiting on a thread reference object.
#define chSysLock()
Enters the kernel lock state.
void chThdSleep(sysinterval_t timeout)
Suspends the invoking thread for the specified time.
Definition ch.c:962
bool chSchIsPreemptionRequired(void)
Evaluates if preemption is required.
Definition ch.c:612
void __dbg_check_leave_isr(void)
Guard code for CH_IRQ_EPILOGUE().
Definition ch.c:222
void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object, if any.
Definition ch.c:1053
#define NIL_STATE_FINAL
Thread terminated.
void chSysUnconditionalUnlock(void)
Unconditionally leaves the kernel lock state.
Definition ch.c:469
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:745
#define NIL_THD_IS_SUSPENDED(tp)
#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 NIL_THD_IS_WTSTART(tp)
void __dbg_check_enable(void)
Guard code for chSysEnable().
Definition ch.c:143
void __dbg_check_lock_from_isr(void)
Guard code for chSysLockFromIsr().
Definition ch.c:181
void __dbg_check_unlock_from_isr(void)
Guard code for chSysUnlockFromIsr().
Definition ch.c:194
thread_t * chSchReadyI(thread_t *tp, msg_t msg)
Makes the specified thread ready for execution.
Definition ch.c:583
#define __dbg_leave_lock()
thread_t * chThdCreate(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition ch.c:809
thread_t * nil_find_thread(tstate_t state, void *p)
Retrieves the highest priority thread in the specified state and associated to the specified object.
Definition ch.c:69
#define chSysUnlockFromISR()
Leaves the kernel lock state from within an interrupt handler.
void chSchDoPreemption(void)
Switches to the first thread on the runnable queue.
Definition ch.c:624
#define NIL_THD_IS_READY(tp)
msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout)
Puts the current thread to sleep into the specified state with timeout specification.
Definition ch.c:665
void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object.
Definition ch.c:1031
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the threads queue object.
Definition ch.c:1071
void __dbg_check_enter_isr(void)
Guard code for CH_IRQ_PROLOGUE().
Definition ch.c:207
#define NIL_THD_IS_WTQUEUE(tp)
void __dbg_check_suspend(void)
Guard code for chSysSuspend().
Definition ch.c:131
void chSysUnconditionalLock(void)
Unconditionally enters the kernel lock state.
Definition ch.c:455
void chSysInit(void)
Initializes the kernel.
Definition ch.c:274
void chSysHalt(const char *reason)
Halts the system.
Definition ch.c:329
#define chDbgAssert(c, r)
Condition assertion.
Definition chdebug.h:143
#define chDbgCheck(c)
Function parameters check.
Definition chdebug.h:117
#define CH_CFG_SYSTEM_HALT_HOOK(reason)
System halt hook.
#define CH_CFG_IDLE_LEAVE_HOOK()
Idle thread leave hook.
#define CH_CFG_IDLE_ENTER_HOOK()
Idle thread enter hook.
#define CH_CFG_THREAD_EXIT_HOOK(tp)
Threads finalization hook.
#define CH_CFG_SYSTEM_INIT_HOOK()
System initialization hook.
#define MEM_IS_ALIGNED(p, a)
Returns whatever a pointer or memory size is aligned.
Definition chalign.h:90
int32_t cnt_t
Definition chearly.h:91
int32_t msg_t
Definition chearly.h:87
uint8_t tstate_t
Definition chearly.h:83
port_syssts_t syssts_t
Definition chearly.h:78
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
port_rtcnt_t rtcnt_t
Definition chearly.h:76
uint32_t eventmask_t
Definition chearly.h:89
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
static void __oslib_init(void)
Initialization of all library modules.
Definition chlib.h:248
static void port_unlock_from_isr(void)
Kernel-unlock action from an interrupt handler.
Definition chcore.h:367
#define PORT_WORKING_AREA_ALIGN
Working Areas alignment constant.
Definition chcore.h:61
static void port_disable(void)
Disables all the interrupt sources.
Definition chcore.h:375
static void port_lock_from_isr(void)
Kernel-lock action from an interrupt handler.
Definition chcore.h:357
#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 port_get_lock_status()
Returns a word representing a critical section status.
Definition chcore.h:282
#define port_is_locked(sts)
Determines if in a critical section.
Definition chcore.h:292
static bool port_is_isr_context(void)
Determines the current execution context.
Definition chcore.h:328
#define port_switch(ntp, otp)
Performs a context switch between two threads.
Definition chcore.h:267
#define CH_CFG_ST_TIMEDELTA
#define MSG_OK
Normal wakeup message.
Definition chschd.h:38
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition chschd.h:39
#define chSysGetRealtimeCounterX()
Returns the current value of the system real time counter.
Definition chsys.h:291
uint64_t systime_t
Type of system time.
Definition chtime.h:106
#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
#define TIME_INFINITE
Infinite interval specification for all functions with a timeout specification.
Definition chtime.h:54
stkalign_t * wabase
Working area base address.
Definition chobjects.h:198
tstate_t state
Current thread state.
Definition chobjects.h:203
Type of a thread descriptor.
Definition chthreads.h:56
stkalign_t * wbase
Pointer to the working area base.
Definition chthreads.h:64
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
Type of a thread queue.
Definition osal.h:238