aboutsummaryrefslogtreecommitdiffstats
path: root/ChibiOS_16.1.5/doc/rt/src/concepts.dox
blob: 0c9c6528b35f535464c92212a118221de962c8e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
/*
    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.

    This file is part of ChibiOS.

    ChibiOS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @page concepts Kernel Concepts
 * @brief ChibiOS/RT Kernel Concepts
 * - @ref naming
 * - @ref api_suffixes
 * - @ref interrupt_classes
 * - @ref system_states
 * - @ref scheduling
 * - @ref thread_states
 * - @ref priority
 * - @ref warea
 * .
 * @section naming Naming Conventions
 * ChibiOS/RT APIs are all named following this convention:
 * @a ch\<group\>\<action\>\<suffix\>().
 * The possible groups are: @a Sys, @a Sch, @a Time, @a VT, @a Thd, @a Sem,
 * @a Mtx, @a Cond, @a Evt, @a Msg, @a Reg, @a SequentialStream, @a IO, @a IQ,
 * @a OQ, @a Dbg, @a Core, @a Heap, @a Pool.
 *
 * @section api_suffixes API Name Suffixes
 * The suffix can be one of the following:
 * - <b>None</b>, APIs without any suffix can be invoked only from the user
 *   code in the <b>Normal</b> state unless differently specified. See
 *   @ref system_states.
 * - @anchor I-Class <b>"I"</b>, I-Class APIs are invokable only from the
 *   <b>I-Locked</b> or <b>S-Locked</b> states. See @ref system_states.
 * - @anchor S-Class <b>"S"</b>, S-Class APIs are invokable only from the
 *   <b>S-Locked</b> state. See @ref system_states.
 * .
 * Examples: @p chThdCreateStatic(), @p chSemSignalI(), @p chIQGetTimeout().
 *
 * @section interrupt_classes Interrupt Classes
 * In ChibiOS/RT there are three logical interrupt classes:
 * - <b>Regular Interrupts</b>. Maskable interrupt sources that cannot
 *   preempt (small parts of) the kernel code and are thus able to invoke
 *   operating system APIs from within their handlers. The interrupt handlers
 *   belonging to this class must be written following some rules. See the
 *   system APIs group and the web article
 *   <a href="http://chibios.sourceforge.net/dokuwiki/doku.php?id=chibios:howtos:interrupts">
 *   How to write interrupt handlers</a>.
 * - <b>Fast Interrupts</b>. Maskable interrupt sources with the ability
 *   to preempt the kernel code and thus have a lower latency and are less
 *   subject to jitter, see the web article
 *   <a href="http://chibios.sourceforge.net/dokuwiki/doku.php?id=chibios:articles:jitter">
 *   Response Time and Jitter</a>.
 *   Such sources are not supported on all the architectures.<br>
 *   Fast interrupts are not allowed to invoke any operating system API from
 *   within their handlers. Fast interrupt sources may, however, pend a lower
 *   priority regular interrupt where access to the operating system is
 *   possible.
 * - <b>Non Maskable Interrupts</b>. Non maskable interrupt sources are
 *   totally out of the operating system control and have the lowest latency.
 *   Such sources are not supported on all the architectures.
 * .
 * The mapping of the above logical classes into physical interrupts priorities
 * is, of course, port dependent. See the documentation of the various ports
 * for details.
 *
 * @section system_states System States
 * When using ChibiOS/RT the system can be in one of the following logical
 * operating states:
 * - <b>Init</b>. When the system is in this state all the maskable
 *   interrupt sources are disabled. In this state it is not possible to use
 *   any system API except @p chSysInit(). This state is entered after a
 *   physical reset.
 * - <b>Normal</b>. All the interrupt sources are enabled and the system APIs
 *   are accessible, threads are running.
 * - <b>Suspended</b>. In this state the fast interrupt sources are enabled but
 *   the regular interrupt sources are not. In this state it is not possible
 *   to use any system API except @p chSysDisable() or @p chSysEnable() in
 *   order to change state.
 * - <b>Disabled</b>. When the system is in this state both the maskable
 *   regular and fast interrupt sources are disabled. In this state it is not
 *   possible to use any system API except @p chSysSuspend() or
 *   @p chSysEnable() in order to change state.
 * - <b>Sleep</b>. Architecture-dependent low power mode, the idle thread
 *   goes in this state and waits for interrupts, after servicing the interrupt
 *   the Normal state is restored and the scheduler has a chance to reschedule.
 * - <b>S-Locked</b>. Kernel locked and regular interrupt sources disabled.
 *   Fast interrupt sources are enabled. @ref S-Class and @ref I-Class APIs are
 *   invokable in this state.
 * - <b>I-Locked</b>. Kernel locked and regular interrupt sources disabled.
 *   @ref I-Class APIs are invokable from this state.
 * - <b>Serving Regular Interrupt</b>. No system APIs are accessible but it is
 *   possible to switch to the I-Locked state using @p chSysLockFromIsr() and
 *   then invoke any @ref I-Class API. Interrupt handlers can be preemptable on
 *   some architectures thus is important to switch to I-Locked state before
 *   invoking system APIs.
 * - <b>Serving Fast Interrupt</b>. System APIs are not accessible.
 * - <b>Serving Non-Maskable Interrupt</b>. System APIs are not accessible.
 * - <b>Halted</b>. All interrupt sources are disabled and system stopped into
 *   an infinite loop. This state can be reached if the debug mode is activated
 *   <b>and</b> an error is detected <b>or</b> after explicitly invoking
 *   @p chSysHalt().
 * .
 * Note that the above states are just <b>Logical States</b> that may have no
 * real associated machine state on some architectures. The following diagram
 * shows the possible transitions between the states:
 *
 * @if LATEX_PDF
 * @dot
  digraph example {
    size="5, 7";
    rankdir="LR";
    node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];
    edge [fontname=Helvetica, fontsize=8];
    init [label="Init", style="bold"];
    norm [label="Normal", shape=doublecircle];
    susp [label="Suspended"];
    disab [label="Disabled"];
    slock [label="S-Locked"];
    ilock [label="I-Locked"];
    slock [label="S-Locked"];
    sleep [label="Sleep"];
    sri [label="SRI"];
    init -> norm [label="chSysInit()"];
    norm -> slock [label="chSysLock()", constraint=false];
    slock -> norm [label="chSysUnlock()"];
    norm -> susp [label="chSysSuspend()"];
    susp -> disab [label="chSysDisable()"];
    norm -> disab [label="chSysDisable()"];
    susp -> norm [label="chSysEnable()"];
    disab -> norm [label="chSysEnable()"];
    disab -> susp [label="chSysSuspend()"];
    slock -> ilock [label="Context Switch", dir="both"];
    norm -> sri [label="Regular IRQ", style="dotted"];
    sri -> norm [label="Regular IRQ return", fontname=Helvetica, fontsize=8];
    sri -> ilock [label="chSysLockFromIsr()", constraint=false];
    ilock -> sri [label="chSysUnlockFromIsr()", fontsize=8];
    norm -> sleep [label="Idle Thread"];
    sleep -> sri [label="Regular IRQ", style="dotted"];
  }
 * @enddot
 * @else
 * @dot
  digraph example {
    rankdir="LR";
    node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];
    edge [fontname=Helvetica, fontsize=8];
    init [label="Init", style="bold"];
    norm [label="Normal", shape=doublecircle];
    susp [label="Suspended"];
    disab [label="Disabled"];
    slock [label="S-Locked"];
    ilock [label="I-Locked"];
    slock [label="S-Locked"];
    sleep [label="Sleep"];
    sri [label="SRI"];
    init -> norm [label="chSysInit()"];
    norm -> slock [label="chSysLock()", constraint=false];
    slock -> norm [label="chSysUnlock()"];
    norm -> susp [label="chSysSuspend()"];
    susp -> disab [label="chSysDisable()"];
    norm -> disab [label="chSysDisable()"];
    susp -> norm [label="chSysEnable()"];
    disab -> norm [label="chSysEnable()"];
    disab -> susp [label="chSysSuspend()"];
    slock -> ilock [label="Context Switch", dir="both"];
    norm -> sri [label="Regular IRQ", style="dotted"];
    sri -> norm [label="Regular IRQ return", fontname=Helvetica, fontsize=8];
    sri -> ilock [label="chSysLockFromIsr()", constraint=false];
    ilock -> sri [label="chSysUnlockFromIsr()", fontsize=8];
    norm -> sleep [label="Idle Thread"];
    sleep -> sri [label="Regular IRQ", style="dotted"];
  }
 * @enddot
 * @endif
 * Note, the <b>SFI</b>, <b>Halted</b> and <b>SNMI</b> states were not shown
 * because those are reachable from most states:
 *
 * @dot
  digraph example {
    size="5, 7";
    rankdir="LR";
    node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];
    edge [fontname=Helvetica, fontsize=8];
    any1 [label="Any State\nexcept *"];
    sfi [label="SFI"];
    any1 -> sfi [style="dotted", label="Fast IRQ"];
    sfi -> any1 [label="Fast IRQ return"];
  }
 * @enddot
 * @dot
  digraph example {
    size="5, 7";
    rankdir="LR";
    node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];
    edge [fontname=Helvetica, fontsize=8];
    any2 [label="Any State"];
    halt [label="Halted"];
    SNMI [label="SNMI"];
    any2 -> halt [label="chSysHalt()"];
    any2 -> SNMI [label="Synchronous NMI"];
    any2 -> SNMI [label="Asynchronous NMI", style="dotted"];
    SNMI -> any2 [label="NMI return"];
    halt -> SNMI [label="Asynchronous NMI", style="dotted"];
    SNMI -> halt [label="NMI return"];
  }
 * @enddot
 * @attention * except: <b>Init</b>, <b>Halt</b>, <b>SNMI</b>, <b>Disabled</b>.
 *
 * @section scheduling Scheduling
 * The strategy is very simple the currently ready thread with the highest
 * priority is executed. If more than one thread with equal priority are
 * eligible for execution then they are executed in a round-robin way, the
 * CPU time slice constant is configurable. The ready list is a double linked
 * list of threads ordered by priority.<br><br>
 * @if LATEX_PDF
 * @dot
  digraph example {
    size="5, 7";
    rankdir="LR";

    node [shape=square, fontname=Helvetica, fontsize=8,
          fixedsize="true", width="0.6", height="0.5"];
    edge [fontname=Helvetica, fontsize=8];

    subgraph cluster_running {
      node [shape=square, fontname=Helvetica, fontsize=8,
            fixedsize="true", width="0.6", height="0.5"];
      currp [label="'currp'\npointer", style="bold"];
      T4 [label="Tuser(4)\nprio=100"];
      label = "Currently Running Thread";
      penwidth = 0;
    }

    subgraph cluster_rlist {
      node [shape=square, fontname=Helvetica, fontsize=8,
            fixedsize="true", width="0.6", height="0.5"];
      rh [label="ready list\nheader\nprio=0", style="bold"];
      Ti [label="Tidle\nprio=1"];
      Tm [label="Tmain\nprio=64"];
      T1 [label="Tuser(1)\nprio=32"];
      T2 [label="Tuser(2)\nprio=32"];
      T3 [label="Tuser(3)\nprio=80"];
      label = "Threads Ready for Execution";
      penwidth = 0;
    }

    currp -> T4
    rh -> Ti -> T1 -> T2 -> Tm -> T3 -> rh [label="p_next"];
    rh -> T3 -> Tm -> T2 -> T1 -> Ti -> rh [label="p_prev"];
  }
 * @enddot
 * @else
 * @dot
  digraph example {
    rankdir="LR";

    node [shape=square, fontname=Helvetica, fontsize=8,
          fixedsize="true", width="0.6", height="0.5"];
    edge [fontname=Helvetica, fontsize=8];

    subgraph cluster_running {
      node [shape=square, fontname=Helvetica, fontsize=8,
            fixedsize="true", width="0.6", height="0.5"];
      currp [label="'currp'\npointer", style="bold"];
      T4 [label="Tuser(4)\nprio=100"];
      label = "Currently Running Thread";
      penwidth = 0;
    }

    subgraph cluster_rlist {
      node [shape=square, fontname=Helvetica, fontsize=8,
            fixedsize="true", width="0.6", height="0.5"];
      rh [label="ready list\nheader\nprio=0", style="bold"];
      Ti [label="Tidle\nprio=1"];
      Tm [label="Tmain\nprio=64"];
      T1 [label="Tuser(1)\nprio=32"];
      T2 [label="Tuser(2)\nprio=32"];
      T3 [label="Tuser(3)\nprio=80"];
      label = "Threads Ready for Execution";
      penwidth = 0;
    }

    currp -> T4
    rh -> Ti -> T1 -> T2 -> Tm -> T3 -> rh [label="p_next"];
    rh -> T3 -> Tm -> T2 -> T1 -> Ti -> rh [label="p_prev"];
  }
 * @enddot
 * @endif
 * <br>
 * Note that the currently running thread is not in the ready list, the list
 * only contains the threads ready to be executed but still actually waiting.
 *
 * @section thread_states Thread States
 * The image shows how threads can change their state in ChibiOS/RT.<br>
 * @if LATEX_PDF
 * @dot
  digraph example {
    rankdir="LR";
    node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];
    size="5, 7";

    edge [fontname=Helvetica, fontsize=8];
    start [label="Start", style="bold"];

    run [label="Running"];
    ready [label="Ready"];
    suspend [label="Suspended"];
    sleep [label="Sleeping"];
    stop [label="Stop", style="bold"];

    start -> suspend [label="\n chThdCreateI()", constraint=false, dir=back];
    start -> run [label="chThdCreate()"];
    start -> ready [label="chThdCreate()"];
    run -> ready [label="Reschedule", dir="both"];
    suspend -> run [label="chThdResume()"];
    suspend -> ready [label="chThdResume()"];
    run -> sleep [label="chSchGoSleepS()"];
    sleep -> run [label="chSchWakepuS()"];
    sleep -> ready [label="chSchWakepuS()"];
    run -> stop [label="chThdExit()"];
  }
 * @enddot
 * @else
 * @dot
  digraph example {
    rankdir="LR";
    node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];

    edge [fontname=Helvetica, fontsize=8];
    start [label="Start", style="bold"];

    run [label="Running"];
    ready [label="Ready"];
    suspend [label="Suspended"];
    sleep [label="Sleeping"];
    stop [label="Stop", style="bold"];

    start -> suspend [label="\n chThdCreateI()", constraint=false, dir=back];
    start -> run [label="chThdCreate()"];
    start -> ready [label="chThdCreate()"];
    run -> ready [label="Reschedule", dir="both"];
    suspend -> run [label="chThdResume()"];
    suspend -> ready [label="chThdResume()"];
    run -> sleep [label="chSchGoSleepS()"];
    sleep -> run [label="chSchWakepuS()"];
    sleep -> ready [label="chSchWakepuS()"];
    run -> stop [label="chThdExit()"];
  }
 * @enddot
 * @endif
 *
 * @section priority Priority Levels
 * Priorities in ChibiOS/RT are a contiguous numerical range but the initial
 * and final values are not enforced.<br>
 * The following table describes the various priority boundaries (from lowest
 *   to highest):
 * - @p IDLEPRIO, this is the lowest priority level and is reserved for the
 *   idle thread, no other threads should share this priority level. This is
 *   the lowest numerical value of the priorities space.
 * - @p LOWPRIO, the lowest priority level that can be assigned to an user
 *   thread.
 * - @p NORMALPRIO, this is the central priority level for user threads. It is
 *   advisable to assign priorities to threads as values relative to
 *   @p NORMALPRIO, as example NORMALPRIO-1 or NORMALPRIO+4, this ensures the
 *   portability of code should the numerical range change in future
 *   implementations.
 * - @p HIGHPRIO, the highest priority level that can be assigned to an user
 *   thread.
 * - @p ABSPRO, absolute maximum software priority level, it can be higher than
 *   @p HIGHPRIO but the numerical values above @p HIGHPRIO up to @p ABSPRIO
 *   (inclusive) are reserved. This is the highest numerical value of the
 *   priorities space.
 * .
 * @section warea Thread Working Area
 * Each thread has its own stack, a Thread structure and some preemption
 * areas. All the structures are allocated into a "Thread Working Area",
 * a thread private heap, usually statically declared in your code.
 * Threads do not use any memory outside the allocated working area
 * except when accessing static shared data.<br><br>
 * @if LATEX_PDF
 * @image latex workspace.eps
 * @else
 * @image html workspace.png
 * @endif
 * <br>
 * Note that the preemption area is only present when the thread is not
 * running (switched out), the context switching is done by pushing the
 * registers on the stack of the switched-out thread and popping the registers
 * of the switched-in thread from its stack.
 * The preemption area can be divided in up to three structures:
 * - External Context.
 * - Interrupt Stack.
 * - Internal Context.
 * .
 * See the port documentation for details, the area may change on
 * the various ports and some structures may not be present (or be zero-sized).
 */