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