ChibiOS/NIL  3.2.2
ch.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 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; either version 3 of the License, or
9  (at your option) any later version.
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  * @brief Retrieves the highest priority thread in the specified state and
53  * associated to the specified object.
54  * @note The search is unbounded, the thread is assumed to exist.
55  *
56  * @param[in] state thread state
57  * @param[in] p object pointer
58  * @return Pointer to the thread.
59  */
60 static thread_t *nil_find_thread(tstate_t state, void * p) {
61  thread_t *tp = nil.threads;
62 
63  while (true) {
64  /* Is this thread matching?*/
65  if ((tp->state == state) && (tp->u1.p == p)) {
66  return tp;
67  }
68  tp++;
69 
71  "pointer out of range");
72  }
73 }
74 
75 /**
76  * @brief Puts in ready state all thread matching the specified status and
77  * associated object.
78  *
79  * @param[in] p object pointer
80  * @param[in] cnt number of threads to be readied as a negative number,
81  * non negative numbers are ignored
82  * @param[in] msg the wakeup message
83  * @return Always zero.
84  */
85 static cnt_t nil_ready_all(void * p, cnt_t cnt, msg_t msg) {
86  thread_t *tp = nil.threads;;
87 
88  while (cnt < (cnt_t)0) {
89 
91  "pointer out of range");
92 
93  /* Is this thread waiting on this queue?*/
94  if ((tp->state == NIL_STATE_WTQUEUE) && (tp->u1.p == p)) {
95  cnt++;
96  (void) chSchReadyI(tp, msg);
97  }
98  tp++;
99  }
100 
101  return cnt;
102 }
103 
104 /*===========================================================================*/
105 /* Module interrupt handlers. */
106 /*===========================================================================*/
107 
108 /*===========================================================================*/
109 /* Module exported functions. */
110 /*===========================================================================*/
111 
112 #if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__)
113 /**
114  * @brief Guard code for @p chSysDisable().
115  *
116  * @notapi
117  */
118 void _dbg_check_disable(void) {
119 
120  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
121  chSysHalt("SV#1");
122  }
123 }
124 
125 /**
126  * @brief Guard code for @p chSysSuspend().
127  *
128  * @notapi
129  */
130 void _dbg_check_suspend(void) {
131 
132  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
133  chSysHalt("SV#2");
134  }
135 }
136 
137 /**
138  * @brief Guard code for @p chSysEnable().
139  *
140  * @notapi
141  */
142 void _dbg_check_enable(void) {
143 
144  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
145  chSysHalt("SV#3");
146  }
147 }
148 
149 /**
150  * @brief Guard code for @p chSysLock().
151  *
152  * @notapi
153  */
154 void _dbg_check_lock(void) {
155 
156  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
157  chSysHalt("SV#4");
158  }
159  _dbg_enter_lock();
160 }
161 
162 /**
163  * @brief Guard code for @p chSysUnlock().
164  *
165  * @notapi
166  */
167 void _dbg_check_unlock(void) {
168 
169  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
170  chSysHalt("SV#5");
171  }
172  _dbg_leave_lock();
173 }
174 
175 /**
176  * @brief Guard code for @p chSysLockFromIsr().
177  *
178  * @notapi
179  */
181 
182  if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
183  chSysHalt("SV#6");
184  }
185  _dbg_enter_lock();
186 }
187 
188 /**
189  * @brief Guard code for @p chSysUnlockFromIsr().
190  *
191  * @notapi
192  */
194 
195  if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
196  chSysHalt("SV#7");
197  }
198  _dbg_leave_lock();
199 }
200 
201 /**
202  * @brief Guard code for @p CH_IRQ_PROLOGUE().
203  *
204  * @notapi
205  */
207 
208  port_lock_from_isr();
209  if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
210  chSysHalt("SV#8");
211  }
212  nil.isr_cnt++;
213  port_unlock_from_isr();
214 }
215 
216 /**
217  * @brief Guard code for @p CH_IRQ_EPILOGUE().
218  *
219  * @notapi
220  */
222 
223  port_lock_from_isr();
224  if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
225  chSysHalt("SV#9");
226  }
227  nil.isr_cnt--;
228  port_unlock_from_isr();
229 }
230 
231 /**
232  * @brief I-class functions context check.
233  * @details Verifies that the system is in an appropriate state for invoking
234  * an I-class API function. A panic is generated if the state is
235  * not compatible.
236  *
237  * @api
238  */
239 void chDbgCheckClassI(void) {
240 
241  if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
242  chSysHalt("SV#10");
243  }
244 }
245 
246 /**
247  * @brief S-class functions context check.
248  * @details Verifies that the system is in an appropriate state for invoking
249  * an S-class API function. A panic is generated if the state is
250  * not compatible.
251  *
252  * @api
253  */
254 void chDbgCheckClassS(void) {
255 
256  if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
257  chSysHalt("SV#11");
258  }
259 }
260 #endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */
261 
262 /**
263  * @brief Initializes the kernel.
264  * @details Initializes the kernel structures, the current instructions flow
265  * becomes the idle thread upon return. The idle thread must not
266  * invoke any kernel primitive able to change state to not runnable.
267  * @note This function assumes that the @p nil global variable has been
268  * zeroed by the runtime environment. If this is not the case then
269  * make sure to clear it before calling this function.
270  *
271  * @special
272  */
273 void chSysInit(void) {
274  thread_t *tp;
275  const thread_config_t *tcp;
276 
277 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
278  nil.isr_cnt = (cnt_t)0;
279  nil.lock_cnt = (cnt_t)0;
280 #endif
281 
282  /* System initialization hook.*/
284 
285  /* Iterates through the list of defined threads.*/
286  tp = &nil.threads[0];
287  tcp = nil_thd_configs;
288  while (tp < &nil.threads[CH_CFG_NUM_THREADS]) {
289 #if CH_DBG_ENABLE_STACK_CHECK
290  tp->wabase = (stkalign_t *)tcp->wbase;
291 #endif
292 
293  /* Port dependent thread initialization.*/
294  PORT_SETUP_CONTEXT(tp, tcp->wbase, tcp->wend, tcp->funcp, tcp->arg);
295 
296  /* Initialization hook.*/
298 
299  tp++;
300  tcp++;
301  }
302 
303 #if CH_DBG_ENABLE_STACK_CHECK
304  /* The idle thread is a special case because its stack is set up by the
305  runtime environment.*/
306  tp->wabase = THD_IDLE_BASE;
307 #endif
308 
309  /* Interrupts partially enabled. It is equivalent to entering the
310  kernel critical zone.*/
311  chSysSuspend();
312 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
313  nil.lock_cnt = (cnt_t)1;
314 #endif
315 
316  /* Memory core initialization, if enabled.*/
317 #if CH_CFG_USE_MEMCORE == TRUE
318  _core_init();
319 #endif
320 
321  /* Heap initialization, if enabled.*/
322 #if CH_CFG_USE_HEAP == TRUE
323  _heap_init();
324 #endif
325 
326  /* Factory initialization, if enabled.*/
327 #if CH_CFG_USE_FACTORY == TRUE
328  _factory_init();
329 #endif
330 
331  /* Port layer initialization last because it depend on some of the
332  initializations performed before.*/
333  port_init();
334 
335  /* Runs the highest priority thread, the current one becomes the idle
336  thread.*/
337  nil.current = nil.next = nil.threads;
338  port_switch(nil.current, tp);
339  chSysUnlock();
340 }
341 
342 /**
343  * @brief Halts the system.
344  * @details This function is invoked by the operating system when an
345  * unrecoverable error is detected, for example because a programming
346  * error in the application code that triggers an assertion while
347  * in debug mode.
348  * @note Can be invoked from any system state.
349  *
350  * @param[in] reason pointer to an error string
351  *
352  * @special
353  */
354 void chSysHalt(const char *reason) {
355 
356  port_disable();
357 
358 #if NIL_DBG_ENABLED
359  nil.dbg_panic_msg = reason;
360 #else
361  (void)reason;
362 #endif
363 
364  /* Halt hook code, usually empty.*/
365  CH_CFG_SYSTEM_HALT_HOOK(reason);
366 
367  /* Harmless infinite loop.*/
368  while (true) {
369  }
370 }
371 
372 /**
373  * @brief Time management handler.
374  * @note This handler has to be invoked by a periodic ISR in order to
375  * reschedule the waiting threads.
376  *
377  * @iclass
378  */
379 void chSysTimerHandlerI(void) {
380 
382 
383 #if CH_CFG_ST_TIMEDELTA == 0
384  thread_t *tp = &nil.threads[0];
385  nil.systime++;
386  do {
387  /* Is the thread in a wait state with timeout?.*/
388  if (tp->timeout > (sysinterval_t)0) {
389 
390  chDbgAssert(!NIL_THD_IS_READY(tp), "is ready");
391 
392  /* Did the timer reach zero?*/
393  if (--tp->timeout == (sysinterval_t)0) {
394  /* Timeout on queues/semaphores requires a special handling because
395  the counter must be incremented.*/
396  /*lint -save -e9013 [15.7] There is no else because it is not needed.*/
397  if (NIL_THD_IS_WTQUEUE(tp)) {
398  tp->u1.semp->cnt++;
399  }
400  else if (NIL_THD_IS_SUSP(tp)) {
401  *tp->u1.trp = NULL;
402  }
403  /*lint -restore*/
404  (void) chSchReadyI(tp, MSG_TIMEOUT);
405  }
406  }
407  /* Lock released in order to give a preemption chance on those
408  architectures supporting IRQ preemption.*/
410  tp++;
412  } while (tp < &nil.threads[CH_CFG_NUM_THREADS]);
413 #else
414  thread_t *tp = &nil.threads[0];
415  sysinterval_t next = (sysinterval_t)0;
416 
417  chDbgAssert(nil.nexttime == port_timer_get_alarm(), "time mismatch");
418 
419  do {
420  sysinterval_t timeout = tp->timeout;
421 
422  /* Is the thread in a wait state with timeout?.*/
423  if (timeout > (sysinterval_t)0) {
424 
425  chDbgAssert(!NIL_THD_IS_READY(tp), "is ready");
426  chDbgAssert(timeout >= chTimeDiffX(nil.lasttime, nil.nexttime),
427  "skipped one");
428 
429  /* The volatile field is updated once, here.*/
430  timeout -= chTimeDiffX(nil.lasttime, nil.nexttime);
431  tp->timeout = timeout;
432 
433  if (timeout == (sysinterval_t)0) {
434  /* Timeout on thread queues requires a special handling because the
435  counter must be incremented.*/
436  if (NIL_THD_IS_WTQUEUE(tp)) {
437  tp->u1.tqp->cnt++;
438  }
439  else {
440  if (NIL_THD_IS_SUSP(tp)) {
441  *tp->u1.trp = NULL;
442  }
443  }
444  (void) chSchReadyI(tp, MSG_TIMEOUT);
445  }
446  else {
447  if (timeout <= (sysinterval_t)(next - (sysinterval_t)1)) {
448  next = timeout;
449  }
450  }
451  }
452 
453  /* Lock released in order to give a preemption chance on those
454  architectures supporting IRQ preemption.*/
456  tp++;
458  } while (tp < &nil.threads[CH_CFG_NUM_THREADS]);
459 
460  nil.lasttime = nil.nexttime;
461  if (next > (sysinterval_t)0) {
462  nil.nexttime = chTimeAddX(nil.nexttime, next);
463  port_timer_set_alarm(nil.nexttime);
464  }
465  else {
466  /* No tick event needed.*/
467  port_timer_stop_alarm();
468  }
469 #endif
470 }
471 
472 /**
473  * @brief Unconditionally enters the kernel lock state.
474  * @note Can be called without previous knowledge of the current lock state.
475  * The final state is "s-locked".
476  *
477  * @special
478  */
480 
481  if (port_irq_enabled(port_get_irq_status())) {
482  chSysLock();
483  }
484 }
485 
486 /**
487  * @brief Unconditionally leaves the kernel lock state.
488  * @note Can be called without previous knowledge of the current lock state.
489  * The final state is "normal".
490  *
491  * @special
492  */
494 
495  if (!port_irq_enabled(port_get_irq_status())) {
496  chSysUnlock();
497  }
498 }
499 
500 /**
501  * @brief Returns the execution status and enters a critical zone.
502  * @details This functions enters into a critical zone and can be called
503  * from any context. Because its flexibility it is less efficient
504  * than @p chSysLock() which is preferable when the calling context
505  * is known.
506  * @post The system is in a critical zone.
507  *
508  * @return The previous system status, the encoding of this
509  * status word is architecture-dependent and opaque.
510  *
511  * @xclass
512  */
513 syssts_t chSysGetStatusAndLockX(void) {
514 
515  syssts_t sts = port_get_irq_status();
516  if (port_irq_enabled(sts)) {
517  if (port_is_isr_context()) {
519  }
520  else {
521  chSysLock();
522  }
523  }
524  return sts;
525 }
526 
527 /**
528  * @brief Restores the specified execution status and leaves a critical zone.
529  * @note A call to @p chSchRescheduleS() is automatically performed
530  * if exiting the critical zone and if not in ISR context.
531  *
532  * @param[in] sts the system status to be restored.
533  *
534  * @xclass
535  */
536 void chSysRestoreStatusX(syssts_t sts) {
537 
538  if (port_irq_enabled(sts)) {
539  if (port_is_isr_context()) {
541  }
542  else {
544  chSysUnlock();
545  }
546  }
547 }
548 
549 #if (PORT_SUPPORTS_RT == TRUE) || defined(__DOXYGEN__)
550 /**
551  * @brief Realtime window test.
552  * @details This function verifies if the current realtime counter value
553  * lies within the specified range or not. The test takes care
554  * of the realtime counter wrapping to zero on overflow.
555  * @note When start==end then the function returns always true because the
556  * whole time range is specified.
557  * @note This function is only available if the port layer supports the
558  * option @p PORT_SUPPORTS_RT.
559  *
560  * @param[in] cnt the counter value to be tested
561  * @param[in] start the start of the time window (inclusive)
562  * @param[in] end the end of the time window (non inclusive)
563  * @retval true current time within the specified time window.
564  * @retval false current time not within the specified time window.
565  *
566  * @xclass
567  */
568 bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end) {
569 
570  return (bool)(((rtcnt_t)cnt - (rtcnt_t)start) <=
571  ((rtcnt_t)end - (rtcnt_t)start - (rtcnt_t)1));
572 }
573 
574 /**
575  * @brief Polled delay.
576  * @note The real delay is always few cycles in excess of the specified
577  * value.
578  * @note This function is only available if the port layer supports the
579  * option @p PORT_SUPPORTS_RT.
580  *
581  * @param[in] cycles number of cycles
582  *
583  * @xclass
584  */
585 void chSysPolledDelayX(rtcnt_t cycles) {
586  rtcnt_t start = chSysGetRealtimeCounterX();
587  rtcnt_t end = start + cycles;
588 
589  while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
590  }
591 }
592 #endif /* PORT_SUPPORTS_RT == TRUE */
593 
594 /**
595  * @brief Makes the specified thread ready for execution.
596  *
597  * @param[in] tp pointer to the @p thread_t object
598  * @param[in] msg the wakeup message
599  *
600  * @return The same reference passed as parameter.
601  */
602 thread_t *chSchReadyI(thread_t *tp, msg_t msg) {
603 
605  chDbgCheck((tp >= nil.threads) && (tp < &nil.threads[CH_CFG_NUM_THREADS]));
606  chDbgAssert(!NIL_THD_IS_READY(tp), "already ready");
607  chDbgAssert(nil.next <= nil.current, "priority ordering");
608 
609  tp->u1.msg = msg;
610  tp->state = NIL_STATE_READY;
611  tp->timeout = (sysinterval_t)0;
612  if (tp < nil.next) {
613  nil.next = tp;
614  }
615  return tp;
616 }
617 
618 /**
619  * @brief Evaluates if preemption is required.
620  * @details The decision is taken by comparing the relative priorities and
621  * depending on the state of the round robin timeout counter.
622  * @note Not a user function, it is meant to be invoked by the scheduler
623  * itself or from within the port layer.
624  *
625  * @retval true if there is a thread that must go in running state
626  * immediately.
627  * @retval false if preemption is not required.
628  *
629  * @special
630  */
632 
633  return chSchIsRescRequiredI();
634 }
635 
636 /**
637  * @brief Switches to the first thread on the runnable queue.
638  * @note Not a user function, it is meant to be invoked by the scheduler
639  * itself or from within the port layer.
640  *
641  * @special
642  */
643 void chSchDoReschedule(void) {
644  thread_t *otp = nil.current;
645 
646  nil.current = nil.next;
647  if (otp == &nil.threads[CH_CFG_NUM_THREADS]) {
649  }
650  port_switch(nil.next, otp);
651 }
652 
653 /**
654  * @brief Reschedules if needed.
655  *
656  * @sclass
657  */
658 void chSchRescheduleS(void) {
659 
661 
662  if (chSchIsRescRequiredI()) {
664  }
665 }
666 
667 /**
668  * @brief Puts the current thread to sleep into the specified state with
669  * timeout specification.
670  * @details The thread goes into a sleeping state, if it is not awakened
671  * explicitly within the specified system time then it is forcibly
672  * awakened with a @p NIL_MSG_TMO low level message.
673  *
674  * @param[in] newstate the new thread state or a semaphore pointer
675  * @param[in] timeout the number of ticks before the operation timeouts.
676  * the following special values are allowed:
677  * - @a TIME_INFINITE no timeout.
678  * .
679  * @return The wakeup message.
680  * @retval NIL_MSG_TMO if a timeout occurred.
681  *
682  * @sclass
683  */
684 msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout) {
685  thread_t *ntp, *otp = nil.current;
686 
688 
690  "idle cannot sleep");
691 
692  /* Storing the wait object for the current thread.*/
693  otp->state = newstate;
694 
695 #if CH_CFG_ST_TIMEDELTA > 0
696  if (timeout != TIME_INFINITE) {
697  systime_t abstime;
698 
699  /* TIMEDELTA makes sure to have enough time to reprogram the timer
700  before the free-running timer counter reaches the selected timeout.*/
701  if (timeout < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {
702  timeout = (sysinterval_t)CH_CFG_ST_TIMEDELTA;
703  }
704 
705  /* Absolute time of the timeout event.*/
706  abstime = chTimeAddX(chVTGetSystemTimeX(), timeout);
707 
708  if (nil.lasttime == nil.nexttime) {
709  /* Special case, first thread asking for a timeout.*/
710  port_timer_start_alarm(abstime);
711  nil.nexttime = abstime;
712  }
713  else {
714  /* Special case, there are already other threads with a timeout
715  activated, evaluating the order.*/
716  if (chTimeIsInRangeX(abstime, nil.lasttime, nil.nexttime)) {
717  port_timer_set_alarm(abstime);
718  nil.nexttime = abstime;
719  }
720  }
721 
722  /* Timeout settings.*/
723  otp->timeout = abstime - nil.lasttime;
724  }
725 #else
726 
727  /* Timeout settings.*/
728  otp->timeout = timeout;
729 #endif
730 
731  /* Scanning the whole threads array.*/
732  ntp = nil.threads;
733  while (true) {
734  /* Is this thread ready to execute?*/
735  if (NIL_THD_IS_READY(ntp)) {
736  nil.current = nil.next = ntp;
737  if (ntp == &nil.threads[CH_CFG_NUM_THREADS]) {
739  }
740  port_switch(ntp, otp);
741  return nil.current->u1.msg;
742  }
743 
744  /* Points to the next thread in lowering priority order.*/
745  ntp++;
747  "pointer out of range");
748  }
749 }
750 
751 /**
752  * @brief Sends the current thread sleeping and sets a reference variable.
753  * @note This function must reschedule, it can only be called from thread
754  * context.
755  *
756  * @param[in] trp a pointer to a thread reference object
757  * @param[in] timeout the number of ticks before the operation timeouts,
758  * the following special values are allowed:
759  * - @a TIME_INFINITE no timeout.
760  * - @a TIME_IMMEDIATE immediate timeout.
761  * .
762  * @return The wake up message.
763  *
764  * @sclass
765  */
767 
768  chDbgAssert(*trp == NULL, "not NULL");
769 
770  if (TIME_IMMEDIATE == timeout) {
771  return MSG_TIMEOUT;
772  }
773 
774  *trp = nil.current;
775  nil.current->u1.trp = trp;
776  return chSchGoSleepTimeoutS(NIL_STATE_SUSP, timeout);
777 }
778 
779 /**
780  * @brief Wakes up a thread waiting on a thread reference object.
781  * @note This function must not reschedule because it can be called from
782  * ISR context.
783  *
784  * @param[in] trp a pointer to a thread reference object
785  * @param[in] msg the message code
786  *
787  * @iclass
788  */
789 void chThdResumeI(thread_reference_t *trp, msg_t msg) {
790 
791  if (*trp != NULL) {
792  thread_reference_t tr = *trp;
793 
794  chDbgAssert(NIL_THD_IS_SUSP(tr), "not suspended");
795 
796  *trp = NULL;
797  (void) chSchReadyI(tr, msg);
798  }
799 }
800 
801 /**
802  * @brief Wakes up a thread waiting on a thread reference object.
803  * @note This function must reschedule, it can only be called from thread
804  * context.
805  *
806  * @param[in] trp a pointer to a thread reference object
807  * @param[in] msg the message code
808  *
809  * @api
810  */
811 void chThdResume(thread_reference_t *trp, msg_t msg) {
812 
813  chSysLock();
814  chThdResumeI(trp, msg);
816  chSysUnlock();
817 }
818 
819 /**
820  * @brief Suspends the invoking thread for the specified time.
821  *
822  * @param[in] timeout the delay in system ticks
823  *
824  * @api
825  */
826 void chThdSleep(sysinterval_t timeout) {
827 
828  chSysLock();
829  chThdSleepS(timeout);
830  chSysUnlock();
831 }
832 
833 /**
834  * @brief Suspends the invoking thread until the system time arrives to the
835  * specified value.
836  *
837  * @param[in] abstime absolute system time
838  *
839  * @api
840  */
841 void chThdSleepUntil(systime_t abstime) {
842 
843  chSysLock();
844  chThdSleepUntilS(abstime);
845  chSysUnlock();
846 }
847 
848 /**
849  * @brief Enqueues the caller thread on a threads queue object.
850  * @details The caller thread is enqueued and put to sleep until it is
851  * dequeued or the specified timeouts expires.
852  *
853  * @param[in] tqp pointer to the threads queue object
854  * @param[in] timeout the timeout in system ticks, the special values are
855  * handled as follow:
856  * - @a TIME_INFINITE no timeout.
857  * - @a TIME_IMMEDIATE immediate timeout.
858  * .
859  * @return The message from @p osalQueueWakeupOneI() or
860  * @p osalQueueWakeupAllI() functions.
861  * @retval MSG_TIMEOUT if the thread has not been dequeued within the
862  * specified timeout or if the function has been
863  * invoked with @p TIME_IMMEDIATE as timeout
864  * specification.
865  *
866  * @sclass
867  */
869 
871  chDbgCheck(tqp != NULL);
872 
873  chDbgAssert(tqp->cnt <= (cnt_t)0, "invalid counter");
874 
875  if (TIME_IMMEDIATE == timeout) {
876  return MSG_TIMEOUT;
877  }
878 
879  tqp->cnt--;
880  nil.current->u1.tqp = tqp;
881  return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout);
882 }
883 
884 /**
885  * @brief Dequeues and wakes up one thread from the threads queue object.
886  * @details Dequeues one thread from the queue without checking if the queue
887  * is empty.
888  * @pre The queue must contain at least an object.
889  *
890  * @param[in] tqp pointer to the threads queue object
891  * @param[in] msg the message code
892  *
893  * @iclass
894  */
895 void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg) {
896  thread_t *tp;
897 
898  chDbgAssert(tqp->cnt < (cnt_t)0, "empty queue");
899 
900  tqp->cnt++;
901  tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)tqp);
902  (void) chSchReadyI(tp, msg);
903 }
904 
905 /**
906  * @brief Dequeues and wakes up one thread from the threads queue object,
907  * if any.
908  *
909  * @param[in] tqp pointer to the threads queue object
910  * @param[in] msg the message code
911  *
912  * @iclass
913  */
914 void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg) {
915 
917  chDbgCheck(tqp != NULL);
918 
919  if (tqp->cnt < (cnt_t)0) {
920  chThdDoDequeueNextI(tqp, msg);
921  }
922 }
923 
924 /**
925  * @brief Dequeues and wakes up all threads from the threads queue object.
926  *
927  * @param[in] tqp pointer to the threads queue object
928  * @param[in] msg the message code
929  *
930  * @iclass
931  */
932 void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg) {
933 
935  chDbgCheck(tqp != NULL);
936 
937  tqp->cnt = nil_ready_all((void *)tqp, tqp->cnt, msg);
938 }
939 
940 #if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
941 /**
942  * @brief Performs a wait operation on a semaphore with timeout specification.
943  *
944  * @param[in] sp pointer to a @p semaphore_t structure
945  * @param[in] timeout the number of ticks before the operation timeouts,
946  * the following special values are allowed:
947  * - @a TIME_INFINITE no timeout.
948  * - @a TIME_IMMEDIATE immediate timeout.
949  * .
950  * @return A message specifying how the invoking thread has been
951  * released from the semaphore.
952  * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the
953  * semaphore has been signaled.
954  * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset().
955  * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within
956  * the specified timeout.
957  *
958  * @api
959  */
961  msg_t msg;
962 
963  chSysLock();
964  msg = chSemWaitTimeoutS(sp, timeout);
965  chSysUnlock();
966 
967  return msg;
968 }
969 
970 /**
971  * @brief Performs a wait operation on a semaphore with timeout specification.
972  *
973  * @param[in] sp pointer to a @p semaphore_t structure
974  * @param[in] timeout the number of ticks before the operation timeouts,
975  * the following special values are allowed:
976  * - @a TIME_INFINITE no timeout.
977  * - @a TIME_IMMEDIATE immediate timeout.
978  * .
979  * @return A message specifying how the invoking thread has been
980  * released from the semaphore.
981  * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the
982  * semaphore has been signaled.
983  * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset().
984  * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within
985  * the specified timeout.
986  *
987  * @sclass
988  */
990 
992  chDbgCheck(sp != NULL);
993 
994  /* Note, the semaphore counter is a volatile variable so accesses are
995  manually optimized.*/
996  cnt_t cnt = sp->cnt;
997  if (cnt <= (cnt_t)0) {
998  if (TIME_IMMEDIATE == timeout) {
999 
1000  return MSG_TIMEOUT;
1001  }
1002  sp->cnt = cnt - (cnt_t)1;
1003  nil.current->u1.semp = sp;
1004 
1005  return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout);
1006  }
1007  sp->cnt = cnt - (cnt_t)1;
1008 
1009  return MSG_OK;
1010 }
1011 
1012 /**
1013  * @brief Performs a signal operation on a semaphore.
1014  *
1015  * @param[in] sp pointer to a @p semaphore_t structure
1016  *
1017  * @api
1018  */
1020 
1021  chSysLock();
1022  chSemSignalI(sp);
1023  chSchRescheduleS();
1024  chSysUnlock();
1025 }
1026 
1027 /**
1028  * @brief Performs a signal operation on a semaphore.
1029  * @post This function does not reschedule so a call to a rescheduling
1030  * function must be performed before unlocking the kernel. Note that
1031  * interrupt handlers always reschedule on exit so an explicit
1032  * reschedule must not be performed in ISRs.
1033  *
1034  * @param[in] sp pointer to a @p semaphore_t structure
1035  *
1036  * @iclass
1037  */
1039 
1040  chDbgCheckClassI();
1041  chDbgCheck(sp != NULL);
1042 
1043  if (++sp->cnt <= (cnt_t)0) {
1044  thread_t *tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)sp);
1045  (void) chSchReadyI(tp, MSG_OK);
1046  }
1047 }
1048 
1049 /**
1050  * @brief Performs a reset operation on the semaphore.
1051  * @post After invoking this function all the threads waiting on the
1052  * semaphore, if any, are released and the semaphore counter is set
1053  * to the specified, non negative, value.
1054  *
1055  * @param[in] sp pointer to a @p semaphore_t structure
1056  * @param[in] n the new value of the semaphore counter. The value must
1057  * be non-negative.
1058  *
1059  * @api
1060  */
1061 void chSemReset(semaphore_t *sp, cnt_t n) {
1062 
1063  chSysLock();
1064  chSemResetI(sp, n);
1065  chSchRescheduleS();
1066  chSysUnlock();
1067 }
1068 
1069 /**
1070  * @brief Performs a reset operation on the semaphore.
1071  * @post After invoking this function all the threads waiting on the
1072  * semaphore, if any, are released and the semaphore counter is set
1073  * to the specified, non negative, value.
1074  * @post This function does not reschedule so a call to a rescheduling
1075  * function must be performed before unlocking the kernel. Note that
1076  * interrupt handlers always reschedule on exit so an explicit
1077  * reschedule must not be performed in ISRs.
1078  *
1079  * @param[in] sp pointer to a @p semaphore_t structure
1080  * @param[in] n the new value of the semaphore counter. The value must
1081  * be non-negative.
1082  *
1083  * @iclass
1084  */
1085 void chSemResetI(semaphore_t *sp, cnt_t n) {
1086  cnt_t cnt;
1087 
1088  chDbgCheckClassI();
1089  chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
1090 
1091  cnt = sp->cnt;
1092  sp->cnt = n;
1093 
1094  /* Does nothing for cnt >= 0, calling anyway.*/
1095  (void) nil_ready_all((void *)sp, cnt, MSG_RESET);
1096 }
1097 #endif /* CH_CFG_USE_SEMAPHORES == TRUE */
1098 
1099 #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
1100 /**
1101  * @brief Adds a set of event flags directly to the specified @p thread_t.
1102  *
1103  * @param[in] tp the thread to be signaled
1104  * @param[in] mask the event flags set to be ORed
1105  *
1106  * @api
1107  */
1108 void chEvtSignal(thread_t *tp, eventmask_t mask) {
1109 
1110  chSysLock();
1111  chEvtSignalI(tp, mask);
1112  chSchRescheduleS();
1113  chSysUnlock();
1114 }
1115 
1116 /**
1117  * @brief Adds a set of event flags directly to the specified @p thread_t.
1118  * @post This function does not reschedule so a call to a rescheduling
1119  * function must be performed before unlocking the kernel. Note that
1120  * interrupt handlers always reschedule on exit so an explicit
1121  * reschedule must not be performed in ISRs.
1122  *
1123  * @param[in] tp the thread to be signaled
1124  * @param[in] mask the event flags set to be ORed
1125  *
1126  * @iclass
1127  */
1128 void chEvtSignalI(thread_t *tp, eventmask_t mask) {
1129 
1130  chDbgCheckClassI();
1131  chDbgCheck(tp != NULL);
1132 
1133  tp->epmask |= mask;
1134  if (NIL_THD_IS_WTOREVT(tp) &&
1135  ((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) {
1136  (void) chSchReadyI(tp, MSG_OK);
1137  }
1138 }
1139 
1140 /**
1141  * @brief Waits for any of the specified events.
1142  * @details The function waits for any event among those specified in
1143  * @p mask to become pending then the events are cleared and
1144  * returned.
1145  *
1146  * @param[in] mask mask of the event flags that the function should wait
1147  * for, @p ALL_EVENTS enables all the events
1148  * @param[in] timeout the number of ticks before the operation timeouts,
1149  * the following special values are allowed:
1150  * - @a TIME_INFINITE no timeout.
1151  * - @a TIME_IMMEDIATE immediate timeout.
1152  * .
1153  * @return The mask of the served and cleared events.
1154  * @retval 0 if the operation has timed out.
1155  *
1156  * @api
1157  */
1158 eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout) {
1159  thread_t *ctp = nil.current;
1160  eventmask_t m;
1161 
1162  chSysLock();
1163  if ((m = (ctp->epmask & mask)) == (eventmask_t)0) {
1164  if (TIME_IMMEDIATE == timeout) {
1165  chSysUnlock();
1166 
1167  return (eventmask_t)0;
1168  }
1169  ctp->u1.ewmask = mask;
1170  if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) {
1171  chSysUnlock();
1172 
1173  return (eventmask_t)0;
1174  }
1175  m = ctp->epmask & mask;
1176  }
1177  ctp->epmask &= ~m;
1178  chSysUnlock();
1179 
1180  return m;
1181 }
1182 #endif /* CH_CFG_USE_EVENTS == TRUE */
1183 
1184 /** @} */
tfunc_t funcp
Thread function.
Definition: ch.h:614
stkalign_t * wbase
Thread working area base.
Definition: ch.h:611
Structure representing a thread.
Definition: ch.h:626
void chSchRescheduleS(void)
Reschedules if needed.
Definition: ch.c:658
#define CH_CFG_IDLE_ENTER_HOOK()
Idle thread enter hook.
Definition: chconf.h:320
#define chSysLock()
Enters the kernel lock state.
Definition: ch.h:1151
systime_t nexttime
Time of the next scheduled tick event.
Definition: ch.h:690
eventmask_t ewmask
Enabled events mask.
Definition: ch.h:640
#define NIL_STATE_READY
Thread ready or executing.
Definition: ch.h:142
void chEvtSignal(thread_t *tp, eventmask_t mask)
Adds a set of event flags directly to the specified thread_t.
Definition: ch.c:1108
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:684
void chSysHalt(const char *reason)
Halts the system.
Definition: ch.c:354
volatile cnt_t cnt
Threads Queue counter.
Definition: ch.h:580
thread_reference_t * trp
Pointer to thread reference.
Definition: ch.h:634
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the threads queue object.
Definition: ch.c:932
void chSemSignal(semaphore_t *sp)
Performs a signal operation on a semaphore.
Definition: ch.c:1019
#define THD_IDLE_BASE
Definition: ch.h:531
tstate_t state
Thread state.
Definition: ch.h:628
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition: ch.c:766
void chThdResume(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: ch.c:811
void chEvtSignalI(thread_t *tp, eventmask_t mask)
Adds a set of event flags directly to the specified thread_t.
Definition: ch.c:1128
eventmask_t epmask
Pending events mask.
Definition: ch.h:646
#define chTimeAddX(systime, interval)
Adds an interval to a system time returning a system time.
Definition: ch.h:1408
#define CH_CFG_SYSTEM_INIT_HOOK()
System initialization hook.
Definition: chconf.h:296
void _core_init(void)
Low level memory manager initialization.
Definition: chmemcore.c:81
cnt_t lock_cnt
Lock nesting level.
Definition: ch.h:700
static 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:85
volatile systime_t systime
System time.
Definition: ch.h:680
#define chTimeDiffX(start, end)
Subtracts two system times returning an interval.
Definition: ch.h:1420
#define TIME_IMMEDIATE
Zero time specification for some functions with a timeout specification.
Definition: ch.h:119
#define TIME_INFINITE
Infinite time specification for all functions with a timeout specification.
Definition: ch.h:125
void chThdResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: ch.c:789
stkalign_t * wabase
Thread stack boundary.
Definition: ch.h:649
#define chSysGetRealtimeCounterX()
Returns the current value of the system real time counter.
Definition: ch.h:1100
void chSemSignalI(semaphore_t *sp)
Performs a signal operation on a semaphore.
Definition: ch.c:1038
#define NIL_STATE_WTOREVT
Waiting for events.
Definition: ch.h:148
void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object.
Definition: ch.c:895
Structure representing a thread static configuration.
Definition: ch.h:610
#define chSchIsRescRequiredI()
Evaluates if a reschedule is required.
Definition: ch.h:1210
void chSysRestoreStatusX(syssts_t sts)
Restores the specified execution status and leaves a critical zone.
Definition: ch.c:536
eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout)
Waits for any of the specified events.
Definition: ch.c:1158
thread_t threads[CH_CFG_NUM_THREADS+1]
Thread structures for all the defined threads.
Definition: ch.h:715
void chDbgCheckClassS(void)
S-class functions context check.
Definition: ch.c:254
void chSemReset(semaphore_t *sp, cnt_t n)
Performs a reset operation on the semaphore.
Definition: ch.c:1061
#define CH_CFG_SYSTEM_HALT_HOOK(reason)
System halt hook.
Definition: chconf.h:336
void chSemResetI(semaphore_t *sp, cnt_t n)
Performs a reset operation on the semaphore.
Definition: ch.c:1085
#define CH_CFG_ST_TIMEDELTA
Time delta constant for the tick-less mode.
Definition: chconf.h:79
void _dbg_check_suspend(void)
Guard code for chSysSuspend().
Definition: ch.c:130
void chThdSleepUntil(systime_t abstime)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: ch.c:841
void chDbgCheckClassI(void)
I-class functions context check.
Definition: ch.c:239
#define MSG_TIMEOUT
Wake-up caused by a timeout condition.
Definition: ch.h:101
#define chSysUnlock()
Leaves the kernel lock state.
Definition: ch.h:1161
#define chThdSleepS(timeout)
Suspends the invoking thread for the specified time.
Definition: ch.h:1264
thread_t * current
Pointer to the running thread.
Definition: ch.h:669
thread_t * next
Pointer to the next thread to be executed.
Definition: ch.h:675
#define chSysSuspend()
Raises the system interrupt priority mask to system level.
Definition: ch.h:1127
stkalign_t * wend
Thread working area end.
Definition: ch.h:612
#define chDbgAssert(c, r)
Condition assertion.
Definition: ch.h:1477
uint32_t sysinterval_t
Type of time interval.
Definition: ch.h:553
#define chSysUnlockFromISR()
Leaves the kernel lock state from within an interrupt handler.
Definition: ch.h:1196
void chThdSleep(sysinterval_t timeout)
Suspends the invoking thread for the specified time.
Definition: ch.c:826
void chSysUnconditionalLock(void)
Unconditionally enters the kernel lock state.
Definition: ch.c:479
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread on a threads queue object.
Definition: ch.c:868
#define CH_CFG_IDLE_LEAVE_HOOK()
Idle thread leave hook.
Definition: chconf.h:329
#define CH_CFG_THREAD_EXT_INIT_HOOK(tr)
Threads initialization hook.
Definition: chconf.h:310
void chSysPolledDelayX(rtcnt_t cycles)
Polled delay.
Definition: ch.c:585
void _dbg_check_lock(void)
Guard code for chSysLock().
Definition: ch.c:154
#define NIL_STATE_WTQUEUE
On queue or semaph.
Definition: ch.h:147
msg_t msg
Wake-up message.
Definition: ch.h:632
#define CH_CFG_NUM_THREADS
Number of user threads in the application.
Definition: chconf.h:46
void chSysInit(void)
Initializes the kernel.
Definition: ch.c:273
#define NIL_STATE_SUSP
Thread suspended.
Definition: ch.h:146
uint32_t systime_t
Type of system time.
Definition: ch.h:547
#define MSG_OK
OK wakeup message.
Definition: ch.h:100
#define chSysLockFromISR()
Enters the kernel lock state from within an interrupt handler.
Definition: ch.h:1178
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:914
cnt_t isr_cnt
ISR nesting level.
Definition: ch.h:696
#define MSG_RESET
Wake-up caused by a reset condition.
Definition: ch.h:104
bool chSchIsPreemptionRequired(void)
Evaluates if preemption is required.
Definition: ch.c:631
volatile sysinterval_t timeout
Timeout counter, zero if disabled.
Definition: ch.h:643
void chSysTimerHandlerI(void)
Time management handler.
Definition: ch.c:379
void _dbg_check_lock_from_isr(void)
Guard code for chSysLockFromIsr().
Definition: ch.c:180
const char *volatile dbg_panic_msg
Panic message.
Definition: ch.h:710
void _dbg_check_unlock_from_isr(void)
Guard code for chSysUnlockFromIsr().
Definition: ch.c:193
void _dbg_check_enable(void)
Guard code for chSysEnable().
Definition: ch.c:142
#define chDbgCheck(c)
Function parameters check.
Definition: ch.h:1451
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end)
Realtime window test.
Definition: ch.c:568
#define chThdSleepUntilS(abstime)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: ch.h:1275
static 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:60
void chSysUnconditionalUnlock(void)
Unconditionally leaves the kernel lock state.
Definition: ch.c:493
Structure representing a queue of threads.
Definition: ch.h:579
thread_t * chSchReadyI(thread_t *tp, msg_t msg)
Makes the specified thread ready for execution.
Definition: ch.c:602
void _dbg_check_leave_isr(void)
Guard code for CH_IRQ_EPILOGUE().
Definition: ch.c:221
void * p
Generic pointer.
Definition: ch.h:633
threads_queue_t * tqp
Pointer to thread queue.
Definition: ch.h:635
syssts_t chSysGetStatusAndLockX(void)
Returns the execution status and enters a critical zone.
Definition: ch.c:513
void * arg
Thread function argument.
Definition: ch.h:615
void _factory_init(void)
Initializes the objects factory.
Definition: chfactory.c:245
void _dbg_check_enter_isr(void)
Guard code for CH_IRQ_PROLOGUE().
Definition: ch.c:206
Nil RTOS main header file.
void chSchDoReschedule(void)
Switches to the first thread on the runnable queue.
Definition: ch.c:643
void _heap_init(void)
Initializes the default heap.
Definition: chmemheaps.c:107
msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout)
Performs a wait operation on a semaphore with timeout specification.
Definition: ch.c:960
semaphore_t * semp
Pointer to semaphore.
Definition: ch.h:637
nil_system_t nil
System data structures.
Definition: ch.c:41
System data structure.
Definition: ch.h:665
systime_t lasttime
System time of the last tick event.
Definition: ch.h:686
msg_t chSemWaitTimeoutS(semaphore_t *sp, sysinterval_t timeout)
Performs a wait operation on a semaphore with timeout specification.
Definition: ch.c:989
void _dbg_check_unlock(void)
Guard code for chSysUnlock().
Definition: ch.c:167
void _dbg_check_disable(void)
Guard code for chSysDisable().
Definition: ch.c:118
#define chTimeIsInRangeX(time, start, end)
Checks if the specified time is within the specified time range.
Definition: ch.h:1436
#define chVTGetSystemTimeX()
Current system time.
Definition: ch.h:1383