/*
    ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
              2015,2016,2017,2018,2019,2020,2021 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 version 3 of the License.

    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 Kernel Concepts
 * This article applies to both RT and NIL kernels, many concepts are also
 * applicable to HAL (states and API classes).
 *
 * - @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 and ChibiOS/NIL APIs are named following this convention:
 * @a ch\<group\>\<action\>\<suffix\>().
 * Examples of groups are: @a Sys, @a Sch, @a Time, @a VT, @a Thd, @a Sem, etc.
 *
 * @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.
 *   This kind of functions never reschedule internally and are meant to be
 *   used from interrupt handlers. If used from thread level then
 *   an explicit reschedule operation could be necessary before leaving the
 *   containing critical zone.
 * - @anchor S-Class <b>"S"</b>, S-Class APIs are invokable only from the
 *   <b>S-Locked</b> state. See @ref system_states.
 *   This kind of functions can reschedule internally but are not guaranteed
 *   to do so necessarily. For example a wait function on a semaphore can
 *   reschedule or not reschedule depending on the semaphore state.
 * - @anchor X-Class <b>"X"</b>, X-Class APIs are invokable from any context.
 * .
 * Examples: @p chThdCreateStatic(), @p chSemSignalI(), @p chThdCreateStatic().
 *
 * @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).
 */
