ChibiOS/RT  6.1.4
chsys.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
3  2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
4 
5  This file is part of ChibiOS.
6 
7  ChibiOS is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation version 3 of the License.
10 
11  ChibiOS is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /**
21  * @file rt/src/chsys.c
22  * @brief System related code.
23  *
24  * @addtogroup system
25  * @details System related APIs and services:
26  * - Initialization.
27  * - Locks.
28  * - Interrupt Handling.
29  * - Power Management.
30  * - Abnormal Termination.
31  * - Realtime counter.
32  * .
33  * @{
34  */
35 
36 #include "ch.h"
37 
38 /*===========================================================================*/
39 /* Module exported variables. */
40 /*===========================================================================*/
41 
42 #if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__)
43 /**
44  * @brief Idle thread working area.
45  */
46 THD_WORKING_AREA(ch_idle_thread_wa, PORT_IDLE_THREAD_STACK_SIZE);
47 #endif
48 
49 /*===========================================================================*/
50 /* Module local types. */
51 /*===========================================================================*/
52 
53 /*===========================================================================*/
54 /* Module local variables. */
55 /*===========================================================================*/
56 
57 /*===========================================================================*/
58 /* Module local functions. */
59 /*===========================================================================*/
60 
61 #if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__)
62 /**
63  * @brief This function implements the idle thread infinite loop.
64  * @details The function puts the processor in the lowest power mode capable
65  * to serve interrupts.<br>
66  * The priority is internally set to the minimum system value so
67  * that this thread is executed only if there are no other ready
68  * threads in the system.
69  *
70  * @param[in] p the thread parameter, unused in this scenario
71  */
72 static void _idle_thread(void *p) {
73 
74  (void)p;
75 
76  while (true) {
77  /*lint -save -e522 [2.2] Apparently no side effects because it contains
78  an asm instruction.*/
79  port_wait_for_interrupt();
80  /*lint -restore*/
82  }
83 }
84 #endif /* CH_CFG_NO_IDLE_THREAD == FALSE */
85 
86 /*===========================================================================*/
87 /* Module exported functions. */
88 /*===========================================================================*/
89 
90 /**
91  * @brief ChibiOS/RT initialization.
92  * @details After executing this function the current instructions stream
93  * becomes the main thread.
94  * @pre Interrupts must disabled before invoking this function.
95  * @post The main thread is created with priority @p NORMALPRIO and
96  * interrupts are enabled.
97  *
98  * @special
99  */
100 void chSysInit(void) {
101 
102  _scheduler_init();
103  _vt_init();
104  _trace_init();
105  _oslib_init();
106 
107 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
108  ch.dbg.isr_cnt = (cnt_t)0;
109  ch.dbg.lock_cnt = (cnt_t)0;
110 #endif
111 #if CH_CFG_USE_TM == TRUE
112  _tm_init();
113 #endif
114 #if CH_DBG_STATISTICS == TRUE
115  _stats_init();
116 #endif
117 
118 #if CH_CFG_NO_IDLE_THREAD == FALSE
119  /* Now this instructions flow becomes the main thread.*/
120 #if CH_CFG_USE_REGISTRY == TRUE
121  currp = _thread_init(&ch.mainthread, (const char *)&ch_debug, NORMALPRIO);
122 #else
124 #endif
125 #else
126  /* Now this instructions flow becomes the idle thread.*/
127  currp = _thread_init(&ch.mainthread, "idle", IDLEPRIO);
128 #endif
129 
130 #if CH_DBG_ENABLE_STACK_CHECK == TRUE
131  {
132  /* Setting up the base address of the static main thread stack, the
133  symbol must be provided externally.*/
134  extern stkalign_t __main_thread_stack_base__;
135  currp->wabase = &__main_thread_stack_base__;
136  }
137 #elif CH_CFG_USE_DYNAMIC == TRUE
138  currp->wabase = NULL;
139 #endif
140 
141  /* Setting up the caller as current thread.*/
142  currp->state = CH_STATE_CURRENT;
143 
144  /* Port layer initialization last because it depend on some of the
145  initializations performed before.*/
146  port_init();
147 
148 #if CH_DBG_STATISTICS == TRUE
149  /* Starting measurement for this thread.*/
150  chTMStartMeasurementX(&currp->stats);
151 #endif
152 
153  /* Initialization hook.*/
155 
156  /* It is alive now.*/
157  chSysEnable();
158 
159 #if CH_CFG_NO_IDLE_THREAD == FALSE
160  {
161  static const thread_descriptor_t idle_descriptor = {
162  "idle",
163  THD_WORKING_AREA_BASE(ch_idle_thread_wa),
164  THD_WORKING_AREA_END(ch_idle_thread_wa),
165  IDLEPRIO,
166  _idle_thread,
167  NULL
168  };
169 
170  /* This thread has the lowest priority in the system, its role is just to
171  serve interrupts in its context while keeping the lowest energy saving
172  mode compatible with the system status.*/
173  (void) chThdCreate(&idle_descriptor);
174  }
175 #endif
176 }
177 
178 /**
179  * @brief Halts the system.
180  * @details This function is invoked by the operating system when an
181  * unrecoverable error is detected, for example because a programming
182  * error in the application code that triggers an assertion while
183  * in debug mode.
184  * @note Can be invoked from any system state.
185  *
186  * @param[in] reason pointer to an error string
187  *
188  * @special
189  */
190 void chSysHalt(const char *reason) {
191 
192  port_disable();
193 
194  /* Logging the event.*/
195  _trace_halt(reason);
196 
197  /* Pointing to the passed message.*/
198  ch.dbg.panic_msg = reason;
199 
200  /* Halt hook code, usually empty.*/
201  CH_CFG_SYSTEM_HALT_HOOK(reason);
202 
203  /* Harmless infinite loop.*/
204  while (true) {
205  }
206 }
207 
208 /**
209  * @brief System integrity check.
210  * @details Performs an integrity check of the important ChibiOS/RT data
211  * structures.
212  * @note The appropriate action in case of failure is to halt the system
213  * before releasing the critical zone.
214  * @note If the system is corrupted then one possible outcome of this
215  * function is an exception caused by @p NULL or corrupted pointers
216  * in list elements. Exception vectors must be monitored as well.
217  * @note This function is not used internally, it is up to the
218  * application to define if and where to perform system
219  * checking.
220  * @note Performing all tests at once can be a slow operation and can
221  * degrade the system response time. It is suggested to execute
222  * one test at time and release the critical zone in between tests.
223  *
224  * @param[in] testmask Each bit in this mask is associated to a test to be
225  * performed.
226  * @return The test result.
227  * @retval false The test succeeded.
228  * @retval true Test failed.
229  *
230  * @iclass
231  */
232 bool chSysIntegrityCheckI(unsigned testmask) {
233  cnt_t n;
234 
236 
237  /* Ready List integrity check.*/
238  if ((testmask & CH_INTEGRITY_RLIST) != 0U) {
239  ch_priority_queue_t *pqp;
240 
241  /* Scanning the ready list forward.*/
242  n = (cnt_t)0;
243  pqp = ch.rlist.pqueue.next;
244  while (pqp != &ch.rlist.pqueue) {
245  n++;
246  pqp = pqp->next;
247  }
248 
249  /* Scanning the ready list backward.*/
250  pqp = ch.rlist.pqueue.prev;
251  while (pqp != &ch.rlist.pqueue) {
252  n--;
253  pqp = pqp->prev;
254  }
255 
256  /* The number of elements must match.*/
257  if (n != (cnt_t)0) {
258  return true;
259  }
260  }
261 
262  /* Timers list integrity check.*/
263  if ((testmask & CH_INTEGRITY_VTLIST) != 0U) {
264  delta_list_t *dlp;
265 
266  /* Scanning the timers list forward.*/
267  n = (cnt_t)0;
268  dlp = ch.vtlist.dlist.next;
269  while (dlp != &ch.vtlist.dlist) {
270  n++;
271  dlp = dlp->next;
272  }
273 
274  /* Scanning the timers list backward.*/
275  dlp = ch.vtlist.dlist.prev;
276  while (dlp != &ch.vtlist.dlist) {
277  n--;
278  dlp = dlp->prev;
279  }
280 
281  /* The number of elements must match.*/
282  if (n != (cnt_t)0) {
283  return true;
284  }
285  }
286 
287 #if CH_CFG_USE_REGISTRY == TRUE
288  if ((testmask & CH_INTEGRITY_REGISTRY) != 0U) {
289  thread_t *tp;
290 
291  /* Scanning the ready list forward.*/
292  n = (cnt_t)0;
293  tp = ch.rlist.newer;
294  while (tp != (thread_t *)&ch.rlist) {
295  n++;
296  tp = tp->newer;
297  }
298 
299  /* Scanning the ready list backward.*/
300  tp = ch.rlist.older;
301  while (tp != (thread_t *)&ch.rlist) {
302  n--;
303  tp = tp->older;
304  }
305 
306  /* The number of elements must match.*/
307  if (n != (cnt_t)0) {
308  return true;
309  }
310  }
311 #endif /* CH_CFG_USE_REGISTRY == TRUE */
312 
313 #if defined(PORT_INTEGRITY_CHECK)
314  if ((testmask & CH_INTEGRITY_PORT) != 0U) {
315  PORT_INTEGRITY_CHECK();
316  }
317 #endif
318 
319  return false;
320 }
321 
322 /**
323  * @brief Handles time ticks for round robin preemption and timer increments.
324  * @details Decrements the remaining time quantum of the running thread
325  * and preempts it when the quantum is used up. Increments system
326  * time and manages the timers.
327  * @note The frequency of the timer determines the system tick granularity
328  * and, together with the @p CH_CFG_TIME_QUANTUM macro, the round robin
329  * interval.
330  *
331  * @iclass
332  */
333 void chSysTimerHandlerI(void) {
334 
336 
337 #if CH_CFG_TIME_QUANTUM > 0
338  /* Running thread has not used up quantum yet? */
339  if (currp->ticks > (tslices_t)0) {
340  /* Decrement remaining quantum.*/
341  currp->ticks--;
342  }
343 #endif
344 #if CH_DBG_THREADS_PROFILING == TRUE
345  currp->time++;
346 #endif
347  chVTDoTickI();
349 }
350 
351 /**
352  * @brief Returns the execution status and enters a critical zone.
353  * @details This functions enters into a critical zone and can be called
354  * from any context. Because its flexibility it is less efficient
355  * than @p chSysLock() which is preferable when the calling context
356  * is known.
357  * @post The system is in a critical zone.
358  *
359  * @return The previous system status, the encoding of this
360  * status word is architecture-dependent and opaque.
361  *
362  * @xclass
363  */
364 syssts_t chSysGetStatusAndLockX(void) {
365 
366  syssts_t sts = port_get_irq_status();
367  if (port_irq_enabled(sts)) {
368  if (port_is_isr_context()) {
370  }
371  else {
372  chSysLock();
373  }
374  }
375  return sts;
376 }
377 
378 /**
379  * @brief Restores the specified execution status and leaves a critical zone.
380  * @note A call to @p chSchRescheduleS() is automatically performed
381  * if exiting the critical zone and if not in ISR context.
382  *
383  * @param[in] sts the system status to be restored.
384  *
385  * @xclass
386  */
387 void chSysRestoreStatusX(syssts_t sts) {
388 
389  if (port_irq_enabled(sts)) {
390  if (port_is_isr_context()) {
392  }
393  else {
395  chSysUnlock();
396  }
397  }
398 }
399 
400 #if (PORT_SUPPORTS_RT == TRUE) || defined(__DOXYGEN__)
401 /**
402  * @brief Realtime window test.
403  * @details This function verifies if the current realtime counter value
404  * lies within the specified range or not. The test takes care
405  * of the realtime counter wrapping to zero on overflow.
406  * @note When start==end then the function returns always false because a
407  * null time range is specified.
408  * @note This function is only available if the port layer supports the
409  * option @p PORT_SUPPORTS_RT.
410  *
411  * @param[in] cnt the counter value to be tested
412  * @param[in] start the start of the time window (inclusive)
413  * @param[in] end the end of the time window (non inclusive)
414  * @retval true current time within the specified time window.
415  * @retval false current time not within the specified time window.
416  *
417  * @xclass
418  */
419 bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end) {
420 
421  return (bool)(((rtcnt_t)cnt - (rtcnt_t)start) <
422  ((rtcnt_t)end - (rtcnt_t)start));
423 }
424 
425 /**
426  * @brief Polled delay.
427  * @note The real delay is always few cycles in excess of the specified
428  * value.
429  * @note This function is only available if the port layer supports the
430  * option @p PORT_SUPPORTS_RT.
431  *
432  * @param[in] cycles number of cycles
433  *
434  * @xclass
435  */
436 void chSysPolledDelayX(rtcnt_t cycles) {
437  rtcnt_t start = chSysGetRealtimeCounterX();
438  rtcnt_t end = start + cycles;
439 
440  while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
441  }
442 }
443 #endif /* PORT_SUPPORTS_RT == TRUE */
444 
445 /** @} */
IDLEPRIO
#define IDLEPRIO
Idle priority.
Definition: chschd.h:52
_scheduler_init
void _scheduler_init(void)
Scheduler initialization.
Definition: chschd.c:128
chVTDoTickI
void chVTDoTickI(void)
Virtual timers ticker.
Definition: chvt.c:584
chSysRestoreStatusX
void chSysRestoreStatusX(syssts_t sts)
Restores the specified execution status and leaves a critical zone.
Definition: chsys.c:387
chSysHalt
void chSysHalt(const char *reason)
Halts the system.
Definition: chsys.c:190
chSysIsCounterWithinX
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end)
Realtime window test.
Definition: chsys.c:419
chSysLock
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:355
currp
#define currp
Current thread pointer access macro.
Definition: chschd.h:462
ch_thread::newer
thread_t * newer
Newer registry element.
Definition: chschd.h:143
CH_CFG_SYSTEM_HALT_HOOK
#define CH_CFG_SYSTEM_HALT_HOOK(reason)
System halt hook.
Definition: chconf.h:735
chSysTimerHandlerI
void chSysTimerHandlerI(void)
Handles time ticks for round robin preemption and timer increments.
Definition: chsys.c:333
ch_system::vtlist
virtual_timers_list_t vtlist
Virtual timers delta list header.
Definition: chschd.h:422
chSysIntegrityCheckI
bool chSysIntegrityCheckI(unsigned testmask)
System integrity check.
Definition: chsys.c:232
_trace_init
void _trace_init(void)
Trace circular buffer subsystem initialization.
Definition: chtrace.c:85
chSysEnable
static void chSysEnable(void)
Lowers the system interrupt priority mask to user level.
Definition: chsys.h:344
CH_CFG_SYSTEM_TICK_HOOK
#define CH_CFG_SYSTEM_TICK_HOOK()
System tick event hook.
Definition: chconf.h:726
CH_CFG_SYSTEM_INIT_HOOK
#define CH_CFG_SYSTEM_INIT_HOOK()
System initialization hook.
Definition: chconf.h:641
chSysGetRealtimeCounterX
#define chSysGetRealtimeCounterX()
Returns the current value of the system real time counter.
Definition: chsys.h:255
ch_thread
Structure representing a thread.
Definition: chschd.h:134
chSysPolledDelayX
void chSysPolledDelayX(rtcnt_t cycles)
Polled delay.
Definition: chsys.c:436
CH_STATE_CURRENT
#define CH_STATE_CURRENT
Currently running.
Definition: chschd.h:64
ch_system_debug::isr_cnt
cnt_t isr_cnt
ISR nesting level.
Definition: chschd.h:395
_vt_init
void _vt_init(void)
Virtual Timers initialization.
Definition: chvt.c:406
THD_WORKING_AREA_BASE
#define THD_WORKING_AREA_BASE(s)
Base of a working area casted to the correct type.
Definition: chthreads.h:144
CH_CFG_IDLE_LOOP_HOOK
#define CH_CFG_IDLE_LOOP_HOOK()
Idle Loop hook.
Definition: chconf.h:717
ch_delta_list::prev
delta_list_t * prev
Previous timer in the list.
Definition: chschd.h:314
_tm_init
void _tm_init(void)
Initializes the time measurement unit.
Definition: chtm.c:84
THD_WORKING_AREA_END
#define THD_WORKING_AREA_END(s)
End of a working area casted to the correct type.
Definition: chthreads.h:151
ch_system::mainthread
thread_t mainthread
Main thread descriptor.
Definition: chschd.h:430
thread_descriptor_t
Type of a thread descriptor.
Definition: chthreads.h:57
chSysLockFromISR
static void chSysLockFromISR(void)
Enters the kernel lock state from within an interrupt handler.
Definition: chsys.h:395
ch_virtual_timers_list::dlist
delta_list_t dlist
Delta list header.
Definition: chschd.h:336
chSysGetStatusAndLockX
syssts_t chSysGetStatusAndLockX(void)
Returns the execution status and enters a critical zone.
Definition: chsys.c:364
chSchRescheduleS
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:339
ch_thread::older
thread_t * older
Older registry element.
Definition: chschd.h:144
_trace_halt
void _trace_halt(const char *reason)
Inserts in the circular debug trace buffer an halt record.
Definition: chtrace.c:162
chDbgCheckClassI
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:233
_thread_init
thread_t * _thread_init(thread_t *tp, const char *name, tprio_t prio)
Initializes a thread structure.
Definition: chthreads.c:88
ch_system_debug::panic_msg
const char *volatile panic_msg
Pointer to the panic message.
Definition: chschd.h:390
_oslib_init
static void _oslib_init(void)
Initialization of all library modules.
Definition: chlib.h:249
ch_system_debug::lock_cnt
cnt_t lock_cnt
Lock nesting level.
Definition: chschd.h:399
ch
ch_system_t ch
System data structures.
Definition: chschd.c:42
_idle_thread
static void _idle_thread(void *p)
This function implements the idle thread infinite loop.
Definition: chsys.c:72
ch_priority_queue::next
ch_priority_queue_t * next
Next in the list/queue.
Definition: chlists.h:86
chThdCreate
thread_t * chThdCreate(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:280
chSysInit
void chSysInit(void)
ChibiOS/RT initialization.
Definition: chsys.c:100
THD_WORKING_AREA
THD_WORKING_AREA(ch_idle_thread_wa, PORT_IDLE_THREAD_STACK_SIZE)
Idle thread working area.
ch.h
ChibiOS/RT main include file.
chSysUnlock
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:367
ch_priority_queue::prev
ch_priority_queue_t * prev
Previous in the queue.
Definition: chlists.h:87
ch_system::rlist
ready_list_t rlist
Ready list header.
Definition: chschd.h:418
ch_delta_list::next
delta_list_t * next
Next timer in the list.
Definition: chschd.h:313
_stats_init
void _stats_init(void)
Initializes the statistics module.
Definition: chstats.c:62
ch_priority_queue
Structure representing a generic priority-ordered bidirectional linked list header and element.
Definition: chlists.h:85
ch_delta_list
Virtual Timer delta list element and header structure.
Definition: chschd.h:312
chSysUnlockFromISR
static void chSysUnlockFromISR(void)
Leaves the kernel lock state from within an interrupt handler.
Definition: chsys.h:415
ch_system::dbg
system_debug_t dbg
System debug.
Definition: chschd.h:426
chTMStartMeasurementX
NOINLINE void chTMStartMeasurementX(time_measurement_t *tmp)
Starts a measurement.
Definition: chtm.c:126
NORMALPRIO
#define NORMALPRIO
Normal priority.
Definition: chschd.h:54