ChibiOS/RT  5.1.0
chsys.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 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 
106 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
107  ch.dbg.isr_cnt = (cnt_t)0;
108  ch.dbg.lock_cnt = (cnt_t)0;
109 #endif
110 #if CH_CFG_USE_TM == TRUE
111  _tm_init();
112 #endif
113 #if CH_CFG_USE_MEMCORE == TRUE
114  _core_init();
115 #endif
116 #if CH_CFG_USE_HEAP == TRUE
117  _heap_init();
118 #endif
119 #if CH_CFG_USE_FACTORY == TRUE
120  _factory_init();
121 #endif
122 #if CH_DBG_STATISTICS == TRUE
123  _stats_init();
124 #endif
125 
126 #if CH_CFG_NO_IDLE_THREAD == FALSE
127  /* Now this instructions flow becomes the main thread.*/
128 #if CH_CFG_USE_REGISTRY == TRUE
129  currp = _thread_init(&ch.mainthread, (const char *)&ch_debug, NORMALPRIO);
130 #else
132 #endif
133 #else
134  /* Now this instructions flow becomes the idle thread.*/
135  currp = _thread_init(&ch.mainthread, "idle", IDLEPRIO);
136 #endif
137 
138 #if CH_DBG_ENABLE_STACK_CHECK == TRUE
139  {
140  /* Setting up the base address of the static main thread stack, the
141  symbol must be provided externally.*/
142  extern stkalign_t __main_thread_stack_base__;
143  currp->wabase = &__main_thread_stack_base__;
144  }
145 #elif CH_CFG_USE_DYNAMIC == TRUE
146  currp->wabase = NULL;
147 #endif
148 
149  /* Setting up the caller as current thread.*/
150  currp->state = CH_STATE_CURRENT;
151 
152  /* Port layer initialization last because it depend on some of the
153  initializations performed before.*/
154  port_init();
155 
156 #if CH_DBG_STATISTICS == TRUE
157  /* Starting measurement for this thread.*/
158  chTMStartMeasurementX(&currp->stats);
159 #endif
160 
161  /* Initialization hook.*/
163 
164  /* It is alive now.*/
165  chSysEnable();
166 
167 #if CH_CFG_NO_IDLE_THREAD == FALSE
168  {
169  static const thread_descriptor_t idle_descriptor = {
170  "idle",
171  THD_WORKING_AREA_BASE(ch_idle_thread_wa),
172  THD_WORKING_AREA_END(ch_idle_thread_wa),
173  IDLEPRIO,
174  _idle_thread,
175  NULL
176  };
177 
178  /* This thread has the lowest priority in the system, its role is just to
179  serve interrupts in its context while keeping the lowest energy saving
180  mode compatible with the system status.*/
181  (void) chThdCreate(&idle_descriptor);
182  }
183 #endif
184 }
185 
186 /**
187  * @brief Halts the system.
188  * @details This function is invoked by the operating system when an
189  * unrecoverable error is detected, for example because a programming
190  * error in the application code that triggers an assertion while
191  * in debug mode.
192  * @note Can be invoked from any system state.
193  *
194  * @param[in] reason pointer to an error string
195  *
196  * @special
197  */
198 void chSysHalt(const char *reason) {
199 
200  port_disable();
201 
202  /* Logging the event.*/
203  _trace_halt(reason);
204 
205  /* Pointing to the passed message.*/
206  ch.dbg.panic_msg = reason;
207 
208  /* Halt hook code, usually empty.*/
209  CH_CFG_SYSTEM_HALT_HOOK(reason);
210 
211  /* Harmless infinite loop.*/
212  while (true) {
213  }
214 }
215 
216 /**
217  * @brief System integrity check.
218  * @details Performs an integrity check of the important ChibiOS/RT data
219  * structures.
220  * @note The appropriate action in case of failure is to halt the system
221  * before releasing the critical zone.
222  * @note If the system is corrupted then one possible outcome of this
223  * function is an exception caused by @p NULL or corrupted pointers
224  * in list elements. Exception vectors must be monitored as well.
225  * @note This function is not used internally, it is up to the
226  * application to define if and where to perform system
227  * checking.
228  * @note Performing all tests at once can be a slow operation and can
229  * degrade the system response time. It is suggested to execute
230  * one test at time and release the critical zone in between tests.
231  *
232  * @param[in] testmask Each bit in this mask is associated to a test to be
233  * performed.
234  * @return The test result.
235  * @retval false The test succeeded.
236  * @retval true Test failed.
237  *
238  * @iclass
239  */
240 bool chSysIntegrityCheckI(unsigned testmask) {
241  cnt_t n;
242 
244 
245  /* Ready List integrity check.*/
246  if ((testmask & CH_INTEGRITY_RLIST) != 0U) {
247  thread_t *tp;
248 
249  /* Scanning the ready list forward.*/
250  n = (cnt_t)0;
251  tp = ch.rlist.queue.next;
252  while (tp != (thread_t *)&ch.rlist.queue) {
253  n++;
254  tp = tp->queue.next;
255  }
256 
257  /* Scanning the ready list backward.*/
258  tp = ch.rlist.queue.prev;
259  while (tp != (thread_t *)&ch.rlist.queue) {
260  n--;
261  tp = tp->queue.prev;
262  }
263 
264  /* The number of elements must match.*/
265  if (n != (cnt_t)0) {
266  return true;
267  }
268  }
269 
270  /* Timers list integrity check.*/
271  if ((testmask & CH_INTEGRITY_VTLIST) != 0U) {
272  virtual_timer_t * vtp;
273 
274  /* Scanning the timers list forward.*/
275  n = (cnt_t)0;
276  vtp = ch.vtlist.next;
277  while (vtp != (virtual_timer_t *)&ch.vtlist) {
278  n++;
279  vtp = vtp->next;
280  }
281 
282  /* Scanning the timers list backward.*/
283  vtp = ch.vtlist.prev;
284  while (vtp != (virtual_timer_t *)&ch.vtlist) {
285  n--;
286  vtp = vtp->prev;
287  }
288 
289  /* The number of elements must match.*/
290  if (n != (cnt_t)0) {
291  return true;
292  }
293  }
294 
295 #if CH_CFG_USE_REGISTRY == TRUE
296  if ((testmask & CH_INTEGRITY_REGISTRY) != 0U) {
297  thread_t *tp;
298 
299  /* Scanning the ready list forward.*/
300  n = (cnt_t)0;
301  tp = ch.rlist.newer;
302  while (tp != (thread_t *)&ch.rlist) {
303  n++;
304  tp = tp->newer;
305  }
306 
307  /* Scanning the ready list backward.*/
308  tp = ch.rlist.older;
309  while (tp != (thread_t *)&ch.rlist) {
310  n--;
311  tp = tp->older;
312  }
313 
314  /* The number of elements must match.*/
315  if (n != (cnt_t)0) {
316  return true;
317  }
318  }
319 #endif /* CH_CFG_USE_REGISTRY == TRUE */
320 
321 #if defined(PORT_INTEGRITY_CHECK)
322  if ((testmask & CH_INTEGRITY_PORT) != 0U) {
323  PORT_INTEGRITY_CHECK();
324  }
325 #endif
326 
327  return false;
328 }
329 
330 /**
331  * @brief Handles time ticks for round robin preemption and timer increments.
332  * @details Decrements the remaining time quantum of the running thread
333  * and preempts it when the quantum is used up. Increments system
334  * time and manages the timers.
335  * @note The frequency of the timer determines the system tick granularity
336  * and, together with the @p CH_CFG_TIME_QUANTUM macro, the round robin
337  * interval.
338  *
339  * @iclass
340  */
341 void chSysTimerHandlerI(void) {
342 
344 
345 #if CH_CFG_TIME_QUANTUM > 0
346  /* Running thread has not used up quantum yet? */
347  if (currp->ticks > (tslices_t)0) {
348  /* Decrement remaining quantum.*/
349  currp->ticks--;
350  }
351 #endif
352 #if CH_DBG_THREADS_PROFILING == TRUE
353  currp->time++;
354 #endif
355  chVTDoTickI();
357 }
358 
359 /**
360  * @brief Returns the execution status and enters a critical zone.
361  * @details This functions enters into a critical zone and can be called
362  * from any context. Because its flexibility it is less efficient
363  * than @p chSysLock() which is preferable when the calling context
364  * is known.
365  * @post The system is in a critical zone.
366  *
367  * @return The previous system status, the encoding of this
368  * status word is architecture-dependent and opaque.
369  *
370  * @xclass
371  */
372 syssts_t chSysGetStatusAndLockX(void) {
373 
374  syssts_t sts = port_get_irq_status();
375  if (port_irq_enabled(sts)) {
376  if (port_is_isr_context()) {
378  }
379  else {
380  chSysLock();
381  }
382  }
383  return sts;
384 }
385 
386 /**
387  * @brief Restores the specified execution status and leaves a critical zone.
388  * @note A call to @p chSchRescheduleS() is automatically performed
389  * if exiting the critical zone and if not in ISR context.
390  *
391  * @param[in] sts the system status to be restored.
392  *
393  * @xclass
394  */
395 void chSysRestoreStatusX(syssts_t sts) {
396 
397  if (port_irq_enabled(sts)) {
398  if (port_is_isr_context()) {
400  }
401  else {
403  chSysUnlock();
404  }
405  }
406 }
407 
408 #if (PORT_SUPPORTS_RT == TRUE) || defined(__DOXYGEN__)
409 /**
410  * @brief Realtime window test.
411  * @details This function verifies if the current realtime counter value
412  * lies within the specified range or not. The test takes care
413  * of the realtime counter wrapping to zero on overflow.
414  * @note When start==end then the function returns always true because the
415  * whole time range is specified.
416  * @note This function is only available if the port layer supports the
417  * option @p PORT_SUPPORTS_RT.
418  *
419  * @param[in] cnt the counter value to be tested
420  * @param[in] start the start of the time window (inclusive)
421  * @param[in] end the end of the time window (non inclusive)
422  * @retval true current time within the specified time window.
423  * @retval false current time not within the specified time window.
424  *
425  * @xclass
426  */
427 bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end) {
428 
429  return (bool)((cnt - start) < (end - start));
430 }
431 
432 /**
433  * @brief Polled delay.
434  * @note The real delay is always few cycles in excess of the specified
435  * value.
436  * @note This function is only available if the port layer supports the
437  * option @p PORT_SUPPORTS_RT.
438  *
439  * @param[in] cycles number of cycles
440  *
441  * @xclass
442  */
443 void chSysPolledDelayX(rtcnt_t cycles) {
444  rtcnt_t start = chSysGetRealtimeCounterX();
445  rtcnt_t end = start + cycles;
446 
447  while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
448  }
449 }
450 #endif /* PORT_SUPPORTS_RT == TRUE */
451 
452 /** @} */
void _scheduler_init(void)
Scheduler initialization.
Definition: chschd.c:65
#define chSysGetRealtimeCounterX()
Returns the current value of the system real time counter.
Definition: chsys.h:253
cnt_t lock_cnt
Lock nesting level.
Definition: chschd.h:396
#define CH_CFG_SYSTEM_TICK_HOOK()
System tick event hook.
Definition: chconf.h:666
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:353
#define CH_CFG_SYSTEM_INIT_HOOK()
System initialization hook.
Definition: chconf.h:581
system_debug_t dbg
System debug.
Definition: chschd.h:423
void chSysPolledDelayX(rtcnt_t cycles)
Polled delay.
Definition: chsys.c:443
Type of a thread descriptor.
Definition: chthreads.h:57
#define IDLEPRIO
Idle priority.
Definition: chschd.h:55
void _factory_init(void)
Initializes the objects factory.
Definition: chfactory.c:245
static void _idle_thread(void *p)
This function implements the idle thread infinite loop.
Definition: chsys.c:72
#define NORMALPRIO
Normal priority.
Definition: chschd.h:57
virtual_timer_t * prev
Previous timer in the list.
Definition: chschd.h:326
#define CH_STATE_CURRENT
Currently running.
Definition: chschd.h:68
#define currp
Current thread pointer access macro.
Definition: chschd.h:459
void _tm_init(void)
Initializes the time measurement unit.
Definition: chtm.c:77
void _core_init(void)
Low level memory manager initialization.
Definition: chmemcore.c:81
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:365
thread_t mainthread
Main thread descriptor.
Definition: chschd.h:427
void chSysHalt(const char *reason)
Halts the system.
Definition: chsys.c:198
virtual_timers_list_t vtlist
Virtual timers delta list header.
Definition: chschd.h:419
#define THD_WORKING_AREA_END(s)
End of a working area casted to the correct type.
Definition: chthreads.h:149
#define THD_WORKING_AREA_BASE(s)
Base of a working area casted to the correct type.
Definition: chthreads.h:142
void _trace_halt(const char *reason)
Inserts in the circular debug trace buffer an halt record.
Definition: chtrace.c:162
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:235
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:456
void chSysTimerHandlerI(void)
Handles time ticks for round robin preemption and timer increments.
Definition: chsys.c:341
thread_t * next
Next in the list/queue.
Definition: chschd.h:143
bool chSysIntegrityCheckI(unsigned testmask)
System integrity check.
Definition: chsys.c:240
void _trace_init(void)
Trace circular buffer subsystem initialization.
Definition: chtrace.c:85
void _vt_init(void)
Virtual Timers initialization.
Definition: chvt.c:61
THD_WORKING_AREA(ch_idle_thread_wa, PORT_IDLE_THREAD_STACK_SIZE)
Idle thread working area.
ready_list_t rlist
Ready list header.
Definition: chschd.h:415
void chSysInit(void)
ChibiOS/RT initialization.
Definition: chsys.c:100
ch_system_t ch
System data structures.
Definition: chschd.c:42
static void chSysUnlockFromISR(void)
Leaves the kernel lock state from within an interrupt handler.
Definition: chsys.h:413
NOINLINE void chTMStartMeasurementX(time_measurement_t *tmp)
Starts a measurement.
Definition: chtm.c:114
thread_t * prev
Previous in the queue.
Definition: chschd.h:144
void _stats_init(void)
Initializes the statistics module.
Definition: chstats.c:62
syssts_t chSysGetStatusAndLockX(void)
Returns the execution status and enters a critical zone.
Definition: chsys.c:372
static void chSysLockFromISR(void)
Enters the kernel lock state from within an interrupt handler.
Definition: chsys.h:393
void chSysRestoreStatusX(syssts_t sts)
Restores the specified execution status and leaves a critical zone.
Definition: chsys.c:395
Virtual Timer descriptor structure.
Definition: chschd.h:324
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end)
Realtime window test.
Definition: chsys.c:427
thread_t * older
Older registry element.
Definition: chschd.h:159
cnt_t isr_cnt
ISR nesting level.
Definition: chschd.h:392
virtual_timer_t * next
Next timer in the delta list.
Definition: chschd.h:341
static void chSysEnable(void)
Lowers the system interrupt priority mask to user level.
Definition: chsys.h:342
thread_t * _thread_init(thread_t *tp, const char *name, tprio_t prio)
Initializes a thread structure.
Definition: chthreads.c:88
virtual_timer_t * next
Next timer in the list.
Definition: chschd.h:325
thread_t * chThdCreate(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:280
static void chVTDoTickI(void)
Virtual timers ticker.
Definition: chvt.h:370
const char *volatile panic_msg
Pointer to the panic message.
Definition: chschd.h:387
#define CH_CFG_IDLE_LOOP_HOOK()
Idle Loop hook.
Definition: chconf.h:657
virtual_timer_t * prev
Last timer in the delta list.
Definition: chschd.h:343
#define CH_CFG_SYSTEM_HALT_HOOK(reason)
System halt hook.
Definition: chconf.h:675
ChibiOS/RT main include file.
threads_queue_t queue
Threads queue header.
Definition: chschd.h:154
thread_t * newer
Newer registry element.
Definition: chschd.h:158
void _heap_init(void)
Initializes the default heap.
Definition: chheap.c:107
Structure representing a thread.
Definition: chschd.h:153