aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/rt/include/chschd.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/rt/include/chschd.h')
-rw-r--r--lib/chibios/os/rt/include/chschd.h600
1 files changed, 600 insertions, 0 deletions
diff --git a/lib/chibios/os/rt/include/chschd.h b/lib/chibios/os/rt/include/chschd.h
new file mode 100644
index 000000000..ff4c7abb4
--- /dev/null
+++ b/lib/chibios/os/rt/include/chschd.h
@@ -0,0 +1,600 @@
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/include/chschd.h
22 * @brief Scheduler macros and structures.
23 *
24 * @addtogroup scheduler
25 * @{
26 */
27
28#ifndef CHSCHD_H
29#define CHSCHD_H
30
31/*===========================================================================*/
32/* Module constants. */
33/*===========================================================================*/
34
35/**
36 * @name Wakeup status codes
37 * @{
38 */
39#define MSG_OK (msg_t)0 /**< @brief Normal wakeup message. */
40#define MSG_TIMEOUT (msg_t)-1 /**< @brief Wakeup caused by a timeout
41 condition. */
42#define MSG_RESET (msg_t)-2 /**< @brief Wakeup caused by a reset
43 condition. */
44/** @} */
45
46/**
47 * @name Priority constants
48 * @{
49 */
50#define NOPRIO (tprio_t)0 /**< @brief Ready list header
51 priority. */
52#define IDLEPRIO (tprio_t)1 /**< @brief Idle priority. */
53#define LOWPRIO (tprio_t)2 /**< @brief Lowest priority. */
54#define NORMALPRIO (tprio_t)128 /**< @brief Normal priority. */
55#define HIGHPRIO (tprio_t)255 /**< @brief Highest priority. */
56/** @} */
57
58/**
59 * @name Thread states
60 * @{
61 */
62#define CH_STATE_READY (tstate_t)0 /**< @brief Waiting on the
63 ready list. */
64#define CH_STATE_CURRENT (tstate_t)1 /**< @brief Currently running. */
65#define CH_STATE_WTSTART (tstate_t)2 /**< @brief Just created. */
66#define CH_STATE_SUSPENDED (tstate_t)3 /**< @brief Suspended state. */
67#define CH_STATE_QUEUED (tstate_t)4 /**< @brief On a queue. */
68#define CH_STATE_WTSEM (tstate_t)5 /**< @brief On a semaphore. */
69#define CH_STATE_WTMTX (tstate_t)6 /**< @brief On a mutex. */
70#define CH_STATE_WTCOND (tstate_t)7 /**< @brief On a cond.variable.*/
71#define CH_STATE_SLEEPING (tstate_t)8 /**< @brief Sleeping. */
72#define CH_STATE_WTEXIT (tstate_t)9 /**< @brief Waiting a thread. */
73#define CH_STATE_WTOREVT (tstate_t)10 /**< @brief One event. */
74#define CH_STATE_WTANDEVT (tstate_t)11 /**< @brief Several events. */
75#define CH_STATE_SNDMSGQ (tstate_t)12 /**< @brief Sending a message,
76 in queue. */
77#define CH_STATE_SNDMSG (tstate_t)13 /**< @brief Sent a message,
78 waiting answer. */
79#define CH_STATE_WTMSG (tstate_t)14 /**< @brief Waiting for a
80 message. */
81#define CH_STATE_FINAL (tstate_t)15 /**< @brief Thread terminated. */
82
83/**
84 * @brief Thread states as array of strings.
85 * @details Each element in an array initialized with this macro can be
86 * indexed using the numeric thread state values.
87 */
88#define CH_STATE_NAMES \
89 "READY", "CURRENT", "WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", \
90 "WTCOND", "SLEEPING", "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", \
91 "SNDMSG", "WTMSG", "FINAL"
92/** @} */
93
94/**
95 * @name Thread flags and attributes
96 * @{
97 */
98#define CH_FLAG_MODE_MASK (tmode_t)3U /**< @brief Thread memory mode
99 mask. */
100#define CH_FLAG_MODE_STATIC (tmode_t)0U /**< @brief Static thread. */
101#define CH_FLAG_MODE_HEAP (tmode_t)1U /**< @brief Thread allocated
102 from a Memory Heap. */
103#define CH_FLAG_MODE_MPOOL (tmode_t)2U /**< @brief Thread allocated
104 from a Memory Pool. */
105#define CH_FLAG_TERMINATE (tmode_t)4U /**< @brief Termination requested
106 flag. */
107/** @} */
108
109/*===========================================================================*/
110/* Module pre-compile time settings. */
111/*===========================================================================*/
112
113/*===========================================================================*/
114/* Derived constants and error checks. */
115/*===========================================================================*/
116
117/*===========================================================================*/
118/* Module data structures and types. */
119/*===========================================================================*/
120
121/**
122 * @brief Structure representing a threads queue.
123 */
124struct ch_threads_queue {
125 ch_queue_t queue; /**< @brief Threads queue header. */
126};
127
128/**
129 * @brief Structure representing a thread.
130 * @note Not all the listed fields are always needed, by switching off some
131 * not needed ChibiOS/RT subsystems it is possible to save RAM space
132 * by shrinking this structure.
133 */
134struct ch_thread {
135 union {
136 ch_list_t list; /**< @brief Threads lists element. */
137 ch_queue_t queue; /**< @brief Threads queues element. */
138 ch_priority_queue_t pqueue; /**< @brief Threads ordered queues
139 element. */
140 } hdr;
141 struct port_context ctx; /**< @brief Processor context. */
142#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
143 thread_t *newer; /**< @brief Newer registry element. */
144 thread_t *older; /**< @brief Older registry element. */
145#endif
146 /* End of the fields shared with the ReadyList structure. */
147#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
148 /**
149 * @brief Thread name or @p NULL.
150 */
151 const char *name;
152#endif
153#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) || \
154 defined(__DOXYGEN__)
155 /**
156 * @brief Working area base address.
157 * @note This pointer is used for stack overflow checks and for
158 * dynamic threading.
159 */
160 stkalign_t *wabase;
161#endif
162 /**
163 * @brief Current thread state.
164 */
165 tstate_t state;
166 /**
167 * @brief Various thread flags.
168 */
169 tmode_t flags;
170#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
171 /**
172 * @brief References to this thread.
173 */
174 trefs_t refs;
175#endif
176 /**
177 * @brief Number of ticks remaining to this thread.
178 */
179#if (CH_CFG_TIME_QUANTUM > 0) || defined(__DOXYGEN__)
180 tslices_t ticks;
181#endif
182#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__)
183 /**
184 * @brief Thread consumed time in ticks.
185 * @note This field can overflow.
186 */
187 volatile systime_t time;
188#endif
189 /**
190 * @brief State-specific fields.
191 * @note All the fields declared in this union are only valid in the
192 * specified state or condition and are thus volatile.
193 */
194 union {
195 /**
196 * @brief Thread wakeup code.
197 * @note This field contains the low level message sent to the thread
198 * by the waking thread or interrupt handler. The value is valid
199 * after exiting the @p chSchWakeupS() function.
200 */
201 msg_t rdymsg;
202 /**
203 * @brief Thread exit code.
204 * @note The thread termination code is stored in this field in order
205 * to be retrieved by the thread performing a @p chThdWait() on
206 * this thread.
207 */
208 msg_t exitcode;
209 /**
210 * @brief Pointer to a generic "wait" object.
211 * @note This field is used to get a generic pointer to a synchronization
212 * object and is valid when the thread is in one of the wait
213 * states.
214 */
215 void *wtobjp;
216 /**
217 * @brief Pointer to a generic thread reference object.
218 * @note This field is used to get a pointer to a synchronization
219 * object and is valid when the thread is in @p CH_STATE_SUSPENDED
220 * state.
221 */
222 thread_reference_t *wttrp;
223#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__)
224 /**
225 * @brief Thread sent message.
226 */
227 msg_t sentmsg;
228#endif
229#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
230 /**
231 * @brief Pointer to a generic semaphore object.
232 * @note This field is used to get a pointer to a synchronization
233 * object and is valid when the thread is in @p CH_STATE_WTSEM
234 * state.
235 */
236 struct ch_semaphore *wtsemp;
237#endif
238#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
239 /**
240 * @brief Pointer to a generic mutex object.
241 * @note This field is used to get a pointer to a synchronization
242 * object and is valid when the thread is in @p CH_STATE_WTMTX
243 * state.
244 */
245 struct ch_mutex *wtmtxp;
246#endif
247#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
248 /**
249 * @brief Enabled events mask.
250 * @note This field is only valid while the thread is in the
251 * @p CH_STATE_WTOREVT or @p CH_STATE_WTANDEVT states.
252 */
253 eventmask_t ewmask;
254#endif
255 } u;
256#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__)
257 /**
258 * @brief Termination waiting list.
259 */
260 ch_list_t waiting;
261#endif
262#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__)
263 /**
264 * @brief Messages queue.
265 */
266 ch_queue_t msgqueue;
267#endif
268#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
269 /**
270 * @brief Pending events mask.
271 */
272 eventmask_t epending;
273#endif
274#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
275 /**
276 * @brief List of the mutexes owned by this thread.
277 * @note The list is terminated by a @p NULL in this field.
278 */
279 struct ch_mutex *mtxlist;
280 /**
281 * @brief Thread's own, non-inherited, priority.
282 */
283 tprio_t realprio;
284#endif
285#if ((CH_CFG_USE_DYNAMIC == TRUE) && (CH_CFG_USE_MEMPOOLS == TRUE)) || \
286 defined(__DOXYGEN__)
287 /**
288 * @brief Memory Pool where the thread workspace is returned.
289 */
290 void *mpool;
291#endif
292#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__)
293 /**
294 * @brief Thread statistics.
295 */
296 time_measurement_t stats;
297#endif
298#if defined(CH_CFG_THREAD_EXTRA_FIELDS)
299 /* Extra fields defined in chconf.h.*/
300 CH_CFG_THREAD_EXTRA_FIELDS
301#endif
302};
303
304/**
305 * @brief Type of a Virtual Timer structure.
306 */
307typedef struct ch_delta_list delta_list_t;
308
309/**
310 * @brief Virtual Timer delta list element and header structure.
311 */
312struct ch_delta_list {
313 delta_list_t *next; /**< @brief Next timer in the list. */
314 delta_list_t *prev; /**< @brief Previous timer in the list. */
315 sysinterval_t delta; /**< @brief Time delta before timeout. */
316};
317
318/**
319 * @brief Structure representing a Virtual Timer.
320 */
321struct ch_virtual_timer {
322 delta_list_t dlist; /**< @brief Delta list element. */
323 vtfunc_t func; /**< @brief Timer callback function
324 pointer. */
325 void *par; /**< @brief Timer callback function
326 parameter. */
327};
328
329/**
330 * @brief Structure representing a virtual timers list header.
331 * @note The timers list is implemented as a double link bidirectional list
332 * in order to make the unlink time constant, the reset of a virtual
333 * timer is often used in the code.
334 */
335struct ch_virtual_timers_list {
336 delta_list_t dlist; /**< @brief Delta list header. */
337#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
338 volatile systime_t systime; /**< @brief System Time counter. */
339#endif
340#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
341 /**
342 * @brief System time of the last tick event.
343 */
344 systime_t lasttime; /**< @brief System time of the last
345 tick event. */
346#endif
347};
348
349/**
350 * @extends threads_queue_t
351 */
352struct ch_ready_list {
353 /**
354 * @brief Threads ordered queues header.
355 * @note The priority field must be initialized to zero.
356 */
357 ch_priority_queue_t pqueue;
358 /**
359 * @brief Not used, present because offsets.
360 */
361 struct port_context ctx;
362#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
363 /**
364 * @brief Newer registry element.
365 */
366 thread_t *newer;
367 /**
368 * @brief Older registry element.
369 */
370 thread_t *older;
371#endif
372 /* End of the fields shared with the thread_t structure.*/
373 /**
374 * @brief The currently running thread.
375 */
376 thread_t *current;
377};
378
379/**
380 * @brief System debug data structure.
381 */
382struct ch_system_debug {
383 /**
384 * @brief Pointer to the panic message.
385 * @details This pointer is meant to be accessed through the debugger, it is
386 * written once and then the system is halted.
387 * @note Accesses to this pointer must never be optimized out so the
388 * field itself is declared volatile.
389 */
390 const char * volatile panic_msg;
391#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__)
392 /**
393 * @brief ISR nesting level.
394 */
395 cnt_t isr_cnt;
396 /**
397 * @brief Lock nesting level.
398 */
399 cnt_t lock_cnt;
400#endif
401#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED) || defined(__DOXYGEN__)
402 /**
403 * @brief Public trace buffer.
404 */
405 ch_trace_buffer_t trace_buffer;
406#endif
407};
408
409/**
410 * @brief System data structure.
411 * @note This structure contain all the data areas used by the OS except
412 * stacks.
413 */
414struct ch_system {
415 /**
416 * @brief Ready list header.
417 */
418 ready_list_t rlist;
419 /**
420 * @brief Virtual timers delta list header.
421 */
422 virtual_timers_list_t vtlist;
423 /**
424 * @brief System debug.
425 */
426 system_debug_t dbg;
427 /**
428 * @brief Main thread descriptor.
429 */
430 thread_t mainthread;
431#if (CH_CFG_USE_TM == TRUE) || defined(__DOXYGEN__)
432 /**
433 * @brief Time measurement calibration data.
434 */
435 tm_calibration_t tm;
436#endif
437#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__)
438 /**
439 * @brief Global kernel statistics.
440 */
441 kernel_stats_t kernel_stats;
442#endif
443 CH_CFG_SYSTEM_EXTRA_FIELDS
444};
445
446/*===========================================================================*/
447/* Module macros. */
448/*===========================================================================*/
449
450/**
451 * @brief Returns the priority of the first thread on the given ready list.
452 *
453 * @notapi
454 */
455#define firstprio(rlp) ((rlp)->next->prio)
456
457/**
458 * @brief Current thread pointer access macro.
459 * @note This macro is not meant to be used in the application code but
460 * only from within the kernel, use @p chThdGetSelfX() instead.
461 */
462#define currp ch.rlist.current
463
464/*===========================================================================*/
465/* External declarations. */
466/*===========================================================================*/
467
468#if !defined(__DOXYGEN__)
469extern ch_system_t ch;
470#endif
471
472/*
473 * Scheduler APIs.
474 */
475#ifdef __cplusplus
476extern "C" {
477#endif
478 void _scheduler_init(void);
479 thread_t *chSchReadyI(thread_t *tp);
480 thread_t *chSchReadyAheadI(thread_t *tp);
481 void chSchGoSleepS(tstate_t newstate);
482 msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout);
483 void chSchWakeupS(thread_t *ntp, msg_t msg);
484 void chSchRescheduleS(void);
485 bool chSchIsPreemptionRequired(void);
486 void chSchDoRescheduleBehind(void);
487 void chSchDoRescheduleAhead(void);
488 void chSchDoReschedule(void);
489#if CH_CFG_OPTIMIZE_SPEED == FALSE
490 void ch_sch_prio_insert(ch_queue_t *tp, ch_queue_t *qp);
491#endif /* CH_CFG_OPTIMIZE_SPEED == FALSE */
492#ifdef __cplusplus
493}
494#endif
495
496/*===========================================================================*/
497/* Module inline functions. */
498/*===========================================================================*/
499
500/* If the performance code path has been chosen then all the following
501 functions are inlined into the various kernel modules.*/
502#if CH_CFG_OPTIMIZE_SPEED == TRUE
503static inline void ch_sch_prio_insert(ch_queue_t *tp, ch_queue_t *qp) {
504
505 ch_queue_t *cp = qp;
506 do {
507 cp = cp->next;
508 } while ((cp != qp) &&
509 (((thread_t *)cp)->hdr.pqueue.prio >= ((thread_t *)tp)->hdr.pqueue.prio));
510 tp->next = cp;
511 tp->prev = cp->prev;
512 tp->prev->next = tp;
513 cp->prev = tp;
514}
515#endif /* CH_CFG_OPTIMIZE_SPEED == TRUE */
516
517/**
518 * @brief Determines if the current thread must reschedule.
519 * @details This function returns @p true if there is a ready thread with
520 * higher priority.
521 *
522 * @return The priorities situation.
523 * @retval false if rescheduling is not necessary.
524 * @retval true if there is a ready thread at higher priority.
525 *
526 * @iclass
527 */
528static inline bool chSchIsRescRequiredI(void) {
529
530 chDbgCheckClassI();
531
532 return firstprio(&ch.rlist.pqueue) > currp->hdr.pqueue.prio;
533}
534
535/**
536 * @brief Determines if yielding is possible.
537 * @details This function returns @p true if there is a ready thread with
538 * equal or higher priority.
539 *
540 * @return The priorities situation.
541 * @retval false if yielding is not possible.
542 * @retval true if there is a ready thread at equal or higher priority.
543 *
544 * @sclass
545 */
546static inline bool chSchCanYieldS(void) {
547
548 chDbgCheckClassS();
549
550 return firstprio(&ch.rlist.pqueue) >= currp->hdr.pqueue.prio;
551}
552
553/**
554 * @brief Yields the time slot.
555 * @details Yields the CPU control to the next thread in the ready list with
556 * equal or higher priority, if any.
557 *
558 * @sclass
559 */
560static inline void chSchDoYieldS(void) {
561
562 chDbgCheckClassS();
563
564 if (chSchCanYieldS()) {
565 chSchDoRescheduleBehind();
566 }
567}
568
569/**
570 * @brief Inline-able preemption code.
571 * @details This is the common preemption code, this function must be invoked
572 * exclusively from the port layer.
573 *
574 * @special
575 */
576static inline void chSchPreemption(void) {
577 tprio_t p1 = firstprio(&ch.rlist.pqueue);
578 tprio_t p2 = currp->hdr.pqueue.prio;
579
580#if CH_CFG_TIME_QUANTUM > 0
581 if (currp->ticks > (tslices_t)0) {
582 if (p1 > p2) {
583 chSchDoRescheduleAhead();
584 }
585 }
586 else {
587 if (p1 >= p2) {
588 chSchDoRescheduleBehind();
589 }
590 }
591#else /* CH_CFG_TIME_QUANTUM == 0 */
592 if (p1 > p2) {
593 chSchDoRescheduleAhead();
594 }
595#endif /* CH_CFG_TIME_QUANTUM == 0 */
596}
597
598#endif /* CHSCHD_H */
599
600/** @} */