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