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