ChibiOS/NIL  4.1.0
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  */
70 thread_t *nil_find_thread(tstate_t state, void *p) {
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  */
95 cnt_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 
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  */
144 void __dbg_check_enable(void) {
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  */
156 void __dbg_check_lock(void) {
157 
158  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
159  chSysHalt("SV#4");
160  }
161  _dbg_enter_lock();
162 }
163 
164 /**
165  * @brief Guard code for @p chSysUnlock().
166  *
167  * @notapi
168  */
169 void __dbg_check_unlock(void) {
170 
171  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
172  chSysHalt("SV#5");
173  }
174  _dbg_leave_lock();
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  }
187  _dbg_enter_lock();
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  }
200  _dbg_leave_lock();
201 }
202 
203 /**
204  * @brief Guard code for @p CH_IRQ_PROLOGUE().
205  *
206  * @notapi
207  */
209 
210  port_lock_from_isr();
211  if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
212  chSysHalt("SV#8");
213  }
214  nil.isr_cnt++;
215  port_unlock_from_isr();
216 }
217 
218 /**
219  * @brief Guard code for @p CH_IRQ_EPILOGUE().
220  *
221  * @notapi
222  */
224 
225  port_lock_from_isr();
226  if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
227  chSysHalt("SV#9");
228  }
229  nil.isr_cnt--;
230  port_unlock_from_isr();
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  */
241 void chDbgCheckClassI(void) {
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  */
256 void chDbgCheckClassS(void) {
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  */
275 void 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.*/
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.*/
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  */
330 void 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.*/
341  CH_CFG_SYSTEM_HALT_HOOK(reason);
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  */
355 void chSysTimerHandlerI(void) {
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];
394  sysinterval_t next = (sysinterval_t)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");
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 
440  if (next > (sysinterval_t)0) {
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 /**
452  * @brief Unconditionally enters the kernel lock state.
453  * @note Can be called without previous knowledge of the current lock state.
454  * The final state is "s-locked".
455  *
456  * @special
457  */
459 
460  if (port_irq_enabled(port_get_irq_status())) {
461  chSysLock();
462  }
463 }
464 
465 /**
466  * @brief Unconditionally leaves the kernel lock state.
467  * @note Can be called without previous knowledge of the current lock state.
468  * The final state is "normal".
469  *
470  * @special
471  */
473 
474  if (!port_irq_enabled(port_get_irq_status())) {
475  chSysUnlock();
476  }
477 }
478 
479 /**
480  * @brief Returns the execution status and enters a critical zone.
481  * @details This functions enters into a critical zone and can be called
482  * from any context. Because its flexibility it is less efficient
483  * than @p chSysLock() which is preferable when the calling context
484  * is known.
485  * @post The system is in a critical zone.
486  *
487  * @return The previous system status, the encoding of this
488  * status word is architecture-dependent and opaque.
489  *
490  * @xclass
491  */
493 
494  syssts_t sts = port_get_irq_status();
495  if (port_irq_enabled(sts)) {
496  if (port_is_isr_context()) {
498  }
499  else {
500  chSysLock();
501  }
502  }
503  return sts;
504 }
505 
506 /**
507  * @brief Restores the specified execution status and leaves a critical zone.
508  * @note A call to @p chSchRescheduleS() is automatically performed
509  * if exiting the critical zone and if not in ISR context.
510  *
511  * @param[in] sts the system status to be restored.
512  *
513  * @xclass
514  */
516 
517  if (port_irq_enabled(sts)) {
518  if (port_is_isr_context()) {
520  }
521  else {
523  chSysUnlock();
524  }
525  }
526 }
527 
528 #if (PORT_SUPPORTS_RT == TRUE) || defined(__DOXYGEN__)
529 /**
530  * @brief Realtime window test.
531  * @details This function verifies if the current realtime counter value
532  * lies within the specified range or not. The test takes care
533  * of the realtime counter wrapping to zero on overflow.
534  * @note When start==end then the function returns always false because a
535  * null time range is specified.
536  * @note This function is only available if the port layer supports the
537  * option @p PORT_SUPPORTS_RT.
538  *
539  * @param[in] cnt the counter value to be tested
540  * @param[in] start the start of the time window (inclusive)
541  * @param[in] end the end of the time window (non inclusive)
542  * @retval true current time within the specified time window.
543  * @retval false current time not within the specified time window.
544  *
545  * @xclass
546  */
548 
549  return (bool)(((rtcnt_t)cnt - (rtcnt_t)start) <
550  ((rtcnt_t)end - (rtcnt_t)start));
551 }
552 
553 /**
554  * @brief Polled delay.
555  * @note The real delay is always few cycles in excess of the specified
556  * value.
557  * @note This function is only available if the port layer supports the
558  * option @p PORT_SUPPORTS_RT.
559  *
560  * @param[in] cycles number of cycles
561  *
562  * @xclass
563  */
566  rtcnt_t end = start + cycles;
567 
568  while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
569  }
570 }
571 #endif /* PORT_SUPPORTS_RT == TRUE */
572 
573 /**
574  * @brief Makes the specified thread ready for execution.
575  *
576  * @param[in] tp pointer to the @p thread_t object
577  * @param[in] msg the wakeup message
578  *
579  * @return The same reference passed as parameter.
580  */
582 
584  chDbgCheck((tp >= nil.threads) && (tp < &nil.threads[CH_CFG_MAX_THREADS]));
585  chDbgAssert(!NIL_THD_IS_READY(tp), "already ready");
586  chDbgAssert(nil.next <= nil.current, "priority ordering");
587 
588  tp->u1.msg = msg;
589  tp->state = NIL_STATE_READY;
590  tp->timeout = (sysinterval_t)0;
591  if (tp < nil.next) {
592  nil.next = tp;
593  }
594  return tp;
595 }
596 
597 /**
598  * @brief Evaluates if preemption is required.
599  * @details The decision is taken by comparing the relative priorities and
600  * depending on the state of the round robin timeout counter.
601  * @note Not a user function, it is meant to be invoked by the scheduler
602  * itself or from within the port layer.
603  *
604  * @retval true if there is a thread that must go in running state
605  * immediately.
606  * @retval false if preemption is not required.
607  *
608  * @special
609  */
611 
612  return chSchIsRescRequiredI();
613 }
614 
615 /**
616  * @brief Switches to the first thread on the runnable queue.
617  * @note Not a user function, it is meant to be invoked by the scheduler
618  * itself or from within the port layer.
619  *
620  * @special
621  */
622 void chSchDoPreemption(void) {
623  thread_t *otp = nil.current;
624 
625  nil.current = nil.next;
626  if (otp == &nil.threads[CH_CFG_MAX_THREADS]) {
628  }
629  port_switch(nil.next, otp);
630 }
631 
632 /**
633  * @brief Reschedules if needed.
634  *
635  * @sclass
636  */
637 void chSchRescheduleS(void) {
638 
640 
641  if (chSchIsRescRequiredI()) {
643  }
644 }
645 
646 /**
647  * @brief Puts the current thread to sleep into the specified state with
648  * timeout specification.
649  * @details The thread goes into a sleeping state, if it is not awakened
650  * explicitly within the specified system time then it is forcibly
651  * awakened with a @p MSG_TIMEOUT low level message.
652  *
653  * @param[in] newstate the new thread state or a semaphore pointer
654  * @param[in] timeout the number of ticks before the operation timeouts.
655  * the following special values are allowed:
656  * - @a TIME_INFINITE no timeout.
657  * .
658  * @return The wakeup message.
659  * @retval MSG_TIMEOUT if a timeout occurred.
660  *
661  * @sclass
662  */
664  thread_t *ntp, *otp = nil.current;
665 
667 
669  "idle cannot sleep");
670 
671  /* Storing the wait object for the current thread.*/
672  otp->state = newstate;
673 
674 #if CH_CFG_ST_TIMEDELTA > 0
675  if (timeout != TIME_INFINITE) {
676  systime_t abstime;
677 
678  /* TIMEDELTA makes sure to have enough time to reprogram the timer
679  before the free-running timer counter reaches the selected timeout.*/
680  if (timeout < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {
682  }
683 
684  /* Absolute time of the timeout event.*/
685  abstime = chTimeAddX(chVTGetSystemTimeX(), timeout);
686 
687  if (nil.lasttime == nil.nexttime) {
688  /* Special case, first thread asking for a timeout.*/
689  port_timer_start_alarm(abstime);
690  nil.nexttime = abstime;
691  }
692  else {
693  /* Special case, there are already other threads with a timeout
694  activated, evaluating the order.*/
695  if (chTimeIsInRangeX(abstime, nil.lasttime, nil.nexttime)) {
696  port_timer_set_alarm(abstime);
697  nil.nexttime = abstime;
698  }
699  }
700 
701  /* Timeout settings.*/
702  otp->timeout = abstime - nil.lasttime;
703  }
704 #else
705 
706  /* Timeout settings.*/
707  otp->timeout = timeout;
708 #endif
709 
710  /* Scanning the whole threads array.*/
711  ntp = nil.threads;
712  while (true) {
713  /* Is this thread ready to execute?*/
714  if (NIL_THD_IS_READY(ntp)) {
715  nil.current = nil.next = ntp;
716  if (ntp == &nil.threads[CH_CFG_MAX_THREADS]) {
718  }
719  port_switch(ntp, otp);
720  return nil.current->u1.msg;
721  }
722 
723  /* Points to the next thread in lowering priority order.*/
724  ntp++;
726  "pointer out of range");
727  }
728 }
729 
730 /**
731  * @brief Checks if the specified time is within the specified time range.
732  * @note When start==end then the function returns always false because the
733  * time window has zero size.
734  *
735  * @param[in] time the time to be verified
736  * @param[in] start the start of the time window (inclusive)
737  * @param[in] end the end of the time window (non inclusive)
738  * @retval true current time within the specified time window.
739  * @retval false current time not within the specified time window.
740  *
741  * @xclass
742  */
744 
745  return (bool)((systime_t)((systime_t)(time) - (systime_t)(start)) <
746  (systime_t)((systime_t)(end) - (systime_t)(start)));
747 }
748 
749 /**
750  * @brief Creates a new thread into a static memory area.
751  * @details The new thread is initialized and make ready to execute.
752  * @note A thread can terminate by calling @p chThdExit() or by simply
753  * returning from its main function.
754  *
755  * @param[out] tdp pointer to the thread descriptor structure
756  * @return The pointer to the @p thread_t structure allocated for
757  * the thread.
758  *
759  * @iclass
760  */
762  thread_t *tp;
763 
765  (tdp->wbase != NULL) &&
766  MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) &&
767  (tdp->wend > tdp->wbase) &&
768  MEM_IS_ALIGNED(tdp->wbase, PORT_STACK_ALIGN) &&
769  (tdp->funcp != NULL));
770 
772 
773  /* Pointer to the thread slot to be used.*/
774  tp = &nil.threads[tdp->prio];
775  chDbgAssert(NIL_THD_IS_WTSTART(tp) || NIL_THD_IS_FINAL(tp),
776  "priority slot taken");
777 
778 #if CH_CFG_USE_EVENTS == TRUE
779  tp->epmask = (eventmask_t)0;
780 #endif
781 #if CH_DBG_ENABLE_STACK_CHECK == TRUE
782  tp->wabase = (stkalign_t *)tdp->wbase;
783 #endif
784 
785  /* Port dependent thread initialization.*/
786  PORT_SETUP_CONTEXT(tp, tdp->wbase, tdp->wend, tdp->funcp, tdp->arg);
787 
788  /* Initialization hook.*/
790 
791  /* Readying up thread.*/
792  return chSchReadyI(tp, MSG_OK);
793 }
794 
795 /**
796  * @brief Creates a new thread into a static memory area.
797  * @details The new thread is initialized and make ready to execute.
798  * @note A thread can terminate by calling @p chThdExit() or by simply
799  * returning from its main function.
800  *
801  * @param[out] tdp pointer to the thread descriptor structure
802  * @return The pointer to the @p thread_t structure allocated for
803  * the thread.
804  *
805  * @api
806  */
808  thread_t *tp;
809 
810  chSysLock();
811  tp = chThdCreateI(tdp);
813  chSysUnlock();
814 
815  return tp;
816 }
817 
818 /**
819  * @brief Terminates the current thread.
820  * @details The thread goes in the @p CH_STATE_FINAL state holding the
821  * specified exit status code, other threads can retrieve the
822  * exit status code by invoking the function @p chThdWait().
823  * @post Exiting a non-static thread that does not have references
824  * (detached) causes the thread to remain in the registry.
825  * It can only be removed by performing a registry scan operation.
826  * @post Eventual code after this function will never be executed,
827  * this function never returns. The compiler has no way to
828  * know this so do not assume that the compiler would remove
829  * the dead code.
830  *
831  * @param[in] msg thread exit code
832  *
833  * @api
834  */
835 void chThdExit(msg_t msg) {
836 
837  chSysLock();
838 
839  /* Exit handler hook.*/
841 
842 #if CH_CFG_USE_WAITEXIT == TRUE
843  {
844  /* Waking up any waiting thread.*/
845  thread_t *tp = nil.threads;
846  while (tp < &nil.threads[CH_CFG_MAX_THREADS]) {
847  /* Is this thread waiting for current thread termination?*/
848  if ((tp->state == NIL_STATE_WTEXIT) && (tp->u1.tp == nil.current)) {
849  (void) chSchReadyI(tp, msg);
850  }
851  tp++;
852  }
853  }
854 #endif
855 
856  /* Going into final state with exit message stored.*/
857  nil.current->u1.msg = msg;
859 
860  /* The thread never returns here.*/
861  chDbgAssert(false, "zombies apocalypse");
862 }
863 
864 /**
865  * @brief Blocks the execution of the invoking thread until the specified
866  * thread terminates then the exit code is returned.
867  *
868  * @param[in] tp pointer to the thread
869  * @return The exit code from the terminated thread.
870  *
871  * @api
872  */
874  msg_t msg;
875 
876  chSysLock();
877  if (NIL_THD_IS_FINAL(tp)) {
878  msg = tp->u1.msg;
879  }
880  else {
881  nil.current->u1.tp = tp;
883  }
884  chSysUnlock();
885 
886  return msg;
887 }
888 
889 /**
890  * @brief Sends the current thread sleeping and sets a reference variable.
891  * @note This function must reschedule, it can only be called from thread
892  * context.
893  *
894  * @param[in] trp a pointer to a thread reference object
895  * @param[in] timeout the number of ticks before the operation timeouts,
896  * the following special values are allowed:
897  * - @a TIME_IMMEDIATE immediate timeout.
898  * - @a TIME_INFINITE no timeout.
899  * .
900  * @return The wake up message.
901  *
902  * @sclass
903  */
905 
906  chDbgAssert(*trp == NULL, "not NULL");
907 
908  if (TIME_IMMEDIATE == timeout) {
909  return MSG_TIMEOUT;
910  }
911 
912  *trp = nil.current;
913  nil.current->u1.trp = trp;
914  return chSchGoSleepTimeoutS(NIL_STATE_SUSPENDED, timeout);
915 }
916 
917 /**
918  * @brief Wakes up a thread waiting on a thread reference object.
919  * @note This function must not reschedule because it can be called from
920  * ISR context.
921  *
922  * @param[in] trp a pointer to a thread reference object
923  * @param[in] msg the message code
924  *
925  * @iclass
926  */
928 
929  if (*trp != NULL) {
930  thread_reference_t tr = *trp;
931 
932  chDbgAssert(NIL_THD_IS_SUSPENDED(tr), "not suspended");
933 
934  *trp = NULL;
935  (void) chSchReadyI(tr, msg);
936  }
937 }
938 
939 /**
940  * @brief Wakes up a thread waiting on a thread reference object.
941  * @note This function must reschedule, it can only be called from thread
942  * context.
943  *
944  * @param[in] trp a pointer to a thread reference object
945  * @param[in] msg the message code
946  *
947  * @api
948  */
950 
951  chSysLock();
952  chThdResumeS(trp, msg);
953  chSysUnlock();
954 }
955 
956 /**
957  * @brief Suspends the invoking thread for the specified time.
958  *
959  * @param[in] timeout the delay in system ticks
960  *
961  * @api
962  */
963 void chThdSleep(sysinterval_t timeout) {
964 
965  chSysLock();
966  chThdSleepS(timeout);
967  chSysUnlock();
968 }
969 
970 /**
971  * @brief Suspends the invoking thread until the system time arrives to the
972  * specified value.
973  *
974  * @param[in] abstime absolute system time
975  *
976  * @api
977  */
978 void chThdSleepUntil(systime_t abstime) {
979 
980  chSysLock();
981  chThdSleepUntilS(abstime);
982  chSysUnlock();
983 }
984 
985 /**
986  * @brief Enqueues the caller thread on a threads queue object.
987  * @details The caller thread is enqueued and put to sleep until it is
988  * dequeued or the specified timeouts expires.
989  *
990  * @param[in] tqp pointer to the threads queue object
991  * @param[in] timeout the timeout in system ticks, the special values are
992  * handled as follow:
993  * - @a TIME_IMMEDIATE immediate timeout.
994  * - @a TIME_INFINITE no timeout.
995  * .
996  * @return The message from @p osalQueueWakeupOneI() or
997  * @p osalQueueWakeupAllI() functions.
998  * @retval MSG_TIMEOUT if the thread has not been dequeued within the
999  * specified timeout or if the function has been
1000  * invoked with @p TIME_IMMEDIATE as timeout
1001  * specification.
1002  *
1003  * @sclass
1004  */
1006 
1007  chDbgCheckClassS();
1008  chDbgCheck(tqp != NULL);
1009 
1010  chDbgAssert(tqp->cnt <= (cnt_t)0, "invalid counter");
1011 
1012  if (TIME_IMMEDIATE == timeout) {
1013  return MSG_TIMEOUT;
1014  }
1015 
1016  tqp->cnt--;
1017  nil.current->u1.tqp = tqp;
1018  return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout);
1019 }
1020 
1021 /**
1022  * @brief Dequeues and wakes up one thread from the threads queue object.
1023  * @details Dequeues one thread from the queue without checking if the queue
1024  * is empty.
1025  * @pre The queue must contain at least an object.
1026  *
1027  * @param[in] tqp pointer to the threads queue object
1028  * @param[in] msg the message code
1029  *
1030  * @iclass
1031  */
1033  thread_t *tp;
1034 
1035  chDbgAssert(tqp->cnt < (cnt_t)0, "empty queue");
1036 
1037  tqp->cnt++;
1038  tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)tqp);
1039 
1040  chDbgAssert(tp != NULL, "thread not found");
1041 
1042  (void) chSchReadyI(tp, msg);
1043 }
1044 
1045 /**
1046  * @brief Dequeues and wakes up one thread from the threads queue object,
1047  * if any.
1048  *
1049  * @param[in] tqp pointer to the threads queue object
1050  * @param[in] msg the message code
1051  *
1052  * @iclass
1053  */
1055 
1056  chDbgCheckClassI();
1057  chDbgCheck(tqp != NULL);
1058 
1059  if (tqp->cnt < (cnt_t)0) {
1060  chThdDoDequeueNextI(tqp, msg);
1061  }
1062 }
1063 
1064 /**
1065  * @brief Dequeues and wakes up all threads from the threads queue object.
1066  *
1067  * @param[in] tqp pointer to the threads queue object
1068  * @param[in] msg the message code
1069  *
1070  * @iclass
1071  */
1073 
1074  chDbgCheckClassI();
1075  chDbgCheck(tqp != NULL);
1076 
1077  tqp->cnt = nil_ready_all((void *)tqp, tqp->cnt, msg);
1078 }
1079 
1080 /** @} */
nil_thread::p
void * p
Generic pointer.
Definition: ch.h:521
chSchReadyI
thread_t * chSchReadyI(thread_t *tp, msg_t msg)
Makes the specified thread ready for execution.
Definition: ch.c:581
nil_thread::tqp
threads_queue_t * tqp
Pointer to thread queue.
Definition: ch.h:524
chThdResume
void chThdResume(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: ch.c:949
chVTGetSystemTimeX
#define chVTGetSystemTimeX()
Current system time.
Definition: ch.h:1254
__dbg_check_unlock_from_isr
void __dbg_check_unlock_from_isr(void)
Guard code for chSysUnlockFromIsr().
Definition: ch.c:195
chTimeDiffX
#define chTimeDiffX(start, end)
Subtracts two system times returning an interval.
Definition: ch.h:1307
chSchGoSleepTimeoutS
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:663
chSysUnconditionalUnlock
void chSysUnconditionalUnlock(void)
Unconditionally leaves the kernel lock state.
Definition: ch.c:472
chSchIsPreemptionRequired
bool chSchIsPreemptionRequired(void)
Evaluates if preemption is required.
Definition: ch.c:610
nil_thread::msg
msg_t msg
Wake-up/exit message.
Definition: ch.h:520
chDbgCheckClassS
void chDbgCheckClassS(void)
S-class functions context check.
Definition: ch.c:256
chSysUnlockFromISR
#define chSysUnlockFromISR()
Leaves the kernel lock state from within an interrupt handler.
Definition: ch.h:1088
chSysGetStatusAndLockX
syssts_t chSysGetStatusAndLockX(void)
Returns the execution status and enters a critical zone.
Definition: ch.c:492
__dbg_check_lock
void __dbg_check_lock(void)
Guard code for chSysLock().
Definition: ch.c:156
nil_thread_descriptor
Structure representing a thread descriptor.
Definition: ch.h:502
nil_threads_queue::cnt
volatile cnt_t cnt
Threads Queue counter.
Definition: ch.h:496
chThdSleep
void chThdSleep(sysinterval_t timeout)
Suspends the invoking thread for the specified time.
Definition: ch.c:963
chThdResumeI
void chThdResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: ch.c:927
chSysTimerHandlerI
void chSysTimerHandlerI(void)
Time management handler.
Definition: ch.c:355
NIL_STATE_WTQUEUE
#define NIL_STATE_WTQUEUE
On queue or semaph.
Definition: ch.h:146
chSysLockFromISR
#define chSysLockFromISR()
Enters the kernel lock state from within an interrupt handler.
Definition: ch.h:1070
NIL_STATE_SUSPENDED
#define NIL_STATE_SUSPENDED
Thread suspended.
Definition: ch.h:144
MSG_TIMEOUT
#define MSG_TIMEOUT
Wake-up caused by a timeout condition.
Definition: ch.h:100
MEM_IS_ALIGNED
#define MEM_IS_ALIGNED(p, a)
Returns whatever a pointer or memory size is aligned.
Definition: ch.h:692
nil_os_instance::dbg_panic_msg
const char *volatile dbg_panic_msg
Panic message.
Definition: ch.h:598
stkalign_t
port_stkalign_t stkalign_t
Definition: ch.h:388
__dbg_check_unlock
void __dbg_check_unlock(void)
Guard code for chSysUnlock().
Definition: ch.c:169
TIME_INFINITE
#define TIME_INFINITE
Infinite time specification for all functions with a timeout specification.
Definition: ch.h:122
nil_thread::tp
thread_t * tp
Pointer to thread.
Definition: ch.h:525
MSG_OK
#define MSG_OK
OK wakeup message.
Definition: ch.h:99
chThdCreate
thread_t * chThdCreate(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: ch.c:807
rtcnt_t
port_rtcnt_t rtcnt_t
Definition: ch.h:386
nil_os_instance::nexttime
systime_t nexttime
Time of the next scheduled tick event.
Definition: ch.h:578
__dbg_check_enter_isr
void __dbg_check_enter_isr(void)
Guard code for CH_IRQ_PROLOGUE().
Definition: ch.c:208
nil_thread::semp
semaphore_t * semp
Pointer to semaphore.
Definition: ch.h:527
NIL_STATE_FINAL
#define NIL_STATE_FINAL
Thread terminated.
Definition: ch.h:153
chSysPolledDelayX
void chSysPolledDelayX(rtcnt_t cycles)
Polled delay.
Definition: ch.c:564
nil_thread_descriptor::arg
void * arg
Thread function argument.
Definition: ch.h:508
nil_ready_all
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
NIL_STATE_WTEXIT
#define NIL_STATE_WTEXIT
Waiting a thread.
Definition: ch.h:145
chSysRestoreStatusX
void chSysRestoreStatusX(syssts_t sts)
Restores the specified execution status and leaves a critical zone.
Definition: ch.c:515
tprio_t
uint32_t tprio_t
Definition: ch.h:392
__dbg_check_leave_isr
void __dbg_check_leave_isr(void)
Guard code for CH_IRQ_EPILOGUE().
Definition: ch.c:223
chSysInit
void chSysInit(void)
Initializes the kernel.
Definition: ch.c:275
chDbgCheck
#define chDbgCheck(c)
Function parameters check.
Definition: ch.h:1321
nil_os_instance::isr_cnt
cnt_t isr_cnt
ISR nesting level.
Definition: ch.h:584
chDbgCheckClassI
void chDbgCheckClassI(void)
I-class functions context check.
Definition: ch.c:241
chSysIsCounterWithinX
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end)
Realtime window test.
Definition: ch.c:547
chThdSleepUntil
void chThdSleepUntil(systime_t abstime)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: ch.c:978
systime_t
uint32_t systime_t
Type of system time.
Definition: ch.h:428
nil_os_instance
System data structure.
Definition: ch.h:553
nil
os_instance_t nil
System data structures.
Definition: ch.c:41
chThdDoDequeueNextI
void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object.
Definition: ch.c:1032
chSysUnconditionalLock
void chSysUnconditionalLock(void)
Unconditionally enters the kernel lock state.
Definition: ch.c:458
chThdSleepUntilS
#define chThdSleepUntilS(abstime)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: ch.h:1215
nil_thread::wabase
stkalign_t * wabase
Thread stack boundary.
Definition: ch.h:542
nil_thread_descriptor::funcp
tfunc_t funcp
Thread function.
Definition: ch.h:507
nil_thread_descriptor::wbase
stkalign_t * wbase
Thread working area base.
Definition: ch.h:504
chSchIsRescRequiredI
#define chSchIsRescRequiredI()
Evaluates if a reschedule is required.
Definition: ch.h:1125
CH_CFG_IDLE_LEAVE_HOOK
#define CH_CFG_IDLE_LEAVE_HOOK()
Idle thread leave hook.
Definition: chconf.h:462
THD_IDLE_BASE
#define THD_IDLE_BASE
Definition: ch.h:370
chSysSuspend
#define chSysSuspend()
Raises the system interrupt priority mask to system level.
Definition: ch.h:1019
chThdExit
void chThdExit(msg_t msg)
Terminates the current thread.
Definition: ch.c:835
chThdDequeueNextI
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:1054
nil_thread::trp
thread_reference_t * trp
Pointer to thread reference.
Definition: ch.h:523
chSysHalt
void chSysHalt(const char *reason)
Halts the system.
Definition: ch.c:330
nil_thread_descriptor::wend
stkalign_t * wend
Thread working area end.
Definition: ch.h:505
cnt_t
int32_t cnt_t
Definition: ch.h:397
tstate_t
uint8_t tstate_t
Definition: ch.h:391
nil_threads_queue
Structure representing a queue of threads.
Definition: ch.h:495
nil_thread::epmask
eventmask_t epmask
Pending events mask.
Definition: ch.h:536
CH_CFG_MAX_THREADS
#define CH_CFG_MAX_THREADS
Maximum number of user threads in the application.
Definition: chconf.h:51
nil_os_instance::lasttime
systime_t lasttime
System time of the last tick event.
Definition: ch.h:574
__dbg_check_lock_from_isr
void __dbg_check_lock_from_isr(void)
Guard code for chSysLockFromIsr().
Definition: ch.c:182
nil_thread
Structure representing a thread.
Definition: ch.h:514
chThdEnqueueTimeoutS
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread on a threads queue object.
Definition: ch.c:1005
chThdSleepS
#define chThdSleepS(timeout)
Suspends the invoking thread for the specified time.
Definition: ch.h:1204
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: ch.h:1347
chSchDoPreemption
void chSchDoPreemption(void)
Switches to the first thread on the runnable queue.
Definition: ch.c:622
CH_CFG_THREAD_EXIT_HOOK
#define CH_CFG_THREAD_EXIT_HOOK(tp)
Threads finalization hook.
Definition: chconf.h:445
CH_CFG_SYSTEM_HALT_HOOK
#define CH_CFG_SYSTEM_HALT_HOOK(reason)
System halt hook.
Definition: chconf.h:468
nil_os_instance::systime
volatile systime_t systime
System time.
Definition: ch.h:568
CH_CFG_IDLE_ENTER_HOOK
#define CH_CFG_IDLE_ENTER_HOOK()
Idle thread enter hook.
Definition: chconf.h:453
NIL_STATE_READY
#define NIL_STATE_READY
Thread ready or executing.
Definition: ch.h:141
__dbg_check_disable
void __dbg_check_disable(void)
Guard code for chSysDisable().
Definition: ch.c:120
msg_t
int32_t msg_t
Definition: ch.h:393
chThdCreateI
thread_t * chThdCreateI(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: ch.c:761
nil_thread::state
tstate_t state
Thread state.
Definition: ch.h:516
nil_os_instance::next
thread_t * next
Pointer to the next thread to be executed.
Definition: ch.h:563
chThdDequeueAllI
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the threads queue object.
Definition: ch.c:1072
nil_os_instance::current
thread_t * current
Pointer to the running thread.
Definition: ch.h:557
eventmask_t
uint32_t eventmask_t
Definition: ch.h:395
nil_thread::timeout
volatile sysinterval_t timeout
Timeout counter, zero if disabled.
Definition: ch.h:533
__dbg_check_enable
void __dbg_check_enable(void)
Guard code for chSysEnable().
Definition: ch.c:144
CH_CFG_SYSTEM_INIT_HOOK
#define CH_CFG_SYSTEM_INIT_HOOK()
System initialization hook.
Definition: chconf.h:424
TIME_IMMEDIATE
#define TIME_IMMEDIATE
Zero time specification for some functions with a timeout specification.
Definition: ch.h:116
chTimeAddX
#define chTimeAddX(systime, interval)
Adds an interval to a system time returning a system time.
Definition: ch.h:1295
sysinterval_t
uint32_t sysinterval_t
Type of time interval.
Definition: ch.h:434
nil_thread_descriptor::prio
tprio_t prio
Thread priority slot.
Definition: ch.h:506
ch.h
Nil RTOS main header file.
chThdSuspendTimeoutS
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition: ch.c:904
chSchRescheduleS
void chSchRescheduleS(void)
Reschedules if needed.
Definition: ch.c:637
chThdWait
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:873
nil_find_thread
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
__oslib_init
static void __oslib_init(void)
Initialization of all library modules.
Definition: chlib.h:249
CH_CFG_ST_TIMEDELTA
#define CH_CFG_ST_TIMEDELTA
Time delta constant for the tick-less mode.
Definition: chconf.h:97
syssts_t
port_syssts_t syssts_t
Definition: ch.h:387
nil_os_instance::lock_cnt
cnt_t lock_cnt
Lock nesting level.
Definition: ch.h:588
chTimeIsInRangeX
bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end)
Checks if the specified time is within the specified time range.
Definition: ch.c:743
chSysGetRealtimeCounterX
#define chSysGetRealtimeCounterX()
Returns the current value of the system real time counter.
Definition: ch.h:992
chSysUnlock
#define chSysUnlock()
Leaves the kernel lock state.
Definition: ch.h:1053
CH_CFG_THREAD_EXT_INIT_HOOK
#define CH_CFG_THREAD_EXT_INIT_HOOK(tr)
Threads initialization hook.
Definition: chconf.h:437
__dbg_check_suspend
void __dbg_check_suspend(void)
Guard code for chSysSuspend().
Definition: ch.c:132
chThdResumeS
#define chThdResumeS(trp, msg)
Wakes up a thread waiting on a thread reference object.
Definition: ch.h:1154
nil_os_instance::threads
thread_t threads[CH_CFG_MAX_THREADS+1]
Thread structures for all the defined threads.
Definition: ch.h:603
chSysLock
#define chSysLock()
Enters the kernel lock state.
Definition: ch.h:1043