From fcfddc0f5df7d4195020e1d393d5f97ed0add5a5 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Thu, 3 Nov 2016 12:13:27 -0700 Subject: [PATCH] kernel: delete old micro and nanokernel documentation Change-Id: Id1685930dd11f4b5038d5f98da978c6348b67966 Signed-off-by: Andrew Boie --- doc/api/api.rst | 2 - doc/api/microkernel_api.rst | 155 ----- doc/api/nanokernel_api.rst | 141 ---- doc/index.rst | 1 - doc/kernel/common/common.rst | 15 - doc/kernel/common/common_atomic.rst | 105 --- doc/kernel/common/common_contexts.rst | 101 --- doc/kernel/common/common_float.rst | 198 ------ doc/kernel/common/common_kernel_clocks.rst | 144 ---- doc/kernel/kernel.rst | 31 - doc/kernel/microkernel/microkernel.rst | 18 - doc/kernel/microkernel/microkernel_data.rst | 13 - doc/kernel/microkernel/microkernel_events.rst | 232 ------- doc/kernel/microkernel/microkernel_fibers.rst | 47 -- doc/kernel/microkernel/microkernel_fifos.rst | 193 ------ .../microkernel/microkernel_mailboxes.rst | 645 ------------------ doc/kernel/microkernel/microkernel_memory.rst | 13 - .../microkernel/microkernel_memory_maps.rst | 185 ----- .../microkernel/microkernel_memory_pools.rst | 203 ------ .../microkernel/microkernel_mutexes.rst | 194 ------ doc/kernel/microkernel/microkernel_pipes.rst | 333 --------- .../microkernel/microkernel_semaphores.rst | 229 ------- .../microkernel_synchronization.rst | 14 - doc/kernel/microkernel/microkernel_tasks.rst | 540 --------------- doc/kernel/microkernel/microkernel_timers.rst | 211 ------ doc/kernel/nanokernel/nanokernel.rst | 20 - doc/kernel/nanokernel/nanokernel_data.rst | 15 - doc/kernel/nanokernel/nanokernel_example.rst | 149 ---- doc/kernel/nanokernel/nanokernel_fibers.rst | 313 --------- doc/kernel/nanokernel/nanokernel_fifos.rst | 144 ---- .../nanokernel/nanokernel_interrupts.rst | 173 ----- .../nanokernel_kernel_event_logger.rst | 364 ---------- doc/kernel/nanokernel/nanokernel_lifos.rst | 142 ---- .../nanokernel/nanokernel_ring_buffers.rst | 143 ---- doc/kernel/nanokernel/nanokernel_stacks.rst | 142 ---- .../nanokernel/nanokernel_synchronization.rst | 133 ---- doc/kernel/nanokernel/nanokernel_tasks.rst | 78 --- doc/kernel/nanokernel/nanokernel_timers.rst | 179 ----- .../figures/overview_nanokernel_1.svg | 52 -- doc/kernel/overview/kernel_fundamentals.rst | 372 ---------- doc/kernel/overview/overview.rst | 12 - doc/kernel/overview/source_tree.rst | 52 -- doc/kernel_v2/memory/pools.rst | 3 +- doc/porting/arch.rst | 3 - 44 files changed, 1 insertion(+), 6451 deletions(-) delete mode 100644 doc/api/microkernel_api.rst delete mode 100644 doc/api/nanokernel_api.rst delete mode 100644 doc/kernel/common/common.rst delete mode 100644 doc/kernel/common/common_atomic.rst delete mode 100644 doc/kernel/common/common_contexts.rst delete mode 100644 doc/kernel/common/common_float.rst delete mode 100644 doc/kernel/common/common_kernel_clocks.rst delete mode 100644 doc/kernel/kernel.rst delete mode 100644 doc/kernel/microkernel/microkernel.rst delete mode 100644 doc/kernel/microkernel/microkernel_data.rst delete mode 100644 doc/kernel/microkernel/microkernel_events.rst delete mode 100644 doc/kernel/microkernel/microkernel_fibers.rst delete mode 100644 doc/kernel/microkernel/microkernel_fifos.rst delete mode 100644 doc/kernel/microkernel/microkernel_mailboxes.rst delete mode 100644 doc/kernel/microkernel/microkernel_memory.rst delete mode 100644 doc/kernel/microkernel/microkernel_memory_maps.rst delete mode 100644 doc/kernel/microkernel/microkernel_memory_pools.rst delete mode 100644 doc/kernel/microkernel/microkernel_mutexes.rst delete mode 100644 doc/kernel/microkernel/microkernel_pipes.rst delete mode 100644 doc/kernel/microkernel/microkernel_semaphores.rst delete mode 100644 doc/kernel/microkernel/microkernel_synchronization.rst delete mode 100644 doc/kernel/microkernel/microkernel_tasks.rst delete mode 100644 doc/kernel/microkernel/microkernel_timers.rst delete mode 100644 doc/kernel/nanokernel/nanokernel.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_data.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_example.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_fibers.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_fifos.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_interrupts.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_kernel_event_logger.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_lifos.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_ring_buffers.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_stacks.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_synchronization.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_tasks.rst delete mode 100644 doc/kernel/nanokernel/nanokernel_timers.rst delete mode 100644 doc/kernel/overview/figures/overview_nanokernel_1.svg delete mode 100644 doc/kernel/overview/kernel_fundamentals.rst delete mode 100644 doc/kernel/overview/overview.rst delete mode 100644 doc/kernel/overview/source_tree.rst diff --git a/doc/api/api.rst b/doc/api/api.rst index c06ec38ced2..6642d3e6e85 100644 --- a/doc/api/api.rst +++ b/doc/api/api.rst @@ -17,8 +17,6 @@ The use of the Zephyr APIs is the same for all SoCs and boards. .. toctree:: :maxdepth: 2 - nanokernel_api.rst - microkernel_api.rst device.rst bluetooth.rst io_interfaces.rst diff --git a/doc/api/microkernel_api.rst b/doc/api/microkernel_api.rst deleted file mode 100644 index 832cffdbde5..00000000000 --- a/doc/api/microkernel_api.rst +++ /dev/null @@ -1,155 +0,0 @@ -.. microkernel_api: - -Microkernel APIs -################ - -.. contents:: - :depth: 1 - :local: - :backlinks: top - -Events -****** - -The microkernel's :dfn:`event` objects are an implementation of traditional -binary semaphores. - -For an overview and important information about Events, see :ref:`microkernel_events`. - ------- - -.. doxygengroup:: microkernel_event - :project: Zephyr - :content-only: - -FIFOs -***** - -The microkernel's :dfn:`FIFO` object type is an implementation of a traditional -first in, first out queue. -A FIFO allows tasks to asynchronously send and receive fixed-size data items. - -For an overview and important information about FIFOs, see :ref:`microkernel_fifos`. - ------- - -.. doxygengroup:: microkernel_fifo - :project: Zephyr - :content-only: - -Pipes -***** - -The microkernel's :dfn:`pipe` object type is an implementation of a traditional -anonymous pipe. A pipe allows a task to send a byte stream to another task. - -For an overview and important information about Pipes, see :ref:`microkernel_pipes`. - ------- - -.. doxygengroup:: microkernel_pipe - :project: Zephyr - :content-only: - -Mailboxes -********* - -The microkernel's :dfn:`mailbox` object type is an implementation of a -traditional message queue that allows tasks to exchange messages. - -For an overview and important information about Mailboxes, see :ref:`microkernel_mailboxes`. - ------- - -.. doxygengroup:: microkernel_mailbox - :project: Zephyr - :content-only: - -Memory Maps -*********** - -The microkernel's memory map objects provide dynamic allocation and -release of fixed-size memory blocks. - -For an overview and important information about Memory Maps, see :ref:`microkernel_memory_maps`. - ------- - -.. doxygengroup:: microkernel_memorymap - :project: Zephyr - :content-only: - -Memory Pools -************ - -The microkernel's :dfn:`memory pool` objects provide dynamic allocation and -release of variable-size memory blocks. - -For an overview and important information about Memory Pools, see :ref:`microkernel_memory_pools`. - ------- - -.. doxygengroup:: microkernel_memorypool - :project: Zephyr - :content-only: - -Mutexes -******* - -The microkernel's :dfn:`mutex` objects provide reentrant mutex -capabilities with basic priority inheritance. A mutex allows -tasks to safely share a resource by ensuring mutual exclusivity -while the resource is being accessed by a task. - -For an overview and important information about Mutexes, see :ref:`microkernel_mutexes`. - ------- - -.. doxygengroup:: microkernel_mutex - :project: Zephyr - :content-only: - -Semaphores -********** - -The microkernel's :dfn:`semaphore` objects are an implementation of traditional -counting semaphores. - -For an overview and important information about Semaphores, see :ref:`microkernel_semaphores`. - ------- - -.. doxygengroup:: microkernel_semaphore - :project: Zephyr - :content-only: - -Timers -****** - -A :dfn:`microkernel timer` allows a task to determine whether or not a -specified time limit has been reached while the task is busy performing -other work. The timer uses the kernel's system clock, measured in -ticks, to monitor the passage of time. - -For an overview and important information about Timers, see :ref:`microkernel_timers`. - ------- - -.. doxygengroup:: microkernel_timer - :project: Zephyr - :content-only: - -Tasks -***** - -A task is a preemptible thread of execution that implements a portion of -an application's processing. It is normally used for processing that -is too lengthy or too complex to be performed by a fiber or an ISR. - -For an overview and important information about Tasks, see :ref:`microkernel_tasks`. - ------- - -.. doxygengroup:: microkernel_task - :project: Zephyr - :content-only: diff --git a/doc/api/nanokernel_api.rst b/doc/api/nanokernel_api.rst deleted file mode 100644 index 82c664306dd..00000000000 --- a/doc/api/nanokernel_api.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. nanokernel_api: - -Nanokernel APIs -############### - -.. contents:: - :depth: 1 - :local: - :backlinks: top - -Fibers -****** - -A :dfn:`fiber` is a lightweight, non-preemptible thread of execution that -implements a portion of an application's processing. Fibers are often -used in device drivers and for performance-critical work. - -For an overview and important information about Fibers, see :ref:`nanokernel_fibers`. - ------- - -.. doxygengroup:: nanokernel_fiber - :project: Zephyr - :content-only: - -Tasks -****** - -A :dfn:`task` is a preemptible thread of execution that implements a portion of -an application's processing. It is normally used to perform processing that is -too lengthy or too complex to be performed by a fiber or an ISR. - -For an overview and important information about Tasks, see :ref:`nanokernel_tasks`. - ------- - -.. doxygengroup:: nanokernel_task - :project: Zephyr - :content-only: - -Semaphores -********** - -The nanokernel's :dfn:`semaphore` object type is an implementation of a -traditional counting semaphore. It is mainly intended for use by fibers. - -For an overview and important information about Semaphores, see :ref:`nanokernel_synchronization`. - ------- - -.. doxygengroup:: nanokernel_semaphore - :project: Zephyr - :content-only: - -LIFOs -***** - -The nanokernel's LIFO object type is an implementation of a traditional -last in, first out queue. It is mainly intended for use by fibers. - -For an overview and important information about LIFOs, see :ref:`nanokernel_lifos`. - ------- - -.. doxygengroup:: nanokernel_lifo - :project: Zephyr - :content-only: - -FIFOs -***** - -The nanokernel's FIFO object type is an implementation of a traditional -first in, first out queue. It is mainly intended for use by fibers. - -For an overview and important information about FIFOs, see :ref:`nanokernel_fifos`. - ------- - -.. doxygengroup:: nanokernel_fifo - :project: Zephyr - :content-only: - -Ring Buffers -************ - -The ring buffer is an array-based -circular buffer, stored in first-in-first-out order. Concurrency control of -ring buffers is not implemented at this level. - -For an overview and important information about ring buffers, see :ref:`nanokernel_ring_buffers`. - ------- - -.. doxygengroup:: nanokernel_ringbuffer - :project: Zephyr - :content-only: - -Stacks -****** - -The nanokernel's stack object type is an implementation of a traditional -last in, first out queue for a limited number of 32-bit data values. -It is mainly intended for use by fibers. - -For an overview and important information about stacks, see :ref:`nanokernel_stacks`. - ------- - -.. doxygengroup:: nanokernel_stack - :project: Zephyr - :content-only: - -Timers -****** - -The nanokernel's :dfn:`timer` object type uses the kernel's system clock to -monitor the passage of time, as measured in ticks. It is mainly intended for use -by fibers. - -For an overview and important information about timers, see :ref:`nanokernel_timers`. - ------- - -.. doxygengroup:: nanokernel_timer - :project: Zephyr - :content-only: - -Kernel Event Logger -******************* - -The kernel event logger is a standardized mechanism to record events within the -Kernel while providing a single interface for the user to collect the data. - -For an overview and important information about the kernel event logger API, -see :ref:`nanokernel_event_logger`. - ------- - -.. doxygengroup:: nanokernel_event_logger - :project: Zephyr - :content-only: diff --git a/doc/index.rst b/doc/index.rst index 555f8bd013e..c0904ccbfa2 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -31,7 +31,6 @@ Sections introduction/introducing_zephyr.rst getting_started/getting_started.rst board/board.rst - kernel/kernel.rst kernel_v2/kernel.rst drivers/drivers.rst subsystems/subsystems.rst diff --git a/doc/kernel/common/common.rst b/doc/kernel/common/common.rst deleted file mode 100644 index eca435ae564..00000000000 --- a/doc/kernel/common/common.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _common: - -Common Kernel Services -###################### - -This section describes kernel services that are provided in both -microkernel applications and nanokernel applications. - -.. toctree:: - :maxdepth: 1 - - common_contexts.rst - common_kernel_clocks.rst - common_atomic.rst - common_float.rst diff --git a/doc/kernel/common/common_atomic.rst b/doc/kernel/common/common_atomic.rst deleted file mode 100644 index a884070a3f6..00000000000 --- a/doc/kernel/common/common_atomic.rst +++ /dev/null @@ -1,105 +0,0 @@ -.. _common_atomic: - -Atomic Services -############### - -Concepts -******** - -The kernel supports an atomic 32-bit data type called :c:type:`atomic_t`. -A variable of this type can be read and modified by any task, fiber, or ISR -in an uninterruptible manner. This guarantees that the desired operation -will not be interfered with due to the scheduling of a higher priority context, -even if the higher priority context manipulates the same variable. - -Purpose -******* - -Use the atomic services to implement critical section processing that only -requires the manipulation of a single 32-bit data item. - -.. note:: - Using an atomic variable is typically far more efficient than using - other techniques to implement critical sections such as using - a microkernel mutex, offloading the processing to a fiber, or - locking interrupts. - -Usage -***** - -Example: Implementing an Uninterruptible Counter -================================================ -This code shows how a function can keep track of the number of times -it has been invoked. Since the count is incremented atomically, there is -no risk that it will become corrupted in mid-increment if the routine is -interrupted by the scheduling of a higher priority context that also -calls the routine. - -.. code-block:: c - - atomic_t call_count; - - int call_counting_routine(void) - { - /* increment invocation counter */ - atomic_inc(&call_count); - - /* do rest of routine's processing */ - ... - } - -APIs -**** - -The following atomic operation APIs are provided by :file:`atomic.h`: - -:c:func:`atomic_get()` - Reads an atomic variable. - -:c:func:`atomic_set()` - Writes an atomic variable. - -:c:func:`atomic_clear()` - Clears an atomic variable. - -:c:func:`atomic_add()` - Performs an addition operation on an atomic variable. - -:c:func:`atomic_sub()` - Performs a subtraction operation on an atomic variable. - -:c:func:`atomic_inc()` - Performs an increment operation on an atomic variable. - -:c:func:`atomic_dec()` - Performs a decrement operation on an atomic variable. - -:c:func:`atomic_and()` - Perform an "and" operation on an atomic variable. - -:c:func:`atomic_or()` - Perform an "or" operation on an atomic variable. - -:c:func:`atomic_xor()` - Perform a "xor" operation on an atomic variable. - -:c:func:`atomic_nand()` - Perform a "nand" operation on an atomic variable. - -:c:func:`atomic_cas()` - Performs compare-and-set operation on an atomic variable. - -:c:func:`atomic_set_bit()` - Sets specified bit of an atomic variable to 1. - -:c:func:`atomic_clear_bit()` - Sets specified bit of an atomic variable to 0. - -:c:func:`atomic_test_bit()` - Reads specified bit of an atomic variable. - -:c:func:`atomic_test_and_set_bit()` - Reads specified bit of an atomic variable and sets it to 1. - -:c:func:`atomic_test_and_clear_bit()` - Reads specified bit of an atomic variable and sets it to 0. \ No newline at end of file diff --git a/doc/kernel/common/common_contexts.rst b/doc/kernel/common/common_contexts.rst deleted file mode 100644 index 569ccf5d0b8..00000000000 --- a/doc/kernel/common/common_contexts.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. _common_contexts: - -Execution Context Services -########################## - -Concepts -******** - -Every kernel execution context has an associated *type* that indicates whether -the context is a task, a fiber, or the kernel's interrupt handling context. - -All task and fiber contexts have a unique *thread identifier* value used to -uniquely identify them. Each task and fiber can also support a 32-bit *thread -custom data* value. This value is accessible only by the task or fiber itself, -and may be used by the application for any purpose. The default custom data -value for a task or fiber is zero. - -.. note:: - The custom data value is not available to ISRs because these operate - only within the shared kernel interrupt handling context. - -The kernel permits a task or a fiber to perform a ``busy wait``, thus delaying -its processing for a specified time period. Such a delay occurs without -requiring the kernel to perform context switching, as it typically does with -timer and timeout services. - - -Purpose -******* - -Use kernel execution context services when writing code that should -operate differently when it is executed by different contexts. - -Use the ``busy wait`` service when the required delay is too short to -warrant context switching to another task or fiber. The ``busy wait`` -service may also be used when performing a delay as part of the -nanokernel's background task in a nanokernel-only system; this task is -not allowed to voluntarily relinquish the CPU. - - -Usage -***** - -Configuring Custom Data Support -=============================== - -Use the :option:`CONFIG_THREAD_CUSTOM_DATA` configuration option -to enable support for thread custom data. By default, custom data -support is disabled. - - -Example: Performing Execution Context-Specific Processing -========================================================= - -This code shows how a routine can use a thread's custom data value -to limit the number of times a thread may call the routine. Note that -counting is not performed when the routine is called by an ISR; ISRs -do not have a custom data value. - -.. note:: - Obviously, only a single routine can use this technique - since it monopolizes the use of the custom data value. - -.. code-block:: c - - #define CALL_LIMIT 7 - - int call_tracking_routine(void) - { - uint32_t call_count; - - if (sys_execution_context_type_get() != NANO_CTX_ISR) { - call_count = (uint32_t)sys_thread_custom_data_get(); - if (call_count == CALL_LIMIT) - return -1; - call_count++; - sys_thread_custom_data_set((void *)call_count); - } - - /* do rest of routine's processing */ - ... - } - -APIs -**** - -The following kernel execution context APIs are common to both -:file:`microkernel.h` and :file:`nanokernel.h`: - - -:c:func:`sys_thread_self_get()` - Gets thread identifier of currently executing task or fiber. - -:c:func:`sys_execution_context_type_get()` - Gets type of currently executing context (i.e. task, fiber, or ISR). - -:c:func:`sys_thread_custom_data_set()` - Writes custom data for currently executing task or fiber. - -:c:func:`sys_thread_custom_data_get()` - Reads custom data for currently executing task or fiber. diff --git a/doc/kernel/common/common_float.rst b/doc/kernel/common/common_float.rst deleted file mode 100644 index b9250013a31..00000000000 --- a/doc/kernel/common/common_float.rst +++ /dev/null @@ -1,198 +0,0 @@ -.. _common_float: - -Floating Point Services -####################### - -.. note:: - Floating point services are currently available only for boards - based on the ARM Cortex-M4 or the Intel x86 architectures. The - services provided are architecture specific. - -Concepts -******** - -The kernel allows an application's tasks and fibers to use floating point -registers on board configurations that support these registers. - -.. note:: - The kernel does not support the use of floating point registers by ISRs. - -The kernel can be configured to provide only the floating point services -required by an application. Three modes of operation are supported, -which are described below. In addition, the kernel's support for the SSE -registers can be included or omitted, as desired. - -No FP registers mode -==================== - -This mode is used when the application has no tasks or fibers that use -floating point registers. It is the kernel's default floating point services -mode. - -If a task or fiber uses any floating point register, -the kernel generates a fatal error condition and aborts the thread. - -Unshared FP registers mode -========================== - -This mode is used when the application has only a single task or fiber -that uses floating point registers. - -The kernel initializes the floating point registers so they can be used -by any task or fiber. The floating point registers are left unchanged -whenever a context switch occurs. - -.. note:: - Incorrect operation may result if two or more tasks or fibers use - floating point registers, as the kernel does not attempt to detect - (or prevent) multiple threads from using these registers. - -Shared FP registers mode -======================== - -This mode is used when the application has two or more threads that use -floating point registers. Depending upon the underlying CPU architecture, -the kernel supports one or more of the following thread sub-classes: - -* non-user: A thread that cannot use any floating point registers - -* FPU user: A thread that can use the standard floating point registers - -* SSE user: A thread that can use both the standard floating point registers - and SSE registers - -The kernel initializes the floating point registers so they can be used -by any task or fiber, then saves and restores these registers during -context switches to ensure the computations performed by each FPU user -or SSE user are not impacted by the computations performed by the other users. - -On the ARM Cortex-M4 architecture the kernel treats *all* tasks and fibers -as FPU users when shared FP registers mode is enabled. This means that the -floating point registers are saved and restored during a context switch, even -when the associated threads are not using them. Each task and fiber must -provide an extra 132 bytes of stack space where these register values can -be saved. - -On the x86 architecture the kernel treats each task and fiber as a non-user, -FPU user or SSE user on a case-by-case basis. A "lazy save" algorithm is used -during context switching which updates the floating point registers only when -it is absolutely necessary. For example, the registers are *not* saved when -switching from an FPU user to a non-user thread, and then back to the original -FPU user. The following table indicates the amount of additional stack space a -thread must provide so the registers can be saved properly. - -=========== =============== ========================== -Thread type FP register use Extra stack space required -=========== =============== ========================== -fiber any 0 bytes -task none 0 bytes -task FPU 108 bytes -task SSE 464 bytes -=========== =============== ========================== - -The x86 kernel automatically detects that a given task or fiber is using -the floating point registers the first time the thread accesses them. -The thread is tagged as an SSE user if the kernel has been configured -to support the SSE registers, or as an FPU user if the SSE registers are -not supported. If this would result in a thread that is an FPU user being -tagged as an SSE user, or if the application wants to avoid the exception -handling overhead involved in auto-tagging threads, it is possible to -pre-tag a thread using one of the techniques listed below. - -* An x86 task or fiber can tag itself as an FPU user or SSE user by calling - :c:func:`task_float_enable()` or :c:func:`fiber_float_enable()` - once it has started executing. - -* An x86 fiber can be tagged as an FPU user or SSE user by its creator - by calling :c:func:`fiber_start()` with the :c:macro:`USE_FP` or - :c:macro:`USE_SSE` option, respectively. - -* A microkernel task can be tagged as an FPU user or SSE user by adding it - to the :c:macro:`FPU` task group or the :c:macro:`SSE` task group - when the task is defined. - -.. note:: - Adding the task to the :c:macro:`FPU` or :c:macro:`SSE` task groups - by calling :c:func:`task_group_join()` does *not* tag the task - as an FPU user or SSE user. - -If an x86 thread uses the floating point registers infrequently it can call -:c:func:`task_float_disable()` or :c:func:`fiber_float_disable()` as -appropriate to remove its tagging as an FPU user or SSE user. This eliminates -the need for the kernel to take steps to preserve the contents of the floating -point registers during context switches when there is no need to do so. -When the thread again needs to use the floating point registers it can re-tag -itself as an FPU user or SSE user using one of the techniques listed above. - - -Purpose -******* - -Use the kernel floating point services when an application needs to -perform floating point operations. - - -Usage -***** - -Configuring Floating Point Services -=================================== - -To configure unshared FP registers mode, enable the :option:`CONFIG_FLOAT` -configuration option and leave the :option:`CONFIG_FP_SHARING` configuration option -disabled. - -To configure shared FP registers mode, enable both the :option:`CONFIG_FLOAT` -configuration option and the :option:`CONFIG_FP_SHARING` configuration option. -Also, ensure that any task that uses the floating point registers has -sufficient added stack space for saving floating point register values -during context switches, as described above. - -Use the :option:`CONFIG_SSE` configuration option to enable support for -SSEx instructions (x86 only). - - -Example: Performing Floating Point Arithmetic -============================================= -This code shows how a routine can use floating point arithmetic to avoid -overflow issues when computing the average of a series of integer values. -Note that no special coding is required if the kernel is properly configured. - -.. code-block:: c - - int average(int *values, int num_values) - { - double sum; - int i; - - sum = 0.0; - - for (i = 0; i < num_values; i++) { - sum += *values; - values++; - } - - return (int)((sum / num_values) + 0.5); - } - -APIs -**** - -The following floating point services APIs (x86 only) are provided by -:file:`microkernel.h` and by :file:`nanokernel.h`: - -:c:func:`fiber_float_enable()` - Tells the kernel that the specified task or fiber is now an FPU user - or SSE user. - -:c:func:`task_float_enable()` - Tells the kernel that the specified task or fiber is now an FPU user - or SSE user. - -:c:func:`fiber_float_disable()` - Tells the kernel that the specified task or fiber is no longer an FPU user - or SSE user. - -:c:func:`task_float_disable()` - Tells the kernel that the specified task or fiber is no longer an FPU user - or SSE user. diff --git a/doc/kernel/common/common_kernel_clocks.rst b/doc/kernel/common/common_kernel_clocks.rst deleted file mode 100644 index 07a4874e884..00000000000 --- a/doc/kernel/common/common_kernel_clocks.rst +++ /dev/null @@ -1,144 +0,0 @@ -.. _common_kernel_clocks: - -Kernel Clocks -############# - -Concepts -******** - -The kernel supports two distinct clocks. - -* A 64-bit *system clock*, which is the foundation for the kernel's - time-based services. This clock is a counter measured in *ticks*, - and increments at a frequency determined by the application. - - The kernel allows this clock to be accessed directly by reading - the timer. It can also be accessed indirectly by using a kernel - timer or timeout capability. - -* A 32-bit *hardware clock*, which is used as the source of the ticks - for the system clock. This clock is a counter measured in unspecified - units (called *cycles*), and increments at a frequency determined by - the hardware. - - The kernel allows this clock to be accessed directly by reading - the timer. - -The kernel also provides a number of variables that can be used -to convert the time units used by the clocks into standard time units -(e.g. seconds, milliseconds, nanoseconds, etc), and to convert between -the two types of clock time units. - -Purpose -******* - -Use the system clock for time-based processing that does not require -high precision, such as implementing time limits or time delays. - -Use the hardware clock for time-based processing that requires higher -precision than the system clock can provide, such as fine-grained -time measurements. - -.. note:: - The high frequency of the hardware clock, combined with its 32-bit size, - means that counter rollover must be taken into account when taking - high-precision measurements over an extended period of time. - -Usage -***** - -Configuring the Kernel Clocks -============================= - -Use the :option:`CONFIG_SYS_CLOCK_TICKS_PER_SEC` configuration option -to specify how many ticks occur every second. Setting this value -to zero disables all system clock and hardware clock capabilities. - -.. note:: - Making the system clock frequency value larger allows the system clock - to provide finer-grained timing, but also increases the amount of work - the kernel has to do to process ticks (since they occur more frequently). - -Example: Measuring Time with Normal Precision -============================================= -This code uses the system clock to determine how many ticks have elapsed -between two points in time. - -.. code-block:: c - - int64_t time_stamp; - int64_t ticks_spent; - - /* capture initial time stamp */ - time_stamp = sys_tick_get(); - - /* do work for some (extended) period of time */ - ... - - /* compute how long the work took & update time stamp */ - ticks_spent = sys_tick_delta(&time_stamp); - -Example: Measuring Time with High Precision -=========================================== -This code uses the hardware clock to determine how many ticks have elapsed -between two points in time. - -.. code-block:: c - - uint32_t start_time; - uint32_t stop_time; - uint32_t cycles_spent; - uint32_t nanoseconds_spent; - - /* capture initial time stamp */ - start_time = sys_cycle_get_32(); - - /* do work for some (short) period of time */ - ... - - /* capture final time stamp */ - stop_time = sys_cycle_get_32(); - - /* compute how long the work took (assumes no counter rollover) */ - cycles_spent = stop_time - start_time; - nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(cycles_spent); - - -APIs -**** - -Kernel clock APIs provided by :file:`microkernel.h` -=================================================== - -:cpp:func:`sys_tick_get()`, :cpp:func:`sys_tick_get_32()` - Read the system clock. - -:cpp:func:`sys_tick_delta()`, :cpp:func:`sys_tick_delta_32()` - Compute the elapsed time since an earlier system clock reading. - -Kernel clock APIs common to both :file:`microkernel.h`and :file:`nanokernel.h` -============================================================================== - -:cpp:func:`sys_tick_get()`, :cpp:func:`sys_tick_get_32()` - Read the system clock. - -:cpp:func:`sys_tick_delta()`, :cpp:func:`sys_tick_delta_32()` - Compute the elapsed time since an earlier system clock reading. - -:cpp:func:`sys_cycle_get_32()` - Read hardware clock. - -Kernel clock variables common to both :file:`microkernel.h` and :file:`nanokernel.h` -==================================================================================== - -:c:data:`sys_clock_ticks_per_sec` - The number of system clock ticks in a single second. - -:c:data:`sys_clock_hw_cycles_per_sec` - The number of hardware clock cycles in a single second. - -:c:data:`sys_clock_us_per_tick` - The number of microseconds in a single system clock tick. - -:c:data:`sys_clock_hw_cycles_per_tick` - The number of hardware clock cycles in a single system clock tick. diff --git a/doc/kernel/kernel.rst b/doc/kernel/kernel.rst deleted file mode 100644 index bfae023aa4f..00000000000 --- a/doc/kernel/kernel.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _kernel: - -Zephyr Kernel Primer -#################### - -This section describes the major features of the Zephyr kernel -and how to use them. - -.. toctree:: - :maxdepth: 2 - - overview/overview.rst - common/common.rst - microkernel/microkernel.rst - nanokernel/nanokernel.rst - -.. rubric:: Abbreviations - -+---------------+-------------------------------------------------------------------+ -| Abbreviations | Definition | -+===============+===================================================================+ -| API | Application Program Interface: typically a defined set | -| | of routines and protocols for building software inputs and output | -| | mechanisms. | -+---------------+-------------------------------------------------------------------+ -| ISR | Interrupt Service Routine | -+---------------+-------------------------------------------------------------------+ -| IDT | Interrupt Descriptor Table | -+---------------+-------------------------------------------------------------------+ -| XIP | eXecute In Place | -+---------------+-------------------------------------------------------------------+ diff --git a/doc/kernel/microkernel/microkernel.rst b/doc/kernel/microkernel/microkernel.rst deleted file mode 100644 index bebfb31d656..00000000000 --- a/doc/kernel/microkernel/microkernel.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _microkernel: - -Microkernel Services -#################### - -This section describes the various services provided by the microkernel. -These services are available in microkernel applications, but not -nanokernel applications. - -.. toctree:: - :maxdepth: 1 - - microkernel_tasks - microkernel_fibers.rst - microkernel_timers - microkernel_memory - microkernel_synchronization - microkernel_data diff --git a/doc/kernel/microkernel/microkernel_data.rst b/doc/kernel/microkernel/microkernel_data.rst deleted file mode 100644 index 7c379597717..00000000000 --- a/doc/kernel/microkernel/microkernel_data.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _microkernel_data: - -Data Passing Services -##################### - -This section contains the information about all data passing services available in the microkernel. - -.. toctree:: - :maxdepth: 2 - - microkernel_fifos - microkernel_mailboxes - microkernel_pipes \ No newline at end of file diff --git a/doc/kernel/microkernel/microkernel_events.rst b/doc/kernel/microkernel/microkernel_events.rst deleted file mode 100644 index 5d37072b006..00000000000 --- a/doc/kernel/microkernel/microkernel_events.rst +++ /dev/null @@ -1,232 +0,0 @@ -.. _microkernel_events: - -Events -###### - -Concepts -******** - -The microkernel's :dfn:`event` objects are an implementation of traditional -binary semaphores. - -Any number of events can be defined in a microkernel system. An event is -typically *sent* by a task, fiber, or ISR and *received* by a task, which then -takes some action in response. Events are the easiest and most efficient way to -synchronize operations between two different execution contexts. - -Each event has a **name** that uniquely identifies it, and an associated -**event state**. Each event starts off in the ``clear`` state. Once that event -gets sent, it is placed into the ``set`` state (where it remains) until it is -received. When the event is received, it reverts back to the ``clear`` state. - -Sending an event that is already set is permitted; however, this does not affect -the existing state, it and does not allow the receiving task to recognize whether -the event has been sent more than once. - -The receiving task can test the state of an event and decide whether or not -to block it. The kernel allows only a single receiving task to wait for a given -event; if a second task attempts to wait, its receive operation immediately -returns a failure indication. - -Each event also has an optional **event handler** function, which is executed -by the microkernel server fiber when the event is sent. An event handler -function lets an event be processed without requiring the kernel to schedule -a receiving task; this allows an event to be processed more quickly. - -When an event handler determines that the event can be ignored, or that it -can process the event without the assistance of a task, the event handler -returns a value of zero, and the event's state is left unchanged. When an event -handler determines that additional processing *is* required, it returns a -non-zero value, and the event's state is changed to *set* (if it isn't already -set). - -An event handler function can be used to improve the efficiency of event -processing by the receiving task. In some situations, event handlers can even -eliminate the need for a receiving task. Any event that does not require -an event handler can specify the :c:macro:`NULL` function. The event handler -function is passed the name of the event being sent each time it is invoked, -allowing the same function to be shared by multiple events. An event's event -handler function is specified at compile-time, but can be changed subsequently -at run-time. - -Purpose -******* - -Use an event to signal a task to take action in response to a condition -detected by another task, a fiber, or an ISR. - -Use an event handler to allow the microkernel server fiber to handle an event, -prior to (or instead of) letting a task handle the event. - -Usage -***** - -Defining an Event -================= - -The following parameters must be defined: - - *name* - This specifies a unique name for the event. - - *handler* - This specifies the name of the event handler function, - which should have the following form: - - .. code-block:: c - - int (int event) - { - /* start handling event; return zero if all done, */ - /* or non-zero to let receiving task handle event */ - ... - } - - If no event handler is required specify :c:macro:`NULL`. - -Public Event ------------- - -Define the event in the application's MDEF using the following syntax: - -.. code-block:: console - - EVENT name handler - -For example, the file :file:`projName.mdef` defines two events as follows: - -.. code-block:: console - - % EVENT NAME ENTRY - % ========================================== - EVENT KEYPRESS validate_keypress - EVENT BUTTONPRESS NULL - -A public event can be referenced by name from any source file that includes -the file :file:`zephyr.h`. - -Private Event -------------- - -Define the event in a source file with the following syntax: - -.. code-block:: c - - DEFINE_EVENT(name, handler); - - -Example: Defining a Private Event, Enabling it from Elsewhere in the Application -================================================================================ - -This code defines a private event named ``PRIV_EVENT`` which has no associated -event handler function. - -.. code-block:: c - - DEFINE_EVENT(PRIV_EVENT, NULL); - -To enable this event from a different source file, use the following syntax: - -.. code-block:: c - - extern const kevent_t PRIV_EVENT; - - -Example: Signaling an Event from an ISR -======================================= - -This code signals an event during the processing of an interrupt. - -.. code-block:: c - - void keypress_interrupt_handler(void *arg) - { - ... - isr_event_signal(KEYPRESS); - ... - } - -Example: Consuming an Event using a Task -======================================== - -This code processes events of a single type using a task. - -.. code-block:: c - - void keypress_task(void) - { - /* consume key presses */ - while (1) { - - /* wait for a key press to be signalled */ - task_event_recv(KEYPRESS, TICKS_NONE); - - /* determine what key was pressed */ - char c = get_keypress(); - - /* process key press */ - ... - } - } - -Example: Filtering Event Signals using an Event Handler -======================================================= - -This code registers an event handler to filter out unwanted events, -allowing the receiving task to wake up only when needed. - -.. code-block:: c - - int validate_keypress(int event_id_is_unused) - { - /* determine what key was pressed */ - char c = get_keypress(); - - /* signal task only if key pressed was a digit */ - if ((c >= '0') && (c <= '9')) { - /* save key press information */ - ... - /* event is signalled to task */ - return 1; - } else { - /* event is not signalled to task */ - return 0; - } - } - - void keypress_task(void) - { - /* register the filtering routine */ - task_event_handler_set(KEYPRESS, validate_keypress); - - /* consume key presses */ - while (1) { - - /* wait for a key press to be signalled */ - task_event_recv(KEYPRESS, TICKS_NONE); - - /* process saved key press, which must be a digit */ - ... - } - } - -APIs -**** - -Event APIs provided by :file:`microkernel.h` -============================================ - -:cpp:func:`isr_event_send()` - Signal an event from an ISR. - -:cpp:func:`fiber_event_send()` - Signal an event from a fiber. - -:cpp:func:`task_event_send()` - Signal an event from a task. - -:cpp:func:`task_event_recv()` - Wait for an event signal for a specified time period. - -:cpp:func:`task_event_handler_set()` - Register an event handler function for an event. diff --git a/doc/kernel/microkernel/microkernel_fibers.rst b/doc/kernel/microkernel/microkernel_fibers.rst deleted file mode 100644 index 82ca8a13b86..00000000000 --- a/doc/kernel/microkernel/microkernel_fibers.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. _microkernel_fibers: - -Fiber Services -############## - -Concepts -******** - -A :dfn:`fiber` is a lightweight, non-preemptible thread of execution that -implements a portion of an application's processing. Fiber-based services are -often used in device drivers and for performance-critical work. - -A microkernel application can use all of the fiber capabilities that are -available to a nanokernel application; for more information see -:ref:`nanokernel_fibers`. - -While a fiber often uses one or more nanokernel object types to carry -out its work, it also can interact with microkernel events and semaphores -to a limited degree. For example, a fiber can signal a task by giving a -microkernel semaphore, but it cannot take a microkernel semaphore. For more -information see :ref:`microkernel_events` and :ref:`microkernel_semaphores`. - - -.. _microkernel_server_fiber: - -Microkernel Server Fiber -======================== - -The microkernel automatically spawns a system thread, known as the -*microkernel server* fiber, which performs most operations involving -microkernel objects. The nanokernel scheduler decides which fibers -get scheduled and when; it will schedule the microkernel server fiber -when there are no fibers of a higher priority. - -By default, the microkernel server fiber has priority 0 (that is, -the highest priority). However, this can be changed. If you drop its -priority, the nanokernel scheduler will give precedence to other, -higher-priority fibers, such as time-sensitive device driver or -application fibers. - -Both the fiber's stack size and scheduling priority can be configured -with the :option:`CONFIG_MICROKERNEL_SERVER_STACK_SIZE` and -:option:`CONFIG_MICROKERNEL_SERVER_PRIORITY` configuration options, -respectively. - - -See also :ref:`microkernel_server`. diff --git a/doc/kernel/microkernel/microkernel_fifos.rst b/doc/kernel/microkernel/microkernel_fifos.rst deleted file mode 100644 index 97b6448a379..00000000000 --- a/doc/kernel/microkernel/microkernel_fifos.rst +++ /dev/null @@ -1,193 +0,0 @@ -.. _microkernel_fifos: - -FIFOs -##### - -Concepts -******** - -The microkernel's :dfn:`FIFO` object type is an implementation of a traditional -first in, first out queue. - -A FIFO allows tasks to asynchronously send and receive fixed-size data items. -Each FIFO has an associated ring buffer used to hold data items that have been -sent but not yet received. - -Any number of FIFOs can be defined in a microkernel system. Each FIFO needs: - -* A **name** that uniquely identifies it. -* A **maximum quantity** of data items that can be queued in its ring buffer. -* The **data item size**, measured in bytes, of each data item it can handle. - - -A task sends a data item by specifying a pointer to an area containing the data -to be sent; the size of the data area must equal the FIFO's data item size. -The data is either given directly to a receiving task (if one is waiting), or -copied to the FIFO's ring buffer (if space is available). When a FIFO is full, -the sending task can wait for space to become available. - -Any number of tasks may wait on a full FIFO simultaneously; when space for -a data item becomes available, that space is given to the highest-priority -task that has waited the longest. - -A task receives a data item by specifying a pointer to an area to receive -the data; the size of the receiving area must equal the FIFO's data item size. -The data is copied from the FIFO's ring buffer (if it contains data items) -or taken directly from a sending task (if the FIFO is empty). When a FIFO -is empty the task may choose to wait for a data item to become available. - -Any number of tasks may wait on an empty FIFO simultaneously; when a data item -becomes available it is given to the highest priority task that has waited -the longest. - -Purpose -******* - -Use a FIFO to transfer small data items between tasks in an asynchronous and -anonymous manner. - -.. note:: - A FIFO can be used to transfer large data items, if desired. However, - it is often preferable to send pointers to large data items to avoid - copying the data. The microkernel's memory map and memory pool object - types can be helpful for data transfers of this sort. - - A synchronous transfer can be achieved by using the microkernel's mailbox - object type. - - A non-anonymous transfer can be achieved by having the sending task - embed its name in the data it sends, where it can be retrieved by - the receiving task. However, there is no straightforward way for the - sending task to determine the name of the task that received its data. - The microkernel's mailbox object type *does* support non-anonymous data - transfer. - -Usage -***** - -Defining a FIFO -=============== - -The following parameters must be defined: - - *name* - This specifies a unique name for the FIFO. - - *depth* - This specifies the maximum number of data items - that can exist at any one time. - - *width* - This specifies the size (in bytes) of each data item. - -Public FIFO ------------ - -Define the FIFO in the application's :file:`.MDEF` file with the -following syntax: - -.. code-block:: console - - FIFO name depth width - -For example, the file :file:`projName.mdef` defines a FIFO -that holds up to 10 items that are each 12 bytes long as follows: - -.. code-block:: console - - % FIFO NAME DEPTH WIDTH - % ============================= - FIFO SIGNAL_FIFO 10 12 - -A public FIFO can be referenced by name from any source file that includes -the file :file:`zephyr.h`. - -Private FIFO ------------- - -Define the FIFO in a source file using the following syntax: - -.. code-block:: c - - DEFINE_FIFO(fifo_name, depth, width) - -For example, the following code defines a private FIFO named ``PRIV_FIFO``. - -.. code-block:: c - - DEFINE_FIFO(PRIV_FIFO, 10, 12); - -To access this FIFO from a different source file, use the following syntax: - -.. code-block:: c - - extern const kfifo_t PRIV_FIFO; - -Example: Writing to a FIFO -========================== - -This code uses a FIFO to pass data items from a producing task to -one or more consuming tasks. If the FIFO fills up because the consumers -can't keep up, throw away all existing data so newer data can be saved. - -.. code-block:: c - - void producer_task(void) - { - struct data_item_t data; - - while (1) { - /* create data item to send (e.g. measurement, timestamp, ...) */ - data = ... - - /* send data to consumers */ - while (task_fifo_put(SIGNAL_FIFO, &data, TICKS_NONE) != RC_OK) { - /* FIFO is full */ - task_fifo_purge(SIGNAL_FIFO); - } - - /* data item was successfully added to FIFO */ - } - } - -Example: Reading from a FIFO -============================ - -This code uses a FIFO to process data items generated by one or more -producing tasks. - -.. code-block:: c - - void consumer_task(void) - { - struct data_item_t data; - - while (1) { - /* get a data item */ - task_fifo_get(SIGNAL_FIFO, &data, TICKS_UNLIMITED); - - /* process data item */ - ... - } - } - -APIs -**** - -FIFO APIs provided by :file:`microkernel.h` -=========================================== - -:cpp:func:`task_fifo_put()` - Write item to a FIFO, or wait for a specified time period if the FIFO is - full. - -:cpp:func:`task_fifo_get()` - Read item from a FIFO, or wait for a specified time period if the FIFO is - empty. - -:c:func:`task_fifo_purge()` - Discard all items in a FIFO and unblock any tasks waiting to read or write - an item. - -:c:func:`task_fifo_size_get()` - Read the number of items currently in a FIFO. diff --git a/doc/kernel/microkernel/microkernel_mailboxes.rst b/doc/kernel/microkernel/microkernel_mailboxes.rst deleted file mode 100644 index de92bf7a4fe..00000000000 --- a/doc/kernel/microkernel/microkernel_mailboxes.rst +++ /dev/null @@ -1,645 +0,0 @@ -.. _microkernel_mailboxes: - -Mailboxes -######### - -Concepts -******** - -The microkernel's :dfn:`mailbox` object type is an implementation of a -traditional message queue. - -A mailbox allows tasks to exchange messages. A task that sends a message is -known as the *sending task*, while a task that receives the message is known -as the *receiving task*. Messages may not be sent or received by fibers or -ISRs, nor may a given message be received by more than one task; -point-to-multipoint messaging is not supported. - -A mailbox has a queue of messages that have been sent, but not yet received. -The messages in the queue are sorted by priority, allowing a higher priority -message to be received before a lower priority message that was sent earlier. -Messages of equal priority are handled in a first in, first out manner. - -Any number of mailboxes can be defined in a microkernel system. Each mailbox -needs a **name** that uniquely identifies it. A mailbox does not limit the -number of messages it can queue, nor does it place limits on the size of the -message it handles. - -The content of a message is stored in an array of bytes, called the -*message data*. The size and format of the message data is application-defined, -and can vary from one message to the next. Message data may be stored in a -buffer provided by the task that sends or receives the message, or in a memory -pool block. The message data portion of a message is optional; a message without -any message data is called an *empty message*. - -The life cycle of a message is fairly simple. A message is created when it -is given to a mailbox by the sending task. The message is then owned -by the mailbox until it is given to a receiving task. The receiving task may -retrieve the message data when it receives the message from the mailbox, -or it may perform data retrieval during a second, subsequent mailbox operation. -Only when data retrieval has been performed is the message deleted by the -mailbox. - -A message can be exchanged non-anonymously or anonymously between a :dfn:`sending` -and :dfn:`receiving` task. A sending task can specify the name of the task to which -the message is being sent, or it can specify that any task may receive the message. -Likewise, a receiving task can specify the name of the task from which it wishes to -receive a message, or it can specify that it is willing to receive a message from -any task. A message is exchanged only when the requirements for both the sending task -and receiving task are satisfied; such tasks are said to be *compatible*. - -For example, task A sends a message to task B, but it will be received by task B -only if the latter tries to receive a message from task A (or from any task). The -exchange will not occur if task B tries to receive a message from task C. The message -can never be received by task C, even if it is trying to receive a message from task -A (or from any task). - -Messages can be exchanged :dfn:`synchronously` or :dfn:`asynchronously`. In a -synchronous exchange, the sending task blocks until the message has been fully -processed by the receiving task. In an asynchronous exchange, the sending task -does not wait until the message has been received by another task before continuing; -this allows the task to do other work (such as gather data that will be used -in the next message) *before* the message is given to a receiving task and -fully processed. The technique used for a given message exchange is determined -by the sending task. - -The synchronous exchange technique provides an inherent form of flow control, -preventing a sending task from generating messages faster than they can be -consumed by receiving tasks. The asynchronous exchange technique provides an -optional form of flow control, which allows a sending task to determine -if a previously sent message still exists before sending a subsequent message. - -Message Descriptor -================== - -A :dfn:`message descriptor` is a data structure that specifies where a message's -data is located, and how the message is to be handled by the mailbox. Both the -sending task and the receiving task pass a message descriptor to the mailbox -when accessing a mailbox. The mailbox uses both message descriptors to perform -a message exchange between compatible sending and receiving tasks. The mailbox -also updates some fields of the descriptors during the exchange, allowing both -tasks to know what occurred. - -A message descriptor is a structure of type :c:type:`struct k_msg`. The fields -listed below are available for application use; all other fields are for -kernel use only. - - *info* - - A 32-bit value that is exchanged by the message sender and receiver, - and whose meaning is defined by the application. This exchange is - bi-directional, allowing the sender to pass a value to the receiver - during any message exchange, and allowing the receiver to pass a value - to the sender during a synchronous message exchange. - - *size* - The message data size, in bytes. Set it to zero when sending an empty - message, or when discarding the message data of a received message. - The mailbox updates this field with the actual number of data bytes - exchanged once the message is received. - - *tx_data* - A pointer to the sending task's message data buffer. Set it to - :c:macro:`NULL` when sending a memory pool block, or when sending - an empty message. (Not used when receiving a message.) - - *tx_block* - The descriptor for the memory pool block containing the sending task's - message data. (Not used when sending a message data buffer, - or when sending an empty message. Not used when receiving a message.) - - *rx_data* - A pointer to the receiving task's message data buffer. Set it to - :c:macro:`NULL` when the message's data is not wanted, or when it will be - retrieved by a subsequent mailbox operation. (Not used when sending - a message.) - - *tx_task* - The name of the sending task. Set it to :c:macro:`ANYTASK` to receive - a message sent by any task. The mailbox updates this field with the - actual sender's name once the message is received. (Not used when - sending a message.) - - *rx_task* - The name of the receiving task. Set it to :c:macro:`ANYTASK` to allow - any task to receive the message. The mailbox updates this field with - the actual receiver's name once the message is received, but only if - the message is sent synchronously. (Not used when receiving a message.) - -Sending a Message -================= - -A task sends a message by first creating the message data to be sent (if any). -The data may be placed in a message buffer -- such as an array or structure -variable -- whose contents are copied to an area supplied by the receiving task -during the message exchange. Alternatively, the data may be placed in a block -allocated from a memory pool, which gets handed off to the receiving task -during the exchange. A message buffer is typically used when the data volume -flowing through is small, and the cost of copying the data is less than the -cost of allocating and freeing a memory pool block. A memory pool block *must* -be used when a non-empty message is sent asynchronously. - -Next, the task creates a message descriptor that characterizes the message -to be sent, as described in the previous section. - -Finally, the task calls one of the mailbox send APIs to initiate the -message exchange. The message is immediately given to a compatible receiving -task, if one is currently waiting for a message. Otherwise, the message is added -to the mailbox's queue of messages, according to the priority specified by -the sending task. Typically, a sending task sets the message priority to -its own task priority level, allowing messages sent by higher priority tasks -to take precedence over those sent by lower priority tasks. - -For a synchronous send operation, the operation normally completes when a -receiving task has both received the message and retrieved the message data. -If the message is not received before the waiting period specified by the -sending task is reached, the message is removed from the mailbox's queue -and the sending task continues processing. When a send operation completes -successfully the sending task can examine the message descriptor to determine -which task received the message and how much data was exchanged, as well as -the application-defined info value supplied by the receiving task. - -.. note:: - A synchronous send operation may block the sending task indefinitely -- even - when the task specifies a maximum waiting period -- since the waiting period - only limits how long the mailbox waits before the message is received - by another task. Once a message is received there is no limit to the time - the receiving task may take to retrieve the message data and unblock - the sending task. - -For an asynchronous send operation, the operation always completes immediately. -This allows the sending task to continue processing regardless of whether the -message is immediately given to a receiving task or is queued by the mailbox. -The sending task may optionally specify a semaphore that the mailbox gives -when the message is deleted by the mailbox (for example, when the message has been -received and its data retrieved by a receiving task). The use of a semaphore -allows the sending task to easily implement a flow control mechanism that -ensures that the mailbox holds no more than an application-specified number -of messages from a sending task (or set of sending tasks) at any point in time. - -Receiving a Message -=================== - -A task receives a message by first creating a message descriptor that -characterizes the message it wants to receive. It then calls one of the -mailbox receive APIs. The mailbox searches its queue of messages -and takes the first one it finds that satisfies both the sending and -receiving tasks' message descriptor criteria. If no compatible message -exists, the receiving task may choose to wait for one to be sent. If no -compatible message appears before the waiting period specified -by the receiving task is reached, the receive operation fails and -the receiving task continues processing. Once a receive operation completes -successfully the receiving task can examine the message descriptor -to determine which task sent the message, how much data was exchanged, -and the application-defined info value supplied by the sending task. - -The receiving task controls both the quantity of data it retrieves from an -incoming message and where the data ends up. The task may choose to take -all of the data in the message, to take only the initial part of the data, -or to take no data at all. Similarly, the task may choose to have the data -copied into a buffer area of its choice or to have it placed in a memory -pool block. A message buffer is typically used when the volume of data -involved is small, and the cost of copying the data is less than the cost -of allocating and freeing a memory pool block. - -The following sections outline various approaches a receiving task may use -when retrieving message data. - -Retrieving Data Immediately into a Buffer ------------------------------------------ - -The most straightforward way for a task to retrieve message data is to -specify a buffer when the message is received. The task indicates -both the location of the buffer (which must not be :c:macro:`NULL`) -and its size (which must be greater than zero). - -The mailbox copies the message's data to the buffer as part of the -receive operation. If the buffer is not big enough to contain all of the -message's data, any uncopied data is lost. If the message is not big enough -to fill all of the buffer with data, the unused portion of the buffer is -left unchanged. In all cases the mailbox updates the receiving task's -message descriptor to indicate how many data bytes were copied (if any). - -The immediate data retrieval technique is best suited for applications involving -small messages where the maximum size of a message is known in advance. - -.. note:: - This technique can be used when the message data is actually located - in a memory pool block supplied by the sending task. The mailbox copies - the data into the buffer specified by the receiving task, then automatically - frees the block back to its memory pool. This allows a receiving task - to retrieve message data without having to know whether the data - was sent using a buffer or a block. - -Retrieving Data Subsequently into a Buffer ------------------------------------------- - -A receiving task may choose to retrieve no message data at the time the message -is received, so that it can retrieve the data into a buffer at a later time. -The task does this by specifying a buffer location of :c:macro:`NULL` -and a size indicating the maximum amount of data it is willing to retrieve -later (which must be greater than or equal to zero). - -The mailbox does not copy any message data as part of the receive operation. -However, the mailbox still updates the receiving task's message descriptor -to indicate how many data bytes are available for retrieval. - -The receiving task must then respond as follows: - -* If the message descriptor size is zero, then either the received message is - an empty message or the receiving task did not want to receive any - message data. The receiving task does not need to take any further action - since the mailbox has already completed data retrieval and deleted the - message. - -* If the message descriptor size is non-zero and the receiving task still - wants to retrieve the data, the task must supply a buffer large enough - to hold the data. The task first sets the message descriptor's - *rx_data* field to the address of the buffer, then calls - :c:func:`task_mbox_data_get()`. This instructs the mailbox to copy the data - and delete the message. - -* If the message descriptor size is non-zero and the receiving task does *not* - want to retrieve the data, the task sets the message descriptor's - *size* field to zero and calls :c:func:`task_mbox_data_get()`. - This instructs the mailbox to delete the message without copying the data. - -The subsequent data retrieval technique is suitable for applications where -immediate retrieval of message data is undesirable. For example, it can be -used when memory limitations make it impractical for the receiving task to -always supply a buffer capable of holding the largest possible incoming message. - -.. note:: - This technique can be used when the message data is actually located - in a memory pool block supplied by the sending task. The mailbox copies - the data into the buffer specified by the receiving task, then automatically - frees the block back to its memory pool. This allows a receiving task - to retrieve message data without having to know whether the data - was sent using a buffer or a block. - -Retrieving Data Subsequently into a Block ------------------------------------------ - -A receiving task may choose to retrieve message data into a memory pool block, -rather than a buffer area of its choice. This is done in much the same way -as retrieving data subsequently into a buffer---the receiving task first -receives the message without its data, then retrieves the data by calling -:c:func:`task_mbox_data_block_get()`. The latter call fills in the block -descriptor supplied by the receiving task, allowing the task to access the data. -This call also causes the mailbox to delete the received message, since -data retrieval has been completed. The receiving task is then responsible -for freeing the block back to the memory pool when the data is no longer needed. - -This technique is best suited for applications where the message data has -been sent using a memory pool block, either because a large amount of data -is involved or because the message was sent asynchronously. - -.. note:: - This technique can be used when the message data is located in a buffer - supplied by the sending task. The mailbox automatically allocates a memory - pool block and copies the message data into it. However, this is much less - efficient than simply retrieving the data into a buffer supplied by the - receiving task. In addition, the receiving task must be designed to handle - cases where the data retrieval operation fails because the mailbox cannot - allocate a suitable block from the memory pool. If such cases are possible, - the receiving task can call :c:func:`task_mbox_data_block_get_wait()` or - :c:func:`task_mbox_data_block_get_wait_timeout()` to permit the task to wait - until a suitable block can be allocated. Alternatively, the task can use - :c:func:`task_mbox_data_get()` to inform the mailbox that it no longer wishes - to receive the data at all, allowing the mailbox to release the message. - -Purpose -******* - -Use a mailbox to transfer data items between tasks whenever the capabilities -of a FIFO are insufficient. - - -Usage -***** - -Defining a Mailbox -================== - -The following parameters must be defined: - - *name* - This specifies a unique name for the mailbox. - -Public Mailbox --------------- - -Define the mailbox in the application's MDEF using the following syntax: - -.. code-block:: console - - MAILBOX name - -For example, the file :file:`projName.mdef` defines a mailbox as follows: - -.. code-block:: console - - % MAILBOX NAME - % ========================== - MAILBOX REQUEST_BOX - -A public mailbox can be referenced by name from any source file that -includes the file :file:`zephyr.h`. - -Private Mailbox ---------------- - -Define the mailbox in a source file using the following syntax: - -.. code-block:: c - - DEFINE_MAILBOX(name); - -For example, the following code defines a private mailbox named ``PRIV_MBX``. - -.. code-block:: c - - DEFINE_MAILBOX(PRIV_MBX); - -The mailbox ``PRIV_MBX`` can be used in the same style as those -defined in the MDEF. - -To use this mailbox from a different source file use the following syntax: - -.. code-block:: c - - extern const kmbox_t PRIV_MBX; - -Example: Sending a Variable-Sized Mailbox Message -================================================= - -This code uses a mailbox to synchronously pass variable-sized requests -from a producing task to any consuming task that wants it. The message -"info" field is used to exchange information about the maximum size buffer -that each task can handle. - -.. code-block:: c - - void producer_task(void) - { - char buffer[100]; - int buffer_bytes_used; - - struct k_msg send_msg; - k_priority_t send_priority = task_priority_get(); - - while (1) { - - /* generate data to send */ - ... - buffer_bytes_used = ... ; - memcpy(buffer, source, buffer_bytes_used); - - /* prepare to send message */ - send_msg.info = buffer_bytes_used; - send_msg.size = buffer_bytes_used; - send_msg.tx_data = buffer; - send_msg.rx_task = ANYTASK; - - /* send message and wait until a consumer receives it */ - task_mbox_put(REQUEST_BOX, send_priority, - &send_msg,TICKS_UNLIMITED); - - /* info, size, and rx_task fields have been updated */ - - /* verify that message data was fully received */ - if (send_msg.size < buffer_bytes_used) { - printf("some message data dropped during transfer!"); - printf("receiver only had room for %d bytes", send_msg.info); - } - } - } - -Example: Receiving a Variable-Sized Mailbox Message -=================================================== - -This code uses a mailbox to process variable-sized requests from any -producing task, using the immediate data retrieval technique. The message -"info" field is used to exchange information about the maximum size buffer -that each task can handle. - -.. code-block:: c - - void consumer_task(void) - { - struct k_msg recv_msg; - char buffer[100]; - - int i; - int total; - - while (1) { - /* prepare to receive message */ - recv_msg.info = 100; - recv_msg.size = 100; - recv_msg.rx_data = buffer; - recv_msg.rx_task = ANYTASK; - - /* get a data item, waiting as long as needed */ - task_mbox_get(REQUEST_BOX, &recv_msg, TICKS_UNLIMITED); - - /* info, size, and tx_task fields have been updated */ - - /* verify that message data was fully received */ - if (recv_msg.info != recv_msg.size) { - printf("some message data dropped during transfer!"); - printf("sender tried to send %d bytes", recv_msg.info); - } - - /* compute sum of all message bytes (from 0 to 100 of them) */ - total = 0; - for (i = 0; i < recv_msg.size; i++) { - total += buffer[i]; - } - } - } - -Example: Sending an Empty Mailbox Message -========================================= - -This code uses a mailbox to synchronously pass 4 byte random values -to any consuming task that wants one. The message "info" field is -large enough to carry the information being exchanged, so the data buffer -portion of the message isn't used. - -.. code-block:: c - - void producer_task(void) - { - struct k_msg send_msg; - k_priority_t send_priority = task_priority_get(); - - while (1) { - - /* generate random value to send */ - uint32_t random_value = sys_rand32_get(); - - /* prepare to send empty message */ - send_msg.info = random_value; - send_msg.size = 0; - send_msg.tx_data = NULL; - send_msg.rx_task = ANYTASK; - - /* send message and wait until a consumer receives it */ - task_mbox_put(REQUEST_BOX, send_priority, - &send_msg, TICKS_UNLIMITED); - - /* no need to examine the receiver's "info" value */ - } - } - -Example: Deferring the Retrieval of Message Data -================================================ - -This code uses a mailbox's subsequent data retrieval mechanism to get message -data from a producing task only if the message meets certain criteria, -thereby eliminating unneeded data copying. The message "info" field supplied -by the sender is used to classify the message. - -.. code-block:: c - - void consumer_task(void) - { - struct k_msg recv_msg; - char buffer[10000]; - - while (1) { - /* prepare to receive message */ - recv_msg.size = 10000; - recv_msg.rx_data = NULL; - recv_msg.rx_task = ANYTASK; - - /* get message, but not its data */ - task_mbox_get(REQUEST_BOX, &recv_msg, TICKS_UNLIMITED); - - /* get message data for only certain types of messages */ - if (is_message_type_ok(recv_msg.info)) { - /* retrieve message data and delete the message */ - recv_msg.rx_data = buffer; - task_mbox_data_get(&recv_msg); - - /* process data in "buffer" */ - ... - } else { - /* ignore message data and delete the message */ - recv_msg.size = 0; - task_mbox_data_get(&recv_msg); - } - } - } - -Example: Sending an Asynchronous Mailbox Message -================================================ - -This code uses a mailbox to send asynchronous messages using memory blocks -obtained from ``TXPOOL``, thereby eliminating unneeded data copying when -exchanging large messages. The optional semaphore capability is used to hold off -the sending of a new message until the previous message has been consumed, -so that a backlog of messages doesn't build up when the consuming task is unable -to keep up. - -.. code-block:: c - - void producer_task(void) - { - struct k_msg send_msg; - kpriority_t send_priority = task_priority_get(); - - volatile char *hw_buffer; - - /* indicate that all previous messages have been processed */ - task_sem_give(MY_SEMA); - - while (1) { - /* allocate memory block that will hold message data */ - task_mem_pool_alloc(&send_msg.tx_block, TXPOOL, - 4096, TICKS_UNLIMITED); - - /* keep saving hardware-generated data in the memory block */ - /* until the previous message has been received by the consumer */ - do { - memcpy(send_msg.tx_block.pointer_to_data, hw_buffer, 4096); - } while (task_sem_take(MY_SEMA, TICKS_NONE) != RC_OK); - - /* finish preparing to send message */ - send_msg.size = 4096; - send_msg.rx_task = ANYTASK; - - /* send message containing most current data and loop around */ - task_mbox_block_put(REQUEST_BOX, send_priority, &send_msg, MY_SEMA); - } - } - -Example: Receiving an Asynchronous Mailbox Message -================================================== - -This code uses a mailbox to receive messages sent asynchronously using a -memory block, thereby eliminating unneeded data copying when processing -a large message. - -.. code-block:: c - - void consumer_task(void) - { - struct k_msg recv_msg; - struct k_block recv_block; - - int total; - char *data_ptr; - int i; - - while (1) { - /* prepare to receive message */ - recv_msg.size = 10000; - recv_msg.rx_data = NULL; - recv_msg.rx_task = ANYTASK; - - /* get message, but not its data */ - task_mbox_get(REQUEST_BOX, &recv_msg, TICKS_UNLIMITED); - - /* get message data as a memory block and discard message */ - task_mbox_data_block_get(&recv_msg, &recv_block, RXPOOL, - TICKS_UNLIMITED); - - /* compute sum of all message bytes in memory block */ - total = 0; - data_ptr = (char *)(recv_block.pointer_to_data); - for (i = 0; i < recv_msg.size; i++) { - total += data_ptr++; - } - - /* release memory block containing data */ - task_mem_pool_free(&recv_block); - } - } - -.. note:: - An incoming message that was sent synchronously is also processed correctly - by this algorithm, since the mailbox automatically creates a memory block - containing the message data using ``RXPOOL``. However, the performance benefit - of using the asynchronous approach is lost. - -APIs -**** - -The following APIs for mailbox operations are provided by the kernel: - -:cpp:func:`task_mbox_put()` - Send synchronous message to a receiving task, with time limited waiting. - -:c:func:`task_mbox_block_put()` - Send asynchronous message to a receiving task, or to a mailbox queue. - -:cpp:func:`task_mbox_get()` - Get message from a mailbox, with time limited waiting. - -:c:func:`task_mbox_data_get()` - Retrieve message data into a buffer. - -:cpp:func:`task_mbox_data_block_get()` - Retrieve message data into a block, with time limited waiting. diff --git a/doc/kernel/microkernel/microkernel_memory.rst b/doc/kernel/microkernel/microkernel_memory.rst deleted file mode 100644 index c7e6ef32603..00000000000 --- a/doc/kernel/microkernel/microkernel_memory.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _microkernel_memory: - -Memory Management Services -########################## - -This section contains the information about the memory management services available in the -microkernel. - -.. toctree:: - :maxdepth: 2 - - microkernel_memory_maps - microkernel_memory_pools \ No newline at end of file diff --git a/doc/kernel/microkernel/microkernel_memory_maps.rst b/doc/kernel/microkernel/microkernel_memory_maps.rst deleted file mode 100644 index f1933c3cc37..00000000000 --- a/doc/kernel/microkernel/microkernel_memory_maps.rst +++ /dev/null @@ -1,185 +0,0 @@ -.. _microkernel_memory_maps: - -Memory Maps -########### - -Concepts -******** - -The microkernel's memory map objects provide dynamic allocation and -release of fixed-size memory blocks. - -Any number of memory maps can be defined in a microkernel system. Each -memory map has: - -* A **name** that uniquely identifies it. -* The **number of blocks** it contains. -* **Block size** of a single block, measured in bytes. - -The number of blocks and block size values cannot be zero. On most -processors, the block size must be defined as a multiple of the word size. - -A task that needs to use a memory block simply allocates it from a memory -map. When all the blocks are currently in use, the task can wait -for one to become available. When the task finishes with a memory block, -it must release the block back to the memory map that allocated it so that -the block can be reused. - -Any number of tasks can wait on an empty memory map simultaneously; when a -memory block becomes available, it is given to the highest-priority task that -has waited the longest. - -The microkernel manages memory blocks in an efficient and deterministic -manner that eliminates the risk of memory fragmentation problems which can -arise when using variable-size blocks. - -Unlike a heap, more than one memory map can be defined, if needed. This -allows for a memory map with smaller blocks and others with larger-sized -blocks. Alternatively, a memory pool object may be used. - -Purpose -******* - -Use a memory map to allocate and free memory in fixed-size blocks. - -Usage -***** - -Defining a Memory Map -===================== - -The following parameters must be defined: - - *name* - This specifies a unique name for the memory map. - - *num_blocks* - This specifies the number of memory blocks in the memory map. - - *block_size* - This specifies the size in bytes of each memory block. - -Public Memory Map ------------------ - -Define the memory map in the application's MDEF using the following -syntax: - -.. code-block:: console - - MAP name num_blocks block_size - -For example, the file :file:`projName.mdef` defines a pair of memory maps -as follows: - -.. code-block:: console - - % MAP NAME NUMBLOCKS BLOCKSIZE - % ====================================== - MAP MYMAP 4 1024 - MAP YOURMAP 6 200 - -A public memory map can be referenced by name from any source file that -includes the file :file:`zephyr.h`. - -Private Memory Map ------------------- - -Define the memory map in a source file using the following syntax: - -.. code-block:: c - - DEFINE_MEM_MAP(name, num_blocks, block_size); - - -Example: Defining a Memory Map, Referencing it from Elsewhere in the Application -================================================================================ - -This code defines a private memory map named ``PRIV_MEM_MAP``: - -.. code-block:: c - - DEFINE_MEM_MAP(PRIV_MEM_MAP, 6, 200); - -To reference the map from a different source file, use the following syntax: - -.. code-block:: c - - extern const kmemory_map_t PRIV_MEM_MAP; - - -Example: Requesting a Memory Block from a Map with No Conditions -================================================================ - -This code waits indefinitely for a memory block to become available -when all the memory blocks are in use. - -.. code-block:: c - - void *block_ptr; - - task_mem_map_alloc(MYMAP, &block_ptr, TICKS_UNLIMITED); - - -Example: Requesting a Memory Block from a Map with a Conditional Time-out -========================================================================= - -This code waits a specified amount of time for a memory block to become -available and gives a warning when the memory block does not become available -in the specified time. - -.. code-block:: c - - void *block_ptr; - - if (task_mem_map_alloc(MYMAP, &block_ptr, 5) == RC_OK)) { - /* utilize memory block */ - } else { - printf("Memory allocation time-out"); - } - - -Example: Requesting a Memory Block from a Map with a No Blocking Condition -========================================================================== - -This code gives an immediate warning when all memory blocks are in use. - -.. code-block:: c - - void *block_ptr; - - if (task_mem_map_alloc(MYMAP, &block_ptr, TICKS_NONE) == RC_OK) { - /* utilize memory block */ - } else { - display_warning(); /* and do not allocate memory block*/ - } - - -Example: Freeing a Memory Block back to a Map -============================================= - -This code releases a memory block back when it is no longer needed. - -.. code-block:: c - - void *block_ptr; - - task_mem_map_alloc(MYMAP, &block_ptr, TICKS_UNLIMITED); - /* use memory block */ - task_mem_map_free(MYMAP, &block_ptr); - - -APIs -**** - -The following Memory Map APIs are provided by :file:`microkernel.h`: - -:cpp:func:`task_mem_map_alloc()` - Wait on a block of memory for the period of time defined by the time-out - parameter. - -:c:func:`task_mem_map_free()` - Return a block to a memory map. - -:cpp:func:`task_mem_map_used_get()` - Return the number of used blocks in a memory map. diff --git a/doc/kernel/microkernel/microkernel_memory_pools.rst b/doc/kernel/microkernel/microkernel_memory_pools.rst deleted file mode 100644 index 47bb3822632..00000000000 --- a/doc/kernel/microkernel/microkernel_memory_pools.rst +++ /dev/null @@ -1,203 +0,0 @@ -.. _microkernel_memory_pools: - -Memory Pools -############ - -Concepts -******** - -The microkernel's :dfn:`memory pool` objects provide dynamic allocation and -release of variable-size memory blocks. - -Unlike :ref:`memory map ` objects, which support -memory blocks of only a *single* size, a memory pool can support memory blocks -of *various* sizes. The memory pool does this by subdividing blocks into smaller -chunks, where possible, to more closely match the actual needs of a requesting -task. - -Any number of memory pools can be defined in a microkernel system. Each memory -pool has: - -* A **name** that uniquely identifies it. -* A **minimum** and **maximum** block size, in bytes, of memory blocks - within the pool. -* The **number of maximum-size memory blocks** initially available. - -A task that needs to use a memory block simply allocates it from a memory -pool. When a block of the desired size is unavailable, the task can wait -for one to become available. Following a successful allocation, the -:c:data:`pointer_to_data` field of the block descriptor supplied by the -task indicates the starting address of the memory block. When the task is -finished with a memory block, it must release the block back to the memory -pool that allocated it so that the block can be reused. - -Any number of tasks can wait on a memory pool simultaneously; when a -memory block becomes available, it is given to the highest-priority task -that has waited the longest. - -When a request for memory is sufficiently smaller than an available -memory pool block, the memory pool will automatically split the block into -4 smaller blocks. The resulting smaller blocks can also be split repeatedly, -until a block just larger than the needed size is available, or the minimum -block size, as specified in the MDEF, is reached. - -If the memory pool cannot find an available block that is at least -the requested size, it will attempt to create one by merging adjacent -free blocks. If a suitable block can't be created, the request fails. - -Although a memory pool uses efficient algorithms to manage its blocks, -the splitting of available blocks and merging of free blocks takes time -and increases overhead block allocation. The larger the allowable -number of splits, the larger the overhead. However, the minimum and maximum -block-size parameters specified for a pool can be used to control the amount -of splitting, and thus the amount of overhead. - -Unlike a heap, more than one memory pool can be defined, if needed. For -example, different applications can utilize different memory pools; this -can help prevent one application from hijacking resources to allocate all -of the available blocks. - -Purpose -******* -Use memory pools to allocate memory in variable-size blocks. - -Use memory pool blocks when sending data to a mailbox asynchronously. - -Usage -***** - -Defining a Memory Pool -====================== - -The following parameters must be defined: - - *name* - This specifies a unique name for the memory pool. - - *min_block_size* - This specifies the minimum memory block size in bytes. - It should be a multiple of the processor's word size. - - *max_block_size* - This specifies the maximum memory block size in bytes. - It should be a power of 4 times larger than *minBlockSize*; - therefore, maxBlockSize = minBlockSize * 4^n, where n>=0. - - *num_max* - This specifies the number of maximum size memory blocks - available at startup. - -Public Memory Pool ------------------- - -Define the memory pool in the application's MDEF with the following -syntax: - -.. code-block:: console - - POOL name min_block_size max_block_size num_max - -For example, the file :file:`projName.mdef` defines two memory pools -as follows: - -.. code-block:: console - - % POOL NAME MIN MAX NMAX - % ======================================= - POOL MY_POOL 32 8192 1 - POOL SECOND_POOL_ID 64 1024 5 - -A public memory pool can be referenced by name from any source file that -includes the file :file:`zephyr.h`. - -.. note:: - Private memory pools are not supported by the Zephyr kernel. - -Example: Requesting a Memory Block from a Pool with No Conditions -================================================================= - -This code waits indefinitely for an 80 byte memory block to become -available, then fills it with zeroes. - -.. code-block:: c - - struct k_block block; - - task_mem_pool_alloc(&block, MYPOOL, 80, TICKS_UNLIMITED); - - memset(block.pointer_to_data, 0, 80); - -Example: Requesting a Memory Block from a Pool with a Conditional Time-out -========================================================================== - -This code waits up to 5 ticks for an 80 byte memory block to become -available and gives a warning if a suitable memory block is not obtained -in that time. - -.. code-block:: none - - struct k_block block; - - if (task_mem_pool_alloc(:&block, MYPOOL, 80, 5) == RC_OK) { - /* use memory block */ - } else { - printf('Memory allocation timeout'); - } - -Example: Requesting a Memory Block from a Pool with a No-Blocking Condition -=========================================================================== - -This code gives an immediate warning when it can not satisfy the request for -a memory block of 80 bytes. - -.. code-block:: none - - struct k_block block; - - if (task_mem_pool_alloc (&block, MYPOOL, 80, TICKS_NONE) == RC_OK) { - /* use memory block */ - } else { - printf('Memory allocation timeout'); - } - -Example: Freeing a Memory Block Back to a Pool -============================================== - -This code releases a memory block back to a pool when it is no longer needed. - -.. code-block:: c - - struct k_block block; - - task_mem_pool_alloc(&block, MYPOOL, size, TICKS_NONE); - /* use memory block */ - task_mem_pool_free(&block); - -Example: Manually Defragmenting a Memory Pool -============================================= - -This code instructs the memory pool to concatenate any unused memory blocks -that can be merged. Doing a full defragmentation of the entire memory pool -before allocating a number of memory blocks may be more efficient than doing -an implicit partial defragmentation of the memory pool each time a memory -block allocation occurs. - -.. code-block:: c - - task_mem_pool_defragment(MYPOOL); - -APIs -**** - -Memory Pools APIs provided by :file:`microkernel.h` -=================================================== - -:cpp:func:`task_mem_pool_alloc()` - Wait for a block of memory; wait the period of time defined by the time-out - parameter. - -:cpp:func:`task_mem_pool_free()` - Return a block of memory to a memory pool. - -:cpp:func:`task_mem_pool_defragment()` - Defragment a memory pool. diff --git a/doc/kernel/microkernel/microkernel_mutexes.rst b/doc/kernel/microkernel/microkernel_mutexes.rst deleted file mode 100644 index 2bc86168a53..00000000000 --- a/doc/kernel/microkernel/microkernel_mutexes.rst +++ /dev/null @@ -1,194 +0,0 @@ -.. _microkernel_mutexes: - -Mutexes -####### - -Concepts -******** - -The microkernel's :dfn:`mutex` objects provide reentrant mutex -capabilities with basic priority inheritance. - -Each mutex allows multiple tasks to safely share an associated -resource by ensuring mutual exclusivity while the resource is -being accessed by a task. - -Any number of mutexes can be defined in a microkernel system. -Each mutex needs a **name** that uniquely identifies it. Typically, -the name should relate to the resource being shared, although this -is not a requirement. - -A task that needs to use a shared resource must first gain exclusive -access by locking the associated mutex. If the mutex is already locked -by another task, the requesting task can wait for the mutex to be -unlocked. - -After obtaining the mutex, the task may safely use the shared -resource for as long as needed. And when the task no longer needs -the resource, it must release the associated mutex to allow -other tasks to use the resource. - -Any number of tasks may wait on a locked mutex. When more than one -task is waiting, the mutex locks the resource for the highest-priority -task that has waited the longest first; this is known as -:dfn:`priority-based waiting`. The order is decided when a task decides -to wait on the object: it is queued in priority order. - -The task currently owning the mutex is also eligible for :dfn:`priority inheritance`. -Priority inheritance is the concept by which a task of lower priority gets its -priority *temporarily* elevated to the priority of the highest-priority -task that is waiting on a mutex held by the lower priority task. Thus, the -lower-priority task can complete its work and release the mutex as quickly -as possible. Once the mutex has been released, the lower-priority task resets -its task priority to the priority it had before locking that mutex. - -.. note:: - - The :option:`CONFIG_PRIORITY_CEILING` configuration option limits - how high the kernel can raise a task's priority due to priority - inheritance. The default value of 0 permits unlimited elevation. - -When two or more tasks wait on a mutex held by a lower priority task, the -kernel adjusts the owning task's priority each time a task begins waiting -(or gives up waiting). When the mutex is eventually released, the owning -task's priority correctly reverts to its original non-elevated priority. - -The kernel does *not* fully support priority inheritance when a task holds -two or more mutexes simultaneously. This situation can result in the task's -priority not reverting to its original non-elevated priority when all mutexes -have been released. Preferably, a task holds only a single mutex when multiple -mutexes are shared between tasks of different priorities. - -The microkernel also allows a task to repeatedly lock a mutex it has already -locked. This ensures that the task can access the resource at a point in its -execution when the resource may or may not already be locked. A mutex that is -repeatedly locked must be unlocked an equal number of times before the mutex -can release the resource completely. - -Purpose -******* - -Use mutexes to provide exclusive access to a resource, such as a physical -device. - -Usage -***** - -Defining a Mutex -================ - -The following parameters must be defined: - - *name* - This specifies a unique name for the mutex. - -Public Mutex ------------- - -Define the mutex in the application's MDEF file with the following syntax: - -.. code-block:: console - - MUTEX name - -For example, the file :file:`projName.mdef` defines a single mutex as follows: - -.. code-block:: console - - % MUTEX NAME - % =============== - MUTEX DEVICE_X - -A public mutex can be referenced by name from any source file that includes -the file :file:`zephyr.h`. - -Private Mutex -------------- - -Define the mutex in a source file using the following syntax: - -.. code-block:: c - - DEFINE_MUTEX(name); - -For example, the following code defines a private mutex named ``XYZ``. - -.. code-block:: c - - DEFINE_MUTEX(XYZ); - -The following syntax allows this mutex to be accessed from a different -source file: - -.. code-block:: c - - extern const kmutex_t XYZ; - - -Example: Locking a Mutex with No Conditions -=========================================== - -This code waits indefinitely for the mutex to become available if the -mutex is in use. - -.. code-block:: c - - task_mutex_lock(XYZ, TICKS_UNLIMITED); - moveto(100,100); - lineto(200,100); - task_mutex_unlock(XYZ); - - -Example: Locking a Mutex with a Conditional Timeout -=================================================== - -This code waits for a mutex to become available for a specified -time, and gives a warning if the mutex does not become available -in the specified amount of time. - -.. code-block:: c - - if (task_mutex_lock(XYZ, 100) == RC_OK) - { - moveto(100,100); - lineto(200,100); - task_mutex_unlock(XYZ); - } - else - { - printf("Cannot lock XYZ display\n"); - } - - -Example: Locking a Mutex with a No Blocking Condition -===================================================== - -This code gives an immediate warning when a mutex is in use. - -.. code-block:: c - - if (task_mutex_lock(XYZ, TICKS_NONE) == RC_OK); - { - do_something(); - task_mutex_unlock(XYZ); /* and unlock mutex*/ - } - else - { - display_warning(); /* and do not unlock mutex*/ - } - -APIs -**** - -Mutex APIs provided by :file:`microkernel.h` -============================================ - -:cpp:func:`task_mutex_lock()` - Wait on a locked mutex for the period of time defined by the timeout - parameter. Lock the mutex and increment the lock count if the mutex - becomes available during that period. - -:cpp:func:`task_mutex_unlock()` - Decrement a mutex lock count, and unlock the mutex when the count - reaches zero. - diff --git a/doc/kernel/microkernel/microkernel_pipes.rst b/doc/kernel/microkernel/microkernel_pipes.rst deleted file mode 100644 index 76b5226acf7..00000000000 --- a/doc/kernel/microkernel/microkernel_pipes.rst +++ /dev/null @@ -1,333 +0,0 @@ -.. _microkernel_pipes: - -Pipes -##### - -Concepts -******** - -The microkernel's :dfn:`pipe` object type is an implementation of a traditional -anonymous pipe. - -A pipe allows a task to send a byte stream to another task. The pipe can be -configured with a ring buffer which holds data that has been sent -but not yet received; alternatively, the pipe may have no ring buffer. -Pipes can be used to transfer chunks of data in whole or in part, and either -synchronously or asynchronously. - -Any number of pipes can be defined in a microkernel system. Each pipe -needs - -* A **name** to uniquely identify it. - -* A **size**, in bytes, of the ring buffer. Note that a size of zero defines - a pipe with no ring buffer. - -Sending Data -============ - -A task sends data to a pipe by specifying a pointer to the data bytes -to be sent. It also specifies both the number of data bytes available -and a :dfn:`pipe option` that indicates the minimum number of data bytes -the pipe must accept. The following pipe option values are supported: - - ``_ALL_N`` - - Specifies that **all** available data bytes must be accepted by the pipe. - When this requirement is not fulfilled, the send request either fails or - performs a partial send. - - ``_1_TO_N`` - - Specifies that **at least one** data byte must be accepted by the pipe. - When this requirement is not fulfilled, the send request fails. - - ``_0_TO_N`` - - Specifies that **any number** of data bytes, including zero, may be accepted - by the pipe; the send request never fails. - -The pipe accepts data bytes from the sending task if they can be delivered -by copying them directly to the receiving task. If the sending task is unable -to wait, or has waited as long as it can, the pipe can also accept data bytes -by copying them to its ring buffer for later delivery. The ring buffer is used -only when necessary to minimize copying of data bytes. - -Upon the completion of a send operation, a :dfn:`return code` is provided to -indicate whether the send request was satisfied. The sending task can also read -the ``bytes written`` argument attribute to determine how many data bytes were -accepted by the pipe, and subsequently allowing it to deal with any unsent data -bytes. - -Data sent to a pipe that does not have a ring buffer is sent synchronously; -that is, when the send operation is complete, the sending task knows that the -receiving task has received the data that was sent. Data sent to a pipe -that has a ring buffer is sent asynchronously; that is, when the send operation -is complete, some or all of the data that was sent may still be in the pipe -waiting for the receiving task to receive it. - -Incomplete Send Requests ------------------------- - -Although a pipe endeavors to accept all available data bytes when the -``_ALL_N`` pipe option is specified, it does not guarantee that the -data bytes will be accepted in an "all or nothing" manner. When the pipe -is able to accept at least one data byte, it returns :c:macro:`RC_INCOMPLETE` -to notify the sending task that its request was not fully satisfied. When -the pipe is unable to accept any data bytes, it returns :c:macro:`RC_FAIL`. - -One example of a situation that can result in an incomplete send is a -time-limited send request through an unbuffered pipe. If the receiving task -chooses to receive only a subset of the sender's data bytes, and the send -operation times out before the receiving task attempts to receive the -remainder, an incomplete send occurs. - -Sending using a Memory Pool Block ---------------------------------- - -A task that sends large chunks of data through a pipe may be able to improve -its efficiency by placing the data into a memory pool block and sending -the block. The pipe treats the memory block as a temporary addition to -its ring buffer, allowing it to immediately accept the data bytes without -copying them. Once all of the data bytes in the block have been delivered -to the receiving task, the pipe automatically frees the block back to the -memory pool. - -Data sent using a memory pool block is always sent asynchronously, even for -a pipe with no ring buffer of its own. Likewise, the pipe always accepts all -of the available data in the block -- a partial transfer never occurs. - -Receiving Data -============== - -A task receives from a pipe by specifying a pointer to an area to receive -the data bytes that were sent. It also specifies both the desired number -of data bytes and a :dfn:`pipe option` that indicates the minimum number of -data bytes the pipe must deliver. The following pipe option values -are supported: - - ``_ALL_N`` - - Specifies that all desired number of data bytes must be received. - When this requirement is not fulfilled, the receive request either fails or - performs a partial receive. - - ``_1_TO_N`` - - Specifies that at least one data byte must be received. When this requirement - is not fulfilled, the receive request fails. - - ``_0_TO_N`` - - Specifies that any number of data bytes (including zero) may be - received; the receive request never fails. - -The pipe delivers data bytes by copying them directly from the sending task -or from the pipe's ring buffer. Data bytes taken from the ring buffer are -delivered in a first in, first out manner. - -When a pipe is unable to deliver the specified minimum number of data bytes, -the receiving task may choose to wait until they can be delivered. - -Upon completion of a receive operation, a :dfn:`return code` is provided to -indicate whether the receive request was satisfied. The receiving task also -can read the ``bytes read`` argument attribute to determine how many -data bytes were delivered by the pipe. - -Incomplete Receive Requests ---------------------------- - -Although a pipe endeavors to deliver all desired data bytes when the -``_ALL_N`` pipe option is specified, it does not guarantee that the -data bytes will be delivered in an "all or nothing" manner. When the pipe -is able to deliver at least one data byte, it returns :c:macro:`RC_INCOMPLETE` -to notify the receiving task that its request was not fully satisfied. When -the pipe is unable to deliver any data bytes, it returns :c:macro:`RC_FAIL`. - -An example of a situation that can result in an incomplete receive is a -time-limited receive request through an unbuffered pipe. If the sending task -sends fewer than the desired number of data bytes, and the receive -operation times out before the sending task attempts to send the remainder, -an incomplete receive occurs. - -Receiving using a Memory Pool Block ------------------------------------ - -A task can achieve the effect of receiving data from a pipe into a memory pool -block by pre-allocating a block and then receiving the data into it. - -Sharing a Pipe -============== - -A pipe is typically used by a single sending task and a single receiving -task; however, it is possible for a pipe to be shared by multiple sending -tasks or multiple receiving tasks. - -Care must be taken when a pipe is shared by multiple sending tasks to -ensure the data bytes they send do not become interleaved unexpectedly; -using the ``_ALL_N`` pipe option helps to ensure that each data chunk is -transferred in a single operation. The same is true when multiple receiving -tasks are reading from the same pipe. - -Purpose -******* - -Use a pipe to transfer data when the receiving task needs the ability -to split or merge the data items generated by the sending task. - -Usage -***** - -Defining a Pipe -=============== - -The following parameters must be defined: - - *name* - This specifies a unique name for the pipe. - - *buffer_size* - This specifies the size in bytes of the pipe's ring buffer. - If no ring buffer is to be used specify zero. - -Public Pipe ------------ - -Define the pipe in the application's MDEF using the following syntax: - -.. code-block:: console - - PIPE name buffer_size - -For example, the file :file:`projName.mdef` defines a pipe with a 1 KB ring -buffer as follows: - -.. code-block:: console - - % PIPE NAME BUFFERSIZE - % =============================== - PIPE DATA_PIPE 1024 - -A public pipe can be referenced by name from any source file that includes -the file :file:`zephyr.h`. - -Private Pipe ------------- - -Define the pipe in a source file using the following syntax: - -.. code-block:: c - - DEFINE_PIPE(name, size); - -For example, the following code defines a private pipe named ``PRIV_PIPE``. - -.. code-block:: c - - DEFINE_PIPE(PRIV_PIPE, 1024); - -To use this pipe from a different source file use the following syntax: - -.. code-block:: c - - extern const kpipe_t PRIV_PIPE; - -Example: Writing Fixed-Size Data Items to a Pipe -================================================ - -This code uses a pipe to send a series of fixed-size data items -to a consuming task. - -.. code-block:: c - - void producer_task(void) - { - struct item_type data_item; - int amount_written; - - while (1) { - /* generate a data item to send */ - data_item = ... ; - - /* write the entire data item to the pipe */ - task_pipe_put(DATA_PIPE, &data_item, sizeof(data_item), - &amount_written, _ALL_N, TICKS_UNLIMITED); - - } - } - -Example: Reading Fixed-Size Data Items from a Pipe -================================================== - -This code uses a pipe to receive a series of fixed-size data items -from a producing task. To improve performance, the consuming task -waits until 20 data items are available then reads them as a group, -rather than reading them individually. - -.. code-block:: c - - void consumer_task(void) - { - struct item_type data_items[20]; - int amount_read; - int i; - - while (1) { - /* read 20 complete data items at once */ - task_pipe_get(DATA_PIPE, &data_items, sizeof(data_items), - &amount_read, _ALL_N, TICKS_UNLIMITED); - - /* process the data items one at a time */ - for (i = 0; i < 20; i++) { - ... = data_items[i]; - ... - } - } - } - -Example: Reading a Stream of Data Bytes from a Pipe -=================================================== - -This code uses a pipe to process a stream of data bytes from a -producing task. The pipe is read in a non-blocking manner to allow -the consuming task to perform other work when there are no -unprocessed data bytes in the pipe. - -.. code-block:: c - - void consumer_task(void) - { - char data_area[20]; - int amount_read; - int i; - - while (1) { - /* consume any data bytes currently in the pipe */ - while (task_pipe_get(DATA_PIPE, &data_area, sizeof(data_area), - &amount_read, _1_TO_N, TICKS_NONE) == RC_OK) { - /* now have from 1 to 20 data bytes */ - for (i = 0; i < amount_read; i++) { - ... = data_area[i]; - ... - } - } - - /* do other processing */ - ... - } - } - -APIs -**** - -Pipe APIs provided by :file:`microkernel.h` -=========================================== - -:cpp:func:`task_pipe_put()` - Write data to a pipe, with time limited waiting. - -:c:func:`task_pipe_block_put()` - Write data to a pipe from a memory pool block. - -:cpp:func:`task_pipe_get()` - Read data from a pipe, or fails and continues if data isn't there. diff --git a/doc/kernel/microkernel/microkernel_semaphores.rst b/doc/kernel/microkernel/microkernel_semaphores.rst deleted file mode 100644 index b7cb861c8f8..00000000000 --- a/doc/kernel/microkernel/microkernel_semaphores.rst +++ /dev/null @@ -1,229 +0,0 @@ -.. _microkernel_semaphores: - -Semaphores -########## - -Concepts -******** - -The microkernel's :dfn:`semaphore` objects are an implementation of traditional -counting semaphores. - -Any number of semaphores can be defined in a microkernel system. Each semaphore -has a **name** that uniquely identifies it. - -A semaphore starts off with a count of zero. This count is incremented each -time the semaphore is given, and is decremented each time the semaphore is taken. -However, a semaphore cannot be taken when it has a count of zero; this makes -it unavailable. - -Semaphores may be given by tasks, fibers, or ISRs. - -Semaphores may be taken by tasks only. A task that attempts to take an unavailable -semaphore may wait for the semaphore to be given. Any number of tasks may wait on -an unavailable semaphore simultaneously; and when the semaphore becomes available, -it is given to the highest priority task that has waited the longest. - -The kernel allows a task to give multiple semaphores in a single operation using a -*semaphore group*. The task specifies the members of a semaphore group with an array -of semaphore names, terminated by the symbol :c:macro:`ENDLIST`. This technique -allows the task to give the semaphores more efficiently than giving them individually. - -A task can also use a semaphore group to take a single semaphore from a set -of semaphores in a single operation. This technique allows the task to -monitor multiple synchronization sources at the same time, similar to the way -:c:func:`select()` can be used to read input from a set of file descriptors -in a POSIX-compliant operating system. The kernel does *not* define the order -in which semaphores are taken when more than one semaphore in a semaphore group -is available; the semaphore that is taken by the task may not be the one -that was given first. - -There is no limit on the number of semaphore groups used by a task, or -on the number of semaphores belonging to any given semaphore group. Semaphore -groups may also be shared by multiple tasks, if desired. - -Purpose -******* - -Use a semaphore to control access to a set of resources by multiple tasks. - -Use a semaphore synchronize processing between a producing task, fiber, -or ISR and one or more consuming tasks. - -Use a semaphore group to allow a task to signal or to monitor multiple -semaphores simultaneously. - -Usage -***** - -Defining a Semaphore -==================== - -The following parameters must be defined: - - *name* - This specifies a unique name for the semaphore. - -Public Semaphore ----------------- - -Define the semaphore in the application's MDEF with the following syntax: - -.. code-block:: console - - SEMA name - -For example, the file :file:`projName.mdef` defines two semaphores as follows: - -.. code-block:: console - - % SEMA NAME - % ================ - SEMA INPUT_DATA - SEMA WORK_DONE - -A public semaphore can be referenced by name from any source file that -includes the file :file:`zephyr.h`. - -Private Semaphore ------------------ - -Define the semaphore in a source file using the following syntax: - -.. code-block:: c - - DEFINE_SEMAPHORE(name); - -For example, the following code defines a private semaphore named ``PRIV_SEM``. - -.. code-block:: c - - DEFINE_SEMAPHORE(PRIV_SEM); - -To reference this semaphore from a different source file, use the following syntax: - -.. code-block:: c - - extern const ksem_t PRIV_SEM; - -Example: Giving a Semaphore from a Task -======================================= - -This code uses a semaphore to indicate that a unit of data -is available for processing by a consumer task. - -.. code-block:: c - - void producer_task(void) - { - /* save data item in a buffer */ - ... - - /* notify task that an additional data item is available */ - task_sem_give(INPUT_DATA); - - ... - } - -Example: Taking a Semaphore with a Conditional Time-out -======================================================= - -This code waits up to 500 ticks for a semaphore to be given, -and gives a warning if it is not obtained in that time. - -.. code-block:: c - - void consumer_task(void) - { - ... - - if (task_sem_take(INPUT_DATA, 500) == RC_TIME) { - printf("Input data not available!"); - } else { - /* extract saved data item from buffer and process it */ - ... - } - ... - } - -Example: Monitoring Multiple Semaphores at Once -=============================================== - -This code waits on two semaphores simultaneously, and then takes -action depending on which one was given. - -.. code-block:: c - - ksem_t my_sem_group[3] = { INPUT_DATA, WORK_DONE, ENDLIST }; - - void consumer_task(void) - { - ksem_t sem_id; - ... - - sem_id = task_sem_group_take(my_sem_group, TICKS_UNLIMITED); - if (sem_id == WORK_DONE) { - printf("Shutting down!"); - return; - } else { - /* process input data */ - ... - } - ... - } - -Example: Giving Multiple Semaphores at Once -=========================================== - -This code uses a semaphore group to allow a controlling task to signal -the semaphores used by four other tasks in a single operation. - -.. code-block:: c - - ksem_t my_sem_group[5] = { SEM1, SEM2, SEM3, SEM4, ENDLIST }; - - void control_task(void) - { - ... - task_semaphore_group_give(my_sem_group); - ... - } - -APIs -**** - -All of the following APIs are provided by :file:`microkernel.h`: - - -APIs for an individual semaphore -================================ - -:cpp:func:`isr_sem_give()` - Give a semaphore (from an ISR). - -:cpp:func:`fiber_sem_give()` - Give a semaphore (from a fiber). - -:cpp:func:`task_sem_give()` - Give a semaphore. - -:cpp:func:`task_sem_take()` - Take a semaphore, with time limited waiting. - -:cpp:func:`task_sem_reset()` - Set the semaphore count to zero. - -:cpp:func:`task_sem_count_get()` - Read the count for a semaphore. - -APIs for semaphore groups -========================= - -:cpp:func:`task_sem_group_give()` - Give each semaphore in a group. - -:cpp:func:`task_sem_group_take()` - Wait up to a specified time period for a semaphore from a group. - -:cpp:func:`task_sem_group_reset()` - Set the count to zero for each semaphore in a group. diff --git a/doc/kernel/microkernel/microkernel_synchronization.rst b/doc/kernel/microkernel/microkernel_synchronization.rst deleted file mode 100644 index a673167414b..00000000000 --- a/doc/kernel/microkernel/microkernel_synchronization.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _microkernel_synchronization: - -Synchronization Services -######################## - -This section contains the information about the synchronization services -available in the microkernel. - -.. toctree:: - :maxdepth: 2 - - microkernel_events - microkernel_semaphores - microkernel_mutexes diff --git a/doc/kernel/microkernel/microkernel_tasks.rst b/doc/kernel/microkernel/microkernel_tasks.rst deleted file mode 100644 index 253ceafacb1..00000000000 --- a/doc/kernel/microkernel/microkernel_tasks.rst +++ /dev/null @@ -1,540 +0,0 @@ -.. _microkernel_tasks: - -Task Services -############# - -Concepts -******** - -A task is a preemptible thread of execution that implements a portion of -an application's processing. It is normally used for processing that -is too lengthy or too complex to be performed by a fiber or an ISR. - -A microkernel application can define any number of application tasks. Each -task has a name that uniquely identifies it, allowing it to be directly -referenced by other tasks. For each microkernel task, the following -properties must be specified: - -* A **memory region** to be used for stack and execution context information. -* A **function** to be invoked when the task starts executing. -* The **priority** to be used by the microkernel scheduler. - -A task's entry point function takes no arguments, so there is no need to -define any argument values for it. - -The microkernel automatically defines a system task, known as the *idle task*, -at the lowest priority. This task is used during system initialization, -and subsequently executes only when there is no other work for the system to do. -The idle task is anonymous and must not be referenced by application tasks. - -.. note:: - A nanokernel application can define only a single application task, known - as the *background task*, which is very different from the microkernel tasks - described in this section. For more information see - :ref:`Nanokernel Task Services `. - -Task Lifecycle -============== - -The kernel automatically starts a task during system initialization if the task -belongs to the :c:macro:`EXE` task group; see `Task Groups`_ below. -A task that is not started automatically must be started by another task -using :c:func:`task_start()`. - -Once a task is started it normally executes forever. A task may terminate -gracefully by simply returning from its entry point function. If it does, -it is the task's responsibility to release any system resources it may own -(such as mutexes and dynamically allocated memory blocks) prior to returning, -since the kernel does *not* attempt to reclaim them so they can be reused. - -A task may also terminate non-gracefully by *aborting*. The kernel -automatically aborts a task when it generates a fatal error condition, -such as dereferencing a null pointer. A task can also be explicitly aborted -using :c:func:`task_abort()`. As with graceful task termination, -the kernel does not attempt to reclaim system resources owned by the task. - -A task may optionally register an *abort handler function* to be invoked -by the kernel when the task terminates (including during graceful termination). -The abort handler can be used to record information about the terminating -task or to assist in reclaiming system resources owned by the task. The abort -handler function is invoked by the microkernel server fiber, so it cannot -directly call kernel APIs that must be invoked by a task; instead, it must -coordinate with another task to invoke such APIs indirectly. - -.. note:: - The kernel does not currently make any claims regarding an application's - ability to restart a terminated task. - -Task Scheduling -=============== - -The microkernel's scheduler selects which of the system's tasks is allowed -to execute; this task is known as the *current task*. The nanokernel's scheduler -permits the current task to execute only when no fibers or ISRs are available -to execute; fiber and ISR executions always take precedence. - -When prompted for a context switch to a different task, fiber, or ISR, the kernel -automatically saves the current task's CPU register values; these values get -restored when the task later resumes execution. - -Task State ----------- - -Each microkernel task has an associated *state* that determines whether or not -it can be scheduled for execution. The state records factors that could prevent -the task from executing, such as: - -* The task has not been started. -* The task is waiting (for a semaphore, for a timeout, ...). -* The task has been suspended. -* The task has terminated. - -A task whose state has no factors that prevent its execution is said to be -*executable*. - -Task Priorities ---------------- - -A microkernel application can be configured to support any number of -task priority levels using the :option:`CONFIG_NUM_TASK_PRIORITIES` -configuration option. - -An application task can have any priority from 0 (highest priority) -down to :option:`CONFIG_NUM_TASK_PRIORITIES`\-2. The lowest priority -level, :option:`CONFIG_NUM_TASK_PRIORITIES`\-1, is reserved for the -microkernel's idle task. - -A task's original priority can be altered up or down after the task has been -started. - -Scheduling Algorithm --------------------- - -The microkernel's scheduler always selects the highest priority executable task -to be the current task. When multiple executable tasks of the same priority are -available, the scheduler chooses the one that has been waiting longest. - -Once a task becomes the current task it remains scheduled for execution -by the microkernel until one of the following occurs: - -* The task is supplanted by a higher-priority task that becomes ready to - execute. - -* The task is supplanted by an equal-priority task that is ready to execute, - either because the current task explicitly calls :c:func:`task_yield()` - or because the kernel implicitly calls :c:func:`task_yield()` after the - scheduler's time slice expired. - -* The task is supplanted by an equal or lower-priority task that is ready - to execute because the current task called a kernel API that blocked its - own execution. For example, the task attempted to take a semaphore that - was unavailable. - -* The task terminates itself by returning from its entry point function. - -* The task aborts itself by performing an operation that causes a fatal error, - or by calling :c:func:`task_abort()`. - -Time Slicing ------------- - -The microkernel's scheduler supports an optional time slicing capability -that prevents a task from monopolizing the CPU when other tasks of the -same priority are ready to execute. - -The scheduler divides time into a series of *time slices*, where -slices are measured in system clock ticks. The time slice size is -specified with the :option:`CONFIG_TIMESLICE_SIZE` configuration -option, but this size can also be changed dynamically, while the -application is running. - -At the end of every time slice, the scheduler implicitly invokes -:c:func:`task_yield()` on behalf of the current task; this gives -any other task of that priority the opportunity to execute before the -current task can once again be scheduled. If one or more equal-priority -tasks are ready to execute, the current task is preempted to allow those -tasks to execute. If no tasks of equal priority are ready to execute, -the current task remains the current task, and it continues to execute. - -Tasks with a priority higher than that specified by the -:option:`CONFIG_TIMESLICE_PRIORITY` configuration option are exempt -from time slicing, and are never preempted by a task of equal -priority. This capability allows an application to use time slicing -only for lower priority tasks that are less time-sensitive. - -.. note:: - The microkernel's time slicing algorithm does *not* ensure that a set - of equal-priority tasks will receive an equitable amount of CPU time, - since it does not measure the amount of time a task actually gets to - execute. For example, a task may become the current task just before - the end of a time slice and then immediately have to yield the CPU. - On the other hand, the microkernel's scheduler *does* ensure that a task - never executes for longer than a single time slice without being required - to yield. - -Task Suspension ---------------- - -The microkernel allows a task to be *suspended*, which prevents the task -from executing for an indefinite period of time. The :c:func:`task_suspend()` -API allows an application task to suspend any other task, including itself. -Suspending a task that is already suspended has no additional effect. - -Once suspended, a task cannot be scheduled until another task calls -:c:func:`task_resume()` to remove the suspension. - -.. note:: - A task can prevent itself from executing for a specified period of time - using :c:func:`task_sleep()`. However, this is different from suspending - a task since a sleeping task becomes executable automatically when the - time limit is reached. - -Task Groups -=========== - -The kernel allows a set of related tasks, known as a *task group*, to be -manipulated as a single unit, rather than individually. This simplifies -the work required to start related tasks, to suspend and resume them, or -to abort them. - -The kernel supports a maximum of 32 distinct task groups. Each task group -has a name that uniquely identifies it, allowing it to be directly referenced -by tasks. - -The task groups a task belongs to are specified when the task is defined. -A task may belong to a single task group, to multiple task groups, or to -no task group. A task's group memberships can also be changed dynamically -while the application is running. - -The task group designations listed below are pre-defined by the kernel; -additional task groups can be defined by the application. - - :c:macro:`EXE` - This task group is started automatically by the kernel during system - intialization. - - :c:macro:`SYS` - This task group is a set of system tasks that continues to execute - during system debugging. - - :c:macro:`FPU` - This task group is a set of tasks that requires the kernel to save - x87 FPU and MMX floating point context information during context switches. - - :c:macro:`SSE` - This task group is a set of tasks that requires the kernel to save SSE - floating point context information during context switches. (Tasks with - this group designation are implicitly members of the :c:macro:`FPU` task - group too.) - -Usage -***** - -Defining a Task -=============== - -The following parameters must be defined: - - *name* - This specifies a unique name for the task. - - *priority* - This specifies the scheduling priority of the task. - - *entry_point* - This specifies the name of the task's entry point function, - which should have the following form: - - .. code-block:: c - - void (void) - { - /* task mainline processing */ - ... - /* (optional) normal task termination */ - return; - } - - *stack_size* - This specifies the size of the memory region used for the task's - stack and for other execution context information, in bytes. - - *groups* - This specifies the task groups the task belongs to. - -Public Task ------------ - -Define the task in the application's MDEF using the following syntax: - -.. code-block:: console - - TASK name priority entry_point stack_size groups - -The task groups are specified using a comma-separated list of task group names -enclosed in square brackets, with no embedded spaces. If the task does not -belong to any task group, specify an empty list; i.e. :literal:`[]`. - -For example, the file :file:`projName.mdef` defines a system comprised -of six tasks as follows: - -.. code-block:: console - - % TASK NAME PRIO ENTRY STACK GROUPS - % =================================================================== - TASK MAIN_TASK 6 keypad_main 1024 [KEYPAD_TASKS,EXE] - TASK PROBE_TASK 2 probe_main 400 [] - TASK SCREEN1_TASK 8 screen_1_main 4096 [VIDEO_TASKS] - TASK SCREEN2_TASK 8 screen_2_main 4096 [VIDEO_TASKS] - TASK SPEAKER1_TASK 10 speaker_1_main 1024 [AUDIO_TASKS] - TASK SPEAKER2_TASK 10 speaker_2_main 1024 [AUDIO_TASKS] - -A public task can be referenced by name from any source file that includes -the file :file:`zephyr.h`. - -Private Task ------------- - -Define the task in a source file using the following syntax: - -.. code-block:: c - - DEFINE_TASK(PRIV_TASK, priority, entry, stack_size, groups); - -The task groups are specified using a list of task group names separated by -:literal:`|`; i.e. the bitwise OR operator. If the task does not belong to any -task group specify NULL. - -For example, the following code can be used to define a private task named -``PRIV_TASK``. - -.. code-block:: c - - DEFINE_TASK(PRIV_TASK, 10, priv_task_main, 800, EXE); - -To utilize this task from a different source file use the following syntax: - -.. code-block:: c - - extern const ktask_t PRIV_TASK; - -Defining a Task Group -===================== - -The following parameters must be defined: - - *name* - This specifies a unique name for the task group. - -Public Task Group ------------------ - -Define the task group in the application's .MDEF file using the following -syntax: - -.. code-block:: console - - TASKGROUP name - -For example, the file :file:`projName.mdef` defines three new task groups -as follows: - -.. code-block:: console - - % TASKGROUP NAME - % ======================== - TASKGROUP VIDEO_TASKS - TASKGROUP AUDIO_TASKS - TASKGROUP KEYPAD_TASKS - -A public task group can be referenced by name from any source file that -includes the file :file:`zephyr.h`. - -.. note:: - Private task groups are not supported by the Zephyr kernel. - -Example: Starting a Task from Another Task -========================================== - -This code shows how the currently-executing task can start another task. - -.. code-block:: c - - void keypad_main(void) - { - /* begin system initialization */ - ... - - /* start task to monitor temperature */ - task_start(PROBE_TASK); - - /* continue to bring up and operate system */ - ... - } - -Example: Suspending and Resuming a Set of Tasks -=============================================== - -This code shows how the currently-executing task can temporarily suspend -the execution of all tasks belonging to the designated task groups. - -.. code-block:: c - - void probe_main(void) - { - int was_overheated = 0; - - /* continuously monitor temperature */ - while (1) { - now_overheated = overheating_update(); - - /* suspend non-essential tasks when overheating is detected */ - if (now_overheated && !was_overheated) { - task_group_suspend(VIDEO_TASKS - AUDIO_TASKS); - was_overheated = 1; - } - - /* resume non-essential tasks when overheating abates */ - if (!now_overheated && was_overheated) { - task_group_resume(VIDEO_TASKS - AUDIO_TASKS); - was_overheated = 0; - } - - /* wait 10 ticks of system clock before checking again */ - task_sleep(10); - } - } - -Example: Offloading Work to the Microkernel Server Fiber -======================================================== - -This code shows how the currently-executing task can perform critical section -processing by offloading it to the microkernel server. Since the critical -section function is being executed by a fiber, once the function begins -executing it cannot be interrupted by any other fiber or task that wants -to log an alarm. - -.. code-block:: c - - /* alarm logging subsystem */ - - #define MAX_ALARMS 100 - - struct alarm_info alarm_log[MAX_ALARMS]; - int num_alarms = 0; - - int log_an_alarm(struct alarm_info *new_alarm) - { - /* ensure alarm log isn't full */ - if (num_alarms == MAX_ALARMS) { - return 0; - } - - /* add new alarm to alarm log */ - alarm_info[num_alarms] = *new_alarm; - num_alarms++; - - /* pass back alarm identifier to indicate successful logging */ - return num_alarms; - } - - /* task that generates an alarm */ - - void XXX_main(void) - { - struct alarm_info my_alarm = { ... }; - - ... - - /* record alarm in system's database */ - if (task_offload_to_fiber(log_an_alarm, &my_alarm) == 0) { - printf("Unable to log alarm!"); - } - - ... - } - -APIs -**** - -All of the following Microkernel APIs are provided by :file:`microkernel.h`. - -APIs Affecting the Currently-Executing Task -=========================================== - -:cpp:func:`task_id_get()` - Gets the task's ID. - -:c:func:`isr_task_id_get()` - Gets the task's ID from an ISR. - -:cpp:func:`task_priority_get()` - Gets the task's priority. - -:c:func:`isr_task_priority_get()` - Gets the task's priority from an ISR. - -:cpp:func:`task_group_mask_get()` - Gets the task's group memberships. - -:c:func:`isr_task_group_mask_get()` - Gets the task's group memberships from an ISR. - -:cpp:func:`task_abort_handler_set()` - Installs the task's abort handler. - -:cpp:func:`task_yield()` - Yields CPU to equal-priority tasks. - -:cpp:func:`task_sleep()` - Yields CPU for a specified time period. - -:cpp:func:`task_offload_to_fiber()` - Instructs the microkernel server fiber to execute a function. - -APIs Affecting a Specified Task -=============================== - -:cpp:func:`task_priority_set()` - Sets a task's priority. - -:cpp:func:`task_entry_set()` - Sets a task's entry point. - -:c:func:`task_start()` - Starts execution of a task. - -:c:func:`task_suspend()` - Suspends execution of a task. - -:c:func:`task_resume()` - Resumes execution of a task. - -:c:func:`task_abort()` - Aborts execution of a task. - -:cpp:func:`task_group_join()` - Adds a task to the specified task group(s). - -:cpp:func:`task_group_leave()` - Removes a task from the specified task group(s). - -APIs Affecting Multiple Tasks -============================= - -:cpp:func:`sys_scheduler_time_slice_set()` - Sets the time slice period used in round-robin task scheduling. - -:c:func:`task_group_start()` - Starts execution of all tasks in the specified task groups. - -:c:func:`task_group_suspend()` - Suspends execution of all tasks in the specified task groups. - -:c:func:`task_group_resume()` - Resumes execution of all tasks in the specified task groups. - -:c:func:`task_group_abort()` - Aborts execution of all tasks in the specified task groups. diff --git a/doc/kernel/microkernel/microkernel_timers.rst b/doc/kernel/microkernel/microkernel_timers.rst deleted file mode 100644 index 3828c65e543..00000000000 --- a/doc/kernel/microkernel/microkernel_timers.rst +++ /dev/null @@ -1,211 +0,0 @@ -.. _microkernel_timers: - -Timer Services -############## - -Concepts -******** - -A :dfn:`microkernel timer` allows a task to determine whether or not a -specified time limit has been reached while the task is busy performing -other work. The timer uses the kernel's system clock, measured in -ticks, to monitor the passage of time. - -Any number of microkernel timers can be defined in a microkernel system. -Each timer has a unique identifier, which allows it to be distinguished -from other timers. - -A task that wants to use a timer must first allocate an unused timer -from the set of microkernel timers. A task can allocate more than one timer -when it needs to monitor multiple time intervals simultaneously. - -A timer is started by specifying: - -* A :dfn:`duration` is the number of ticks the timer counts before it - expires for the first time. -* A :dfn:`period` is the number of ticks the timer counts before it expires - each time thereafter. -* The :dfn:`microkernel semaphore identifier` is what the timer gives each - time the semaphore expires. - -The semaphore's state can be examined by the task any time the task needs to -determine whether or not the given time limit has been reached. - -When the timer's period is set to zero, the timer stops automatically -after reaching the duration and giving the semaphore. When the period is set to -any number of ticks other than zero, the timer restarts automatically with -a new duration that is equal to its period. When this new duration has elapsed, -the timer gives the semaphore again and restarts. For example, a timer can be -set to expire after 5 ticks, and to then re-expire every 20 ticks thereafter, -resulting in the semaphore being given 3 times after 45 ticks have elapsed. - -.. note:: - Care must be taken when specifying the duration of a microkernel timer. - The first tick measured by the timer after it is started will be - less than a full-tick interval. For example, when the system clock period - is 10 milliseconds, starting a timer that expires after 1 tick will result - in the semaphore being given anywhere from a fraction of a millisecond - later to just slightly less than 10 milliseconds later. To ensure that a - timer doesn't expire for at least ``N`` ticks, it is necessary to specify - a duration of ``N+1`` ticks. This adjustment is not required when specifying - the period of a timer, which always corresponds to full-tick intervals. - -A running microkernel timer can be cancelled or restarted by a task prior to -its expiration. Cancelling a timer that has already expired does not affect -the state of the associated semaphore. Likewise, restarting a timer that has -already expired is equivalent to stopping the timer and starting it afresh. - -When a task no longer needs a timer it should free the timer. This makes -the timer available for reallocation. - -Purpose -******* - -Use a microkernel timer to determine whether or not a specified number of -system clock ticks have elapsed while the task is busy performing other work. - -.. note:: - If a task has no other work to perform while waiting for time to pass - it can simply call :cpp:func:`task_sleep()`. - -.. note:: - The microkernel provides additional APIs that allow a task to monitor - both the system clock and the higher-precision hardware clock, without - using a microkernel timer. - -Usage -***** - -Configuring Microkernel Timers -============================== - -Set the :option:`CONFIG_NUM_TIMER_PACKETS` configuration option to -specify the number of timer-related command packets available in the -application. This value should be **equal to** or **greater than** the -sum of the following quantities: - -* The number of microkernel timers. -* The number of tasks. - -.. note:: - Unlike most other microkernel object types, microkernel timers are defined - as a group using a configuration option, rather than as individual public - objects in an MDEF or private objects in a source file. - -Example: Allocating a Microkernel Timer -======================================= - -This code allocates an unused timer. - -.. code-block:: c - - ktimer_t timer_id; - - timer_id = task_timer_alloc(); - -Example: Starting a One Shot Microkernel Timer -============================================== -This code uses a timer to limit the amount of time a task spends on gathering -data. It works by monitoring the status of a microkernel semaphore that is set -when the timer expires. Since the timer is started with a period of zero, it -stops automatically once it expires. - -.. code-block:: c - - ktimer_t timer_id; - ksem_t my_sem; - - ... - - /* set timer to expire in 10 ticks */ - task_timer_start(timer_id, 10, 0, my_sem); - - /* gather data until timer expires */ - do { - ... - } while (task_sem_take(my_sem, TICKS_NONE) != RC_OK); - - /* process the new data */ - ... - -Example: Starting a Periodic Microkernel Timer -============================================== -This code is similar to the previous example, except that the timer -automatically restarts every time it expires. This approach eliminates -the overhead of having the task explicitly issue a request to -reactivate the timer. - -.. code-block:: c - - ktimer_t timer_id; - ksem_t my_sem; - - ... - - /* set timer to expire every 10 ticks */ - task_timer_start(timer_id, 10, 10, my_sem); - - while (1) { - /* gather data until timer expires */ - do { - ... - } while (task_sem_take(my_sem, TICKS_NONE) != RC_OK); - - /* process the new data, then loop around to get more */ - ... - } - -Example: Cancelling a Microkernel Timer -======================================= -This code illustrates how an active timer can be stopped prematurely. - -.. code-block:: c - - ktimer_t timer_id; - ksem_t my_sem; - - ... - - /* set timer to expire in 10 ticks */ - task_timer_start(timer_id, 10, 0, my_sem); - - /* do work while waiting for input to arrive */ - ... - - /* now have input, so stop the timer if it is still running */ - task_timer_stop(timer_id); - - /* check to see if the timer expired before it was stopped */ - if (task_sem_take(my_sem, TICKS_NONE) == RC_OK) { - printf("Warning: Input took too long to arrive!"); - } - -Example: Freeing a Microkernel Timer -==================================== -This code allows a task to relinquish a previously-allocated timer -so it can be used by other tasks. - -.. code-block:: c - - task_timer_free(timer_id); - - -APIs -**** - -The following microkernel timer APIs are provided by :file:`microkernel.h`: - -:cpp:func:`task_timer_alloc()` - Allocates an unused timer. - -:cpp:func:`task_timer_start()` - Starts a timer. - -:cpp:func:`task_timer_restart()` - Restarts a timer. - -:cpp:func:`task_timer_stop()` - Cancels a timer. - -:cpp:func:`task_timer_free()` - Marks timer as unused. diff --git a/doc/kernel/nanokernel/nanokernel.rst b/doc/kernel/nanokernel/nanokernel.rst deleted file mode 100644 index 6569927cd2d..00000000000 --- a/doc/kernel/nanokernel/nanokernel.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. _nanokernel: - -Nanokernel Services -################### - -This section describes the various services provided by the nanokernel. -Unless otherwise noted, these services are available in both microkernel -applications and nanokernel applications. - -.. toctree:: - :maxdepth: 1 - - nanokernel_tasks.rst - nanokernel_fibers - nanokernel_timers - nanokernel_synchronization - nanokernel_data - nanokernel_interrupts - nanokernel_kernel_event_logger - nanokernel_example diff --git a/doc/kernel/nanokernel/nanokernel_data.rst b/doc/kernel/nanokernel/nanokernel_data.rst deleted file mode 100644 index 45d9b03d4d4..00000000000 --- a/doc/kernel/nanokernel/nanokernel_data.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _nanokernel_data: - -Data Passing Services -##################### - -This section contains the information about all data passing services -provided by the nanokernel. - -.. toctree:: - :maxdepth: 2 - - nanokernel_fifos - nanokernel_lifos - nanokernel_stacks - nanokernel_ring_buffers diff --git a/doc/kernel/nanokernel/nanokernel_example.rst b/doc/kernel/nanokernel/nanokernel_example.rst deleted file mode 100644 index a70eb137892..00000000000 --- a/doc/kernel/nanokernel/nanokernel_example.rst +++ /dev/null @@ -1,149 +0,0 @@ -.. _nanokernel_example: - -Semaphore, Timer, and Fiber Example -################################### - -The following example is intended to provide a basic picture of how Zephyr's -semaphores, timers, and fibers work. The actual implementations of the -standard hello_world are much simpler, see -:file:`ZEPHYR_BASE/samples/hello_world` - -Example Code -************ - -.. code-block:: c - - #include - - #include - - /* specify delay between greetings (in ms); compute equivalent in ticks */ - - #define SLEEPTIME - - #define SLEEPTICKS (SLEEPTIME * CONFIG_TICKFREQ / 1000) - - #define STACKSIZE 2000 - - char fiberStack[STACKSIZE]; - - struct nano_sem nanoSemTask; - - struct nano_sem nanoSemFiber; - - void fiberEntry (void) - - { - struct nano_timer timer; - uint32_t data[2] = {0, 0}; - - nano_sem_init (&nanoSemFiber); - nano_timer_init (&timer, data); - - while (1) - { - /* wait for task to let us have a turn */ - nano_fiber_sem_take(&nanoSemFiber, TICKS_UNLIMITED); - - /* say "hello" */ - PRINT ("%s: Hello World!\n", __FUNCTION__); - - /* wait a while, then let task have a turn */ - nano_fiber_timer_start (&timer, SLEEPTICKS); - nano_fiber_timer_test (&timer, TICKS_UNLIMITED); - nano_fiber_sem_give (&nanoSemTask); - } - - } - - void main (void) - - { - struct nano_timer timer; - uint32_t data[2] = {0, 0}; - - task_fiber_start (&fiberStack[0], STACKSIZE, - (nano_fiber_entry_t) fiberEntry, 0, 0, 7, 0); - - nano_sem_init (&nanoSemTask); - nano_timer_init (&timer, data); - - while (1) - { - /* say "hello" */ - PRINT ("%s: Hello World!\n", __FUNCTION__); - - /* wait a while, then let fiber have a turn */ - nano_task_timer_start (&timer, SLEEPTICKS); - nano_task_timer_test (&timer, TICKS_UNLIMITED); - nano_task_sem_give (&nanoSemFiber); - - /* now wait for fiber to let us have a turn */ - nano_task_sem_take (&nanoSemTask, TICKS_UNLIMITED); - } - - } - -Step-by-Step Description -************************ - -A quick breakdown of the major objects in use by this sample includes: - -- One fiber, executing in the :c:func:`fiberEntry()` routine. - -- The background task, executing in the :c:func:`main()` routine. - -- Two semaphores (*nanoSemTask*, *nanoSemFiber*), - -- Two timers: - - + One local to the fiber (timer) - - + One local to background task (timer) - -First, the background task starts executing main(). The background task -calls task_fiber_start initializing and starting the fiber. Since a -fiber is available to be run, the background task is pre-empted and the -fiber begins running. - -Execution jumps to fiberEntry. nanoSemFiber and the fiber-local timer -before dropping into the while loop, where it takes and waits on -nanoSemFiber. task_fiber_start. - -The background task initializes nanoSemTask and the task-local timer. - -The following steps repeat endlessly: - -#. The background task execution begins at the top of the main while - loop and prints, “main: Hello World!” - -#. The background task then starts a timer for SLEEPTICKS in the - future, and waits for that timer to expire. - - -#. Once the timer expires, it signals the fiber by giving the - nanoSemFiber semaphore, which in turn marks the fiber as runnable. - -#. The fiber, now marked as runnable, pre-empts the background - task, allowing execution to jump to the fiber. - nano_fiber_sem_take. - -#. The fiber then prints, “fiberEntry: Hello World!” It starts a time - for SLEEPTICKS in the future and waits for that timer to expire. The - fiber is marked as not runnable, and execution jumps to the - background task. - -#. The background task then takes and waits on the nanoSemTask - semaphore. - -#. Once the timer expires, the fiber signals the background task by - giving the nanoSemFiber semaphore. The background task is marked as - runnable, but code execution continues in the fiber, since fibers - take priority over the background task. The fiber execution - continues to the top of the while loop, where it takes and waits on - nanoSemFiber. The fiber is marked as not runnable, and the - background task is scheduled. - -#. The background task execution picks up after the call to - :c:func:`nano_task_sem_take()`. It jumps to the top of the - while loop. diff --git a/doc/kernel/nanokernel/nanokernel_fibers.rst b/doc/kernel/nanokernel/nanokernel_fibers.rst deleted file mode 100644 index 1b717b05657..00000000000 --- a/doc/kernel/nanokernel/nanokernel_fibers.rst +++ /dev/null @@ -1,313 +0,0 @@ -.. _nanokernel_fibers: - -Fiber Services -############## - -Concepts -******** - -A :dfn:`fiber` is a lightweight, non-preemptible thread of execution that -implements a portion of an application's processing. Fibers are often -used in device drivers and for performance-critical work. - -Fibers can be used by microkernel applications, as well as by nanokernel -applications. However, fibers can interact with microkernel object types -to only a limited degree; for more information see :ref:`microkernel_fibers`. - -An application can use any number of fibers. Each fiber is anonymous, and -cannot be directly referenced by other fibers or tasks once it has started -executing. The properties that must be specified when a fiber is spawned -include: - -* A **memory region** to be used for stack and execution context information. -* A **function** to be invoked when the fiber starts executing. -* A **pair of arguments** to be passed to that entry point function. -* A **priority** to be used by the nanokernel scheduler. -* A **set of options** that will apply to the fiber. - -The kernel may automatically spawn zero or more system fibers during system -initialization. The specific set of fibers spawned depends upon both: - -#. The kernel capabilities that have been configured by the application. -#. The board configuration used to build the application image. - - -Fiber Lifecycle -=============== - -A fiber can be spawned by another fiber, by a task, or by the kernel itself -during system initialization. A fiber typically becomes executable immediately; -however, it is possible to delay the scheduling of a newly-spawned fiber for a -specified time period. For example, scheduling can be delayed to allow device -hardware which the fiber uses to become available. The kernel also supports a -delayed start cancellation capability, which prevents a newly-spawned fiber from -executing if the fiber becomes unnecessary before its full delay period is reached. - -Once a fiber is started it normally executes forever. A fiber may terminate -itself gracefully by simply returning from its entry point function. When this -happens, it is the fiber's responsibility to release any system resources it may -own (such as a nanokernel semaphore being used in a mutex-like manner) prior -to returning, since the kernel does *not* attempt to reclaim them so they can -be reused. - -A fiber may also terminate non-gracefully by *aborting*. The kernel -automatically aborts a fiber when it generates a fatal error condition, -such as dereferencing a null pointer. A fiber can also explicitly abort itself -using :cpp:func:`fiber_abort()`. As with graceful fiber termination, the kernel -does not attempt to reclaim system resources owned by the fiber. - -.. note:: - The kernel does not currently make any claims regarding an application's - ability to restart a terminated fiber. - -Fiber Scheduling -================ - -The nanokernel's scheduler selects which of the system's threads is allowed -to execute; this thread is known as the :dfn:`current context`. The nanokernel's -scheduler permits threads to execute only when no ISR needs to execute; execution -of ISRs take precedence. - -When executing threads, the nanokernel's scheduler gives fiber execution -precedence over task execution. The scheduler preempts task execution -whenever a fiber needs to execute, but never preempts the execution of a fiber -to allow another fiber to execute -- even if it is a higher priority fiber. - -The kernel automatically saves an executing fiber's CPU register values when -making a context switch to a different fiber, a task, or an ISR; these values -get restored when the fiber later resumes execution. - -Fiber State ------------ - -A fiber has an implicit *state* that determines whether or not it can be -scheduled for execution. The state records all factors that can prevent -the fiber from executing, such as: - -* The fiber has not been spawned. -* The fiber is waiting for a kernel service, for example, a semaphore or a timer. -* The fiber has terminated. - -A fiber whose state has no factors that prevent its execution is said to be -*executable*. - -Fiber Priorities ----------------- - -The kernel supports a virtually unlimited number of fiber priority levels, -ranging from 0 (highest priority) to 2^31-1 (lowest priority). Negative -priority levels must not be used. - -A fiber's original priority cannot be altered up or down after it has been -spawned. - -Fiber Scheduling Algorithm --------------------------- - -Whenever possible, the nanokernel's scheduler selects the highest priority -executable fiber to be the current context. When multiple executable fibers -of that priority are available, the scheduler chooses the one that has been -waiting longest. - -When no executable fibers exist, the scheduler selects the current task -to be the current context. The current task selected depends upon whether the -application is a nanokernel application or a microkernel application. In nanokernel -applications, the current task is always the background task. In microkernel -applications, the current task is the current task selected by the microkernel's -scheduler. The current task is always executable. - -Once a fiber becomes the current context, it remains scheduled for execution -by the nanokernel until one of the following occurs: - -* The fiber is supplanted by another thread because it calls a kernel API - that blocks its own execution. (For example, the fiber attempts to take - a nanokernel semaphore that is unavailable.) - -* The fiber terminates itself by returning from its entry point function. - -* The fiber aborts itself by performing an operation that causes a fatal error, - or by calling :cpp:func:`fiber_abort()`. - -Once the current task becomes the current context, it remains scheduled for -execution by the nanokernel until is supplanted by a fiber. - -.. note:: - The current task is **never** directly supplanted by another task, since the - microkernel scheduler uses the microkernel server fiber to initiate a - change from one microkernel task to another. - -Cooperative Time Slicing ------------------------- - -Due to the non-preemptive nature of the nanokernel's scheduler, a fiber that -performs lengthy computations may cause an unacceptable delay in the scheduling -of other fibers, including higher priority and equal priority ones. To overcome -such problems, the fiber can choose to voluntarily relinquish the CPU from time -to time to permit other fibers to execute. - -A fiber can relinquish the CPU in two ways: - -* Calling :cpp:func:`fiber_yield()` places the fiber back in the nanokernel - scheduler's list of executable fibers and then invokes the scheduler. - All executable fibers whose priority is higher or equal to that of the - yielding fiber are then allowed to execute before the yielding fiber is - rescheduled. If no such executable fibers exist, the scheduler immediately - reschedules the yielding fiber without context switching. - -* Calling :cpp:func:`fiber_sleep()` blocks the execution of the fiber for - a specified time period. Executable fibers of all priorities are then - allowed to execute, although there is no guarantee that fibers whose - priority is lower than that of the sleeping task will actually be scheduled - before the time period expires and the sleeping task becomes executable - once again. - -Fiber Options -============= - -The kernel supports several :dfn:`fiber options` that may be used to inform -the kernel of special treatment the fiber requires. - -The set of kernel options associated with a fiber are specified when the fiber -is spawned. If the fiber uses multiple options, they are separated with -:literal:`|`, the logical ``OR`` operator. A fiber that does not use any -options is spawned using an options value of 0. - -The fiber options listed below are pre-defined by the kernel. - -:c:macro:`USE_FP` - Instructs the kernel to save the fiber's x87 FPU and MMX floating point - context information during context switches. - -:c:macro:`USE_SSE` - Instructs the kernel to save the fiber's SSE floating point context - information during context switches. A fiber with this option - implicitly uses the :c:macro:`USE_FP` option, as well. - -Usage -***** - -Defining a Fiber -================ - -The following properties must be defined when spawning a fiber: - - *stack_name* - This specifies the memory region used for the fiber's stack and for - other execution context information. To ensure proper memory alignment, - it should have the following form: - - .. code-block:: c - - char __stack []; - - *stack_size* - This specifies the size of the *stack_name* memory region, in bytes. - - *entry_point* - This specifies the name of the fiber's entry point function, - which should have the following form: - - .. code-block:: c - - void (int arg1, int arg2) - { - /* fiber mainline processing */ - ... - /* (optional) normal fiber termination */ - return; - } - - *arguments* - This specifies the two arguments passed to *entry_point* when the fiber - begins executing. Non-integer arguments can be passed in by casting to - an integer type. - - *priority* - This specifies the scheduling priority of the fiber. - - *options* - This specifies the fiber's options. - -Example: Spawning a Fiber from a Task -===================================== - -This code shows how the currently executing task can spawn multiple fibers, -each dedicated to processing data from a different communication channel. - -.. code-block:: c - - #define COMM_STACK_SIZE 512 - #define NUM_COMM_CHANNELS 8 - - struct descriptor { - ...; - }; - - char __stack comm_stack[NUM_COMM_CHANNELS][COMM_STACK_SIZE]; - struct descriptor comm_desc[NUM_COMM_CHANNELS] = { ... }; - - ... - - void comm_fiber(int desc_arg, int unused); - { - ARG_UNUSED(unused); - - struct descriptor *desc = (struct descriptor *) desc_arg; - - while (1) { - /* process packet of data from comm channel */ - - ... - } - } - - void comm_main(void) - { - ... - - for (int i = 0; i < NUM_COMM_CHANNELS; i++) { - task_fiber_start(&comm_stack[i][0], COMM_STACK_SIZE, - comm_fiber, (int) &comm_desc[i], 0, - 10, 0); - } - - ... - } - -APIs -**** - -APIs affecting the currently-executing fiber are provided -by :file:`microkernel.h` and by :file:`nanokernel.h`: - -:cpp:func:`fiber_yield()` - - Yield the CPU to higher priority and equal priority fibers. - -:cpp:func:`fiber_sleep()` - - Yield the CPU for a specified time period. - -:cpp:func:`fiber_abort()` - - Terminate fiber execution. - -APIs affecting a specified fiber are provided by :file:`microkernel.h` -and by :file:`nanokernel.h`: - -:cpp:func:`task_fiber_start()`, :cpp:func:`fiber_fiber_start()`, -:cpp:func:`fiber_start()` - - Spawn a new fiber. - -:cpp:func:`task_fiber_delayed_start()`, -:cpp:func:`fiber_fiber_delayed_start()`, -:cpp:func:`fiber_delayed_start()` - - Spawn a new fiber after a specified time period. - -:cpp:func:`task_fiber_delayed_start_cancel()`, -:cpp:func:`fiber_fiber_delayed_start_cancel()`, -:cpp:func:`fiber_delayed_start_cancel()` - - Cancel spawning of a new fiber, if not already started. diff --git a/doc/kernel/nanokernel/nanokernel_fifos.rst b/doc/kernel/nanokernel/nanokernel_fifos.rst deleted file mode 100644 index 13506da7112..00000000000 --- a/doc/kernel/nanokernel/nanokernel_fifos.rst +++ /dev/null @@ -1,144 +0,0 @@ -.. _nanokernel_fifos: - -Nanokernel FIFOs -################ - -Concepts -******** - -The nanokernel's FIFO object type is an implementation of a traditional -first in, first out queue. It is mainly intended for use by fibers. - -A nanokernel FIFO allows data items of any size tasks to be sent and received -asynchronously. The FIFO uses a linked list to hold data items that have been -sent but not yet received. - -FIFO data items must be aligned on a 4-byte boundary, as the kernel reserves -the first 32 bits of each item for use as a pointer to the next data item -in the FIFO's linked list. Consequently, a data item that holds N bytes -of application data requires N+4 bytes of memory. - -Any number of nanokernel FIFOs can be defined. Each FIFO is a distinct -variable of type :c:type:`struct nano_fifo`, and is referenced using a -pointer to that variable. A FIFO must be initialized before it can be used to -send or receive data items. - -Items can be added to a nanokernel FIFO in a non-blocking manner by any -context type (i.e. ISR, fiber, or task). - -Items can be removed from a nanokernel FIFO in a non-blocking manner by any -context type; if the FIFO is empty the :c:macro:`NULL` return code -indicates that no item was removed. Items can also be removed from a -nanokernel FIFO in a blocking manner by a fiber or task; if the FIFO is empty -the thread waits for an item to be added. - -Any number of threads may wait on an empty nanokernel FIFO simultaneously. -When a data item becomes available it is given to the fiber that has waited -longest, or to a waiting task if no fiber is waiting. - -.. note:: - A task that waits on an empty nanokernel FIFO does a busy wait. This is - not an issue for a nanokernel application's background task; however, in - a microkernel application a task that waits on a nanokernel FIFO remains - the current task. In contrast, a microkernel task that waits on a - microkernel data passing object ceases to be the current task, allowing - other tasks of equal or lower priority to do useful work. - - If multiple tasks in a microkernel application wait on the same nanokernel - FIFO, higher priority tasks are given data items in preference to lower - priority tasks. However, the order in which equal priority tasks are given - data items is unpredictible. - -Purpose -******* - -Use a nanokernel FIFO to asynchronously transfer data items of arbitrary size -in a "first in, first out" manner. - -Usage -***** - -Example: Initializing a Nanokernel FIFO -======================================= - -This code establishes an empty nanokernel FIFO. - -.. code-block:: c - - struct nano_fifo signal_fifo; - - nano_fifo_init(&signal_fifo); - -Example: Writing to a Nanokernel FIFO from a Fiber -================================================== - -This code uses a nanokernel FIFO to send data to one or more consumer fibers. - -.. code-block:: c - - struct data_item_t { - void *fifo_reserved; /* 1st word reserved for use by FIFO */ - ... - }; - - struct data_item_t tx_data; - - void producer_fiber(int unused1, int unused2) - { - ARG_UNUSED(unused1); - ARG_UNUSED(unused2); - - while (1) { - /* create data item to send (e.g. measurement, timestamp, ...) */ - tx_data = ... - - /* send data to consumers */ - nano_fiber_fifo_put(&signal_fifo, &tx_data); - - ... - } - } - -Example: Reading from a Nanokernel FIFO -======================================= - -This code uses a nanokernel FIFO to obtain data items from a producer fiber, -which are then processed in some manner. This design supports the distribution -of data items to multiple consumer fibers, if desired. - -.. code-block:: c - - void consumer_fiber(int unused1, int unused2) - { - struct data_item_t *rx_data; - - ARG_UNUSED(unused1); - ARG_UNUSED(unused2); - - while (1) { - rx_data = nano_fiber_fifo_get(&signal_fifo, TICKS_NONE); - - /* process FIFO data */ - ... - } - } - -APIs -**** - -The following APIs for a nanokernel FIFO are provided by :file:`nanokernel.h`: - -:cpp:func:`nano_fifo_init()` - - Initializes a FIFO. - -:cpp:func:`nano_task_fifo_put()`, :cpp:func:`nano_fiber_fifo_put()`, -:cpp:func:`nano_isr_fifo_put()`, :cpp:func:`nano_fifo_put()` - - Add an item to a FIFO. - -:cpp:func:`nano_task_fifo_get()`, :cpp:func:`nano_fiber_fifo_get()`, -:cpp:func:`nano_isr_fifo_get()`, :cpp:func:`nano_fifo_get()` - - Remove an item from a FIFO, or waits for an item for a specified - time period if it is empty. diff --git a/doc/kernel/nanokernel/nanokernel_interrupts.rst b/doc/kernel/nanokernel/nanokernel_interrupts.rst deleted file mode 100644 index 9846e94e4bd..00000000000 --- a/doc/kernel/nanokernel/nanokernel_interrupts.rst +++ /dev/null @@ -1,173 +0,0 @@ -.. _nanokernel_interrupts: - -Interrupt Services -################## - -Concepts -******** - -:abbr:`ISRs (Interrupt Service Routines)` are execution threads -that run in response to a hardware or software interrupt. -They are used to preempt the execution of the -task or fiber running at the time of the interrupt, -allowing the response to occur with very low overhead. -When an ISR completes its normal task and fiber execution resumes. - -Any number of ISRs can be utilized in a Zephyr project, subject to -any hardware constraints imposed by the underlying hardware. -Each ISR has the following properties: - -* The :abbr:`IRQ (Interrupt ReQuest)` signal that triggers the ISR. -* The priority level associated with the IRQ. -* The address of the function that is invoked to handle the interrupt. -* The argument value that is passed to that function. - -An :abbr:`IDT (Interrupt Descriptor Table)` is used to associate a given interrupt -source with a given ISR. -Only a single ISR can be associated with a specific IRQ at any given time. - -Multiple ISRs can utilize the same function to process interrupts, -allowing a single function to service a device that generates -multiple types of interrupts or to service multiple devices -(usually of the same type). The argument value passed to an ISR's function -can be used to allow the function to determine which interrupt has been -signaled. - -The Zephyr kernel provides a default ISR for all unused IDT entries. This ISR -generates a fatal system error if an unexpected interrupt is signaled. - -The kernel supports interrupt nesting. This allows an ISR to be preempted -in mid-execution if a higher priority interrupt is signaled. The lower -priority ISR resumes execution once the higher priority ISR has completed -its processing. - -The kernel allows a task or fiber to temporarily lock out the execution -of ISRs, either individually or collectively, should the need arise. -The collective lock can be applied repeatedly; that is, the lock can -be applied when it is already in effect. The collective lock must be -unlocked an equal number of times before interrupts are again processed -by the kernel. - -Purpose -******* - -Use an ISR to perform interrupt processing that requires a very rapid -response, and which can be done quickly and without blocking. - -.. note:: - - Interrupt processing that is time consuming, or which involves blocking, - should be handed off to a fiber or task. See `Offloading ISR Work`_ for - a description of various techniques that can be used in a Zephyr project. - -Installing an ISR -***************** - -It's important to note that IRQ_CONNECT() is not a C function and does -some inline assembly magic behind the scenes. All its arguments must be known -at build time. Drivers that have multiple instances may need to define -per-instance config functions to configure the interrupt for that instance. - -Example -------- - -.. code-block:: c - - #define MY_DEV_IRQ 24 /* device uses IRQ 24 */ - #define MY_DEV_PRIO 2 /* device uses interrupt priority 2 */ - /* argument passed to my_isr(), in this case a pointer to the device */ - #define MY_ISR_ARG DEVICE_GET(my_device) - #define MY_IRQ_FLAGS 0 /* IRQ flags. Unused on non-x86 */ - - void my_isr(void *arg) - { - ... /* ISR code */ - } - - void my_isr_installer(void) - { - ... - IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_ISR_ARG, MY_IRQ_FLAGS); - irq_enable(MY_DEV_IRQ); /* enable IRQ */ - ... - } - - -Working with Interrupts -*********************** - -Offloading ISR Work -******************* - -Interrupt service routines should generally be kept short -to ensure predictable system operation. -In situations where time consuming processing is required -an ISR can quickly restore the kernel's ability to respond -to other interrupts by offloading some or all of the interrupt-related -processing work to a fiber or task. - -Zephyr OS provides a variety of mechanisms to allow an ISR to offload work -to a fiber or task. - -1. An ISR can signal a helper fiber (or task) to do interrupt-related work - using a nanokernel object, such as a FIFO, LIFO, or semaphore. - The :c:func:`nano_isr_XXX()` APIs should be used to notify the helper fiber - (or task) that work is available for it. - - See :ref:`nanokernel_fibers`. - -2. An ISR can signal the microkernel server fiber to do interrupt-related - work by sending an event that has an associated event handler. - - See :ref:`microkernel_events`. - -3. An ISR can signal a helper task to do interrupt-related work - by sending an event that the helper task detects. - - See :ref:`microkernel_events`. - -4. An ISR can signal a helper task to do interrupt-related work. - by giving a semaphore that the helper task takes. - - See :ref:`microkernel_semaphores`. - -When an ISR offloads work to a fiber there is typically a single -context switch to that fiber when the ISR completes. -Thus, interrupt-related processing usually continues almost immediately. -Additional intermediate context switches may be required -to execute any currently executing fiber -or any higher-priority fibers that are scheduled to run. - -When an ISR offloads work to a task there is typically a context switch -to the microkernel server fiber, followed by a context switch to that task. -Thus, there is usually a larger delay before the interrupt-related processing -resumes than when offloading work to a fiber. -Additional intermediate context switches may be required -to execute any currently executing fiber or any higher-priority tasks -that are scheduled to run. - -APIs -**** - -These are the interrupt-related Application Program Interfaces. - -:c:func:`irq_enable()` - Enables interrupts from a specific IRQ. - -:c:func:`irq_disable()` - Disables interrupts from a specific IRQ. - -:c:func:`irq_lock()` - Locks out interrupts from all sources. - -:c:func:`irq_unlock()` - Removes lock on interrupts from all sources. - -Macros -****** - -These are the macros used to install a static ISR. - -:c:macro:`IRQ_CONNECT()` - Registers a static ISR with the IDT. - diff --git a/doc/kernel/nanokernel/nanokernel_kernel_event_logger.rst b/doc/kernel/nanokernel/nanokernel_kernel_event_logger.rst deleted file mode 100644 index 78260a3e04b..00000000000 --- a/doc/kernel/nanokernel/nanokernel_kernel_event_logger.rst +++ /dev/null @@ -1,364 +0,0 @@ -.. _nanokernel_event_logger: - -Kernel Event Logger -################### - -Definition -********** - -The kernel event logger is a standardized mechanism to record events within the Kernel while -providing a single interface for the user to collect the data. This mechanism is currently used -to log the following events: - -* Sleep events (entering and exiting low power conditions). -* Context switch events. -* Interrupt events. - -Kernel Event Logger Configuration -********************************* - -Kconfig provides the ability to enable and disable the collection of events and to configure the -size of the buffer used by the event logger. - -These options can be found in the following path :file:`kernel/Kconfig`. - -General kernel event logger configuration: - -* :option:`CONFIG_KERNEL_EVENT_LOGGER_BUFFER_SIZE` - - Default size: 128 words, 32-bit length. - -Profiling points configuration: - -* :option:`CONFIG_KERNEL_EVENT_LOGGER_DYNAMIC` - - Allows modifying at runtime the events to record. At boot no event is recorded if enabled - This flag adds functions allowing to enable/disable recoding of kernel event logger and - task monitor events. - -* :option:`CONFIG_KERNEL_EVENT_LOGGER_CUSTOM_TIMESTAMP` - - Enables the possibility to set the timer function to be used to populate kernel event logger - timestamp. This has to be done at runtime by calling sys_k_event_logger_set_timer and providing - the function callback. - -Adding a Kernel Event Logging Point -*********************************** - -Custom trace points can be added with the following API: - -* :c:func:`sys_k_event_logger_put()` - - Adds the profile of a new event with custom data. - -* :cpp:func:`sys_k_event_logger_put_timed()` - - Adds timestamped profile of a new event. - -.. important:: - - The data must be in 32-bit sized blocks. - -Retrieving Kernel Event Data -**************************** - -Applications are required to implement a fiber for accessing the recorded event messages -in both the nanokernel and microkernel systems. Developers can use the provided API to -retrieve the data, or may write their own routines using the ring buffer provided by the -event logger. - -The API functions provided are: - -* :c:func:`sys_k_event_logger_get()` -* :c:func:`sys_k_event_logger_get_wait()` -* :c:func:`sys_k_event_logger_get_wait_timeout()` - -The above functions specify various ways to retrieve a event message and to copy it to -the provided buffer. When the buffer size is smaller than the message, the function will -return an error. All three functions retrieve messages via a FIFO method. The :literal:`wait` -and :literal:`wait_timeout` functions allow the caller to pend until a new message is -logged, or until the timeout expires. - -Enabling/disabling event recording -********************************** - -If KERNEL_EVENT_LOGGER_DYNAMIC is enabled, following functions must be checked for -dynamically enabling/disabling event recording at runtime: - -* :cpp:func:`sys_k_event_logger_set_mask()` -* :cpp:func:`sys_k_event_logger_get_mask()` -* :cpp:func:`sys_k_event_logger_set_monitor_mask()` -* :cpp:func:`sys_k_event_logger_get_monitor_mask()` - -Each mask bit corresponds to the corresponding event ID (mask is starting at bit 1 not bit 0). - -More details are provided in function description. - -Timestamp -********* - -The timestamp used by the kernel event logger is 32-bit LSB of board HW timer (for example -Lakemont APIC timer for Quark SE). This timer period is very small and leads to timestamp -wraparound happening quite often (e.g. every 134s for Quark SE). - -see :option:`CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC` - -This wraparound must be considered when analyzing kernel event logger data and care must be -taken when tickless idle is enabled and sleep duration can exceed maximum HW timer value. - -Timestamp used by the kernel event logger can be customized by enabling following option: -:option:`CONFIG_KERNEL_EVENT_LOGGER_CUSTOM_TIMESTAMP` - -In case this option is enabled, a callback function returning a 32-bit timestamp must -be provided to the kernel event logger by calling the following function at runtime: -:cpp:func:`sys_k_event_logger_set_timer()` - -Message Formats -*************** - -Interrupt-driven Event Messaging --------------------------------- - -The data of the interrupt-driven event message comes in two block of 32 bits: - -* The first block contains the timestamp occurrence of the interrupt event. -* The second block contains the Id of the interrupt. - -Example: - -.. code-block:: c - - uint32_t data[2]; - data[0] = timestamp_event; - data[1] = interrupt_id; - -Context-switch Event Messaging ------------------------------- - -The data of the context-switch event message comes in two block of 32 bits: - -* The first block contains the timestamp occurrence of the context-switch event. -* The second block contains the thread id of the context involved. - -Example: - -.. code-block:: c - - uint32_t data[2]; - data[0] = timestamp_event; - data[1] = context_id; - -Sleep Event Messaging ---------------------- - -The data of the sleep event message comes in three block of 32 bits: - -* The first block contains the timestamp when the CPU went to sleep mode. -* The second block contains the timestamp when the CPU woke up. -* The third block contains the interrupt Id that woke the CPU up. - -Example: - -.. code-block:: c - - uint32_t data[3]; - data[0] = timestamp_went_sleep; - data[1] = timestamp woke_up. - data[2] = interrupt_id. - - -Task Monitor ------------- - -The task monitor tracks the activities of the task schedule server -in the microkernel and it is able to report three different types of -events related with the scheduler activities: - - -Task Monitor Task State Change Event -++++++++++++++++++++++++++++++++++++ - -The Task Monitor Task State Change Event tracks the task's status changes. -The event data is arranged as three 32 bit blocks: - -* The first block contains the timestamp when the task server - changed the task status. -* The second block contains the task ID of the affected task. -* The thid block contains a 32 bit number with the new status. - -Example: - -.. code-block:: c - - uint32_t data[3]; - - data[0] = timestamp; - data[1] = task_id. - data[2] = status_data. - -Task Monitor Kevent Event -+++++++++++++++++++++++++ - -The Task Monitor Kevent Event tracks the commands requested to the -task server by the kernel. The event data is arranged as two blocks -of 32 bits each: - -* The first block contains the timestamp when the task server - attended the kernel command. -* The second block contains the code of the command. - -.. code-block:: c - - uint32_t data[3]; - - data[0] = timestamp; - data[1] = event_code. - -Task Monitor Command Packet Event -+++++++++++++++++++++++++++++++++ - -The Task Monitor Command Packet Event track the command packets sent -to the task server. The event data is arranged as three blocks of -32 bits each: - -* The first block contains the timestamp when the task server - attended the kernel command. -* The second block contains the task identifier of the task - affected by the packet. -* The thid block contains the memory vector of the routine - executed by the task server. - -Example: - -.. code-block:: c - - uint32_t data[3]; - - data[0] = timestamp; - data[1] = task_id. - data[2] = comm_handler. - -Example: Retrieving Profiling Messages -====================================== - -.. code-block:: c - - uint32_t data[3]; - uint8_t data_length = SIZE32_OF(data); - uint8_t dropped_count; - - while(1) { - /* collect the data */ - res = sys_k_event_logger_get_wait(&event_id, &dropped_count, data, - &data_length); - - if (dropped_count > 0) { - /* process the message dropped count */ - } - - if (res > 0) { - /* process the data */ - switch (event_id) { - case KERNEL_EVENT_CONTEXT_SWITCH_EVENT_ID: - /* ... Process the context switch event data ... */ - break; - case KERNEL_EVENT_INTERRUPT_EVENT_ID: - /* ... Process the interrupt event data ... */ - break; - case KERNEL_EVENT_SLEEP_EVENT_ID: - /* ... Process the data for a sleep event ... */ - break; - case KERNEL_EVENT_LOGGER_TASK_MON_TASK_STATE_CHANGE_EVENT_ID: - /* ... Process the data for a task monitor event ... */ - break; - case KERNEL_EVENT_LOGGER_TASK_MON_KEVENT_EVENT_ID: - /* ... Process the data for a task monitor command event ... */ - break; - case KERNEL_EVENT_LOGGER_TASK_MON_CMD_PACKET_EVENT_ID: - /* ... Process the data for a task monitor packet event ... */ - break; - default: - printf("unrecognized event id %d\n", event_id); - } - } else { - if (res == -EMSGSIZE) { - /* ERROR - The buffer provided to collect the - * profiling events is too small. - */ - } else if (ret == -EAGAIN) { - /* There is no message available in the buffer */ - } - } - } - -.. note:: - - To see an example that shows how to collect the kernel event data, check the - project :file:`samples/kernel_event_logger`. - -Example: Adding a Kernel Event Logging Point -============================================ - -.. code-block:: c - - uint32_t data[2]; - - if (sys_k_must_log_event(KERNEL_EVENT_LOGGER_CUSTOM_ID)) { - data[0] = custom_data_1; - data[1] = custom_data_2; - - sys_k_event_logger_put(KERNEL_EVENT_LOGGER_CUSTOM_ID, data, ARRAY_SIZE(data)); - } - -Use the following function to register only the time of an event. - -.. code-block:: c - - if (sys_k_must_log_event(KERNEL_EVENT_LOGGER_CUSTOM_ID)) { - sys_k_event_logger_put_timed(KERNEL_EVENT_LOGGER_CUSTOM_ID); - } - -APIs -**** - -The following APIs are provided by the :file:`k_event_logger.h` file: - -:cpp:func:`sys_k_event_logger_register_as_collector()` - Register the current fiber as the collector fiber. - -:c:func:`sys_k_event_logger_put()` - Enqueue a kernel event logger message with custom data. - -:cpp:func:`sys_k_event_logger_put_timed()` - Enqueue a kernel event logger message with the current time. - -:c:func:`sys_k_event_logger_get()` - De-queue a kernel event logger message. - -:c:func:`sys_k_event_logger_get_wait()` - De-queue a kernel event logger message. Wait if the buffer is empty. - -:c:func:`sys_k_event_logger_get_wait_timeout()` - De-queue a kernel event logger message. Wait if the buffer is empty until the timeout expires. - -:cpp:func:`sys_k_must_log_event()` - Check if an event type has to be logged or not - -In case KERNEL_EVENT_LOGGER_DYNAMIC is enabled: - -:cpp:func:`sys_k_event_logger_set_mask()` - Set kernel event logger event mask - -:cpp:func:`sys_k_event_logger_get_mask()` - Get kernel event logger event mask - -:cpp:func:`sys_k_event_logger_set_monitor_mask()` - Set task monitor event mask - -:cpp:func:`sys_k_event_logger_get_monitor_mask()` - Get task monitor event mask - -In case KERNEL_EVENT_LOGGER_CUSTOM_TIMESTAMP is enabled: - -:cpp:func:`sys_k_event_logger_set_timer()` - Set kernel event logger timestamp function diff --git a/doc/kernel/nanokernel/nanokernel_lifos.rst b/doc/kernel/nanokernel/nanokernel_lifos.rst deleted file mode 100644 index 3b81032adc2..00000000000 --- a/doc/kernel/nanokernel/nanokernel_lifos.rst +++ /dev/null @@ -1,142 +0,0 @@ -.. _nanokernel_lifos: - -Nanokernel LIFOs -################ - -Concepts -******** - -The nanokernel's LIFO object type is an implementation of a traditional -last in, first out queue. It is mainly intended for use by fibers. - -A nanokernel LIFO allows data items of any size tasks to be sent and received -asynchronously. The LIFO uses a linked list to hold data items that have been -sent but not yet received. - -LIFO data items must be aligned on a 4-byte boundary, as the kernel reserves -the first 32 bits of each item for use as a pointer to the next data item -in the LIFO's linked list. Consequently, a data item that holds N bytes -of application data requires N+4 bytes of memory. - -Any number of nanokernel LIFOs can be defined. Each LIFO is a distinct -variable of type :c:type:`struct nano_lifo`, and is referenced using a -pointer to that variable. A LIFO must be initialized before it can be used to -send or receive data items. - -Items can be added to a nanokernel LIFO in a non-blocking manner by any -context type (i.e. ISR, fiber, or task). - -Items can be removed from a nanokernel LIFO in a non-blocking manner by any -context type; if the LIFO is empty the :c:macro:`NULL` return code -indicates that no item was removed. Items can also be removed from a -nanokernel LIFO in a blocking manner by a fiber or task; if the LIFO is empty -the thread waits for an item to be added. - -Any number of threads may wait on an empty nanokernel LIFO simultaneously. -When a data item becomes available it is given to the fiber that has waited -longest, or to a waiting task if no fiber is waiting. - -.. note:: - A task that waits on an empty nanokernel LIFO does a busy wait. This is - not an issue for a nanokernel application's background task; however, in - a microkernel application a task that waits on a nanokernel LIFO remains - the current task. In contrast, a microkernel task that waits on a - microkernel data passing object ceases to be the current task, allowing - other tasks of equal or lower priority to do useful work. - - If multiple tasks in a microkernel application wait on the same nanokernel - LIFO, higher priority tasks are given data items in preference to lower - priority tasks. However, the order in which equal priority tasks are given - data items is unpredictable. - -Purpose -******* - -Use a nanokernel LIFO to asynchronously transfer data items of arbitrary size -in a "last in, first out" manner. - -Usage -***** - -Example: Initializing a Nanokernel LIFO -======================================= - -This code establishes an empty nanokernel LIFO. - -.. code-block:: c - - struct nano_lifo signal_lifo; - - nano_lifo_init(&signal_lifo); - -Example: Writing to a Nanokernel LIFO from a Fiber -================================================== - -This code uses a nanokernel LIFO to send data to a consumer fiber. - -.. code-block:: c - - struct data_item_t { - void *lifo_reserved; /* 1st word reserved for use by LIFO */ - ... - }; - - struct data_item_t tx data; - - void producer_fiber(int unused1, int unused2) - { - ARG_UNUSED(unused1); - ARG_UNUSED(unused2); - - while (1) { - /* create data item to send */ - tx_data = ... - - /* send data to consumer */ - nano_fiber_lifo_put(&signal_lifo, &tx_data); - - ... - } - } - -Example: Reading from a Nanokernel LIFO -======================================= - -This code uses a nanokernel LIFO to obtain data items from a producer fiber, -which are then processed in some manner. - -.. code-block:: c - - void consumer_fiber(int unused1, int unused2) - { - struct data_item_t *rx_data; - - ARG_UNUSED(unused1); - ARG_UNUSED(unused2); - - while (1) { - rx_data = nano_fiber_lifo_get(&signal_lifo, TICKS_UNLIMITED); - /* process LIFO data */ - ... - } - } - -APIs -**** - -The following APIs for a nanokernel LIFO are provided by :file:`nanokernel.h`: - -:cpp:func:`nano_lifo_init()` - - Initializes a LIFO. - -:cpp:func:`nano_task_lifo_put()`, :cpp:func:`nano_fiber_lifo_put()`, -:cpp:func:`nano_isr_lifo_put()`, :cpp:func:`nano_lifo_put()` - - Add an item to a LIFO. - -:cpp:func:`nano_task_lifo_get()`, :cpp:func:`nano_fiber_lifo_get()`, -:cpp:func:`nano_isr_lifo_get()`, :cpp:func:`nano_lifo_get()` - - Remove an item from a LIFO, or waits for an item for a specified - time period if it is empty. diff --git a/doc/kernel/nanokernel/nanokernel_ring_buffers.rst b/doc/kernel/nanokernel/nanokernel_ring_buffers.rst deleted file mode 100644 index 7cef8c84608..00000000000 --- a/doc/kernel/nanokernel/nanokernel_ring_buffers.rst +++ /dev/null @@ -1,143 +0,0 @@ -.. _nanokernel_ring_buffers: - -Nanokernel Ring Buffers -####################### - -Definition -********** - -The ring buffer is defined in :file:`include/misc/ring_buffer.h` and -:file:`kernel/nanokernel/ring_buffer.c`. This is an array-based -circular buffer, stored in first-in-first-out order. The APIs allow -for enqueueing and retrieval of chunks of data up to 1024 bytes in size, -along with two metadata values (type ID and an app-specific integer). - -Unlike nanokernel FIFOs, storage of enqueued items and their metadata -is managed in a fixed buffer and there are no preconditions on the data -enqueued (other than the size limit). Since the size annotation is only -an 8-bit value, sizes are expressed in terms of 32-bit chunks. - -Internally, the ring buffer always maintains an empty 32-bit block in the -buffer to distinguish between empty and full buffers. Any given entry -in the buffer will use a 32-bit block for metadata plus any data attached. -If the size of the buffer array is a power of two, the ring buffer will -use more efficient masking instead of expensive modulo operations to -maintain itself. - -Concurrency -*********** - -Concurrency control of ring buffers is not implemented at this level. -Depending on usage (particularly with respect to number of concurrent -readers/writers) applications may need to protect the ring buffer with -mutexes and/or use semaphores to notify consumers that there is data to -read. - -For the trivial case of one producer and one consumer, concurrency -shouldn't be needed. - -Example: Initializing a Ring Buffer -=================================== - -There are three ways to initialize a ring buffer. The first two are through use -of macros which defines one (and an associated private buffer) in file scope. -You can declare a fast ring buffer that uses mask operations by declaring -a power-of-two sized buffer: - -.. code-block:: c - - /* Buffer with 2^8 or 256 elements */ - SYS_RING_BUF_DECLARE_POW2(my_ring_buf, 8); - -Arbitrary-sized buffers may also be declared with a different macro, but -these will always be slower due to use of modulo operations: - -.. code-block:: c - - #define MY_RING_BUF_SIZE 93 - SYS_RING_BUF_DECLARE_SIZE(my_ring_buf, MY_RING_BUF_SIZE); - -Alternatively, a ring buffer may be initialized manually. Whether the buffer -will use modulo or mask operations will be detected automatically: - -.. code-block:: c - - #define MY_RING_BUF_SIZE 64 - - struct my_struct { - struct ring_buffer rb; - uint32_t buffer[MY_RING_BUF_SIZE]; - ... - }; - struct my_struct ms; - - void init_my_struct { - sys_ring_buf_init(&ms.rb, sizeof(ms.buffer), ms.buffer); - ... - } - -Example: Enqueuing data -======================= - -.. code-block:: c - - int ret; - - ret = sys_ring_buf_put(&ring_buf, TYPE_FOO, 0, &my_foo, SIZE32_OF(my_foo)); - if (ret == -EMSGSIZE) { - ... not enough room for the message .. - } - -If the type or value fields are sufficient, the data pointer and size may be 0. - -.. code-block:: c - - int ret; - - ret = sys_ring_buf_put(&ring_buf, TYPE_BAR, 17, NULL, 0); - if (ret == -EMSGSIZE) { - ... not enough room for the message .. - } - -Example: Retrieving data -======================== - -.. code-block:: c - - int ret; - uint32_t data[6]; - - size = SIZE32_OF(data); - ret = sys_ring_buf_get(&ring_buf, &type, &value, data, &size); - if (ret == -EMSGSIZE) { - printk("Buffer is too small, need %d uint32_t\n", size); - } else if (ret == -EAGAIN) { - printk("Ring buffer is empty\n"); - } else { - printk("got item of type %u value &u of size %u dwords\n", - type, value, size); - ... - } - -APIs -**** - -The following APIs for ring buffers are provided by :file:`ring_buffer.h`: - -:cpp:func:`sys_ring_buf_init()` - Initializes a ring buffer. - -:c:func:`SYS_RING_BUF_DECLARE_POW2()`, :c:func:`SYS_RING_BUF_DECLARE_SIZE()` - Declare and init a file-scope ring buffer. - -:cpp:func:`sys_ring_buf_space_get()` - Returns the amount of free buffer storage space in 32-bit dwords. - -:cpp:func:`sys_ring_buf_is_empty()` - Indicates whether a buffer is empty. - -:cpp:func:`sys_ring_buf_put()` - Enqueues an item. - -:cpp:func:`sys_ring_buf_get()` - De-queues an item. diff --git a/doc/kernel/nanokernel/nanokernel_stacks.rst b/doc/kernel/nanokernel/nanokernel_stacks.rst deleted file mode 100644 index fa0d752fa97..00000000000 --- a/doc/kernel/nanokernel/nanokernel_stacks.rst +++ /dev/null @@ -1,142 +0,0 @@ -.. _nanokernel_stacks: - -Nanokernel Stacks -################# - -Concepts -******** - -The nanokernel's stack object type is an implementation of a traditional -last in, first out queue for a limited number of 32-bit data values. -It is mainly intended for use by fibers. - -Each stack uses an array of 32-bit words to hold its data values. The array -may be of any size, but must be aligned on a 4-byte boundary. - -Any number of nanokernel stacks can be defined. Each stack is a distinct -variable of type :c:type:`struct nano_stack`, and is referenced using a pointer -to that variable. A stack must be initialized to use its array before it -can be used to send or receive data values. - -Data values can be added to a stack in a non-blocking manner by any context type -(i.e. ISR, fiber, or task). - -.. note:: - A context must not attempt to add a data value to a stack whose array - is already full, as the resulting array overflow will lead to - unpredictable behavior. - -Data values can be removed from a stack in a non-blocking manner by any context -type; if the stack is empty a special return code indicates that no data value -was removed. Data values can also be removed from a stack in a blocking manner -by a fiber or task; if the stack is empty the fiber or task waits for a data -value to be added. - -Only a single fiber, but any number of tasks, may wait on an empty nanokernel -stack simultaneously. When a data value becomes available it is given to the -waiting fiber, or to a waiting task if no fiber is waiting. - -.. note:: - The nanokernel does not allow more than one fiber to wait on a nanokernel - stack. If a second fiber starts waiting the first waiting fiber is - superseded and ends up waiting forever. - - A task that waits on an empty nanokernel stack does a busy wait. This is - not an issue for a nanokernel application's background task; however, in - a microkernel application a task that waits on a nanokernel stack remains - the current task. In contrast, a microkernel task that waits on a - microkernel data passing object ceases to be the current task, allowing - other tasks of equal or lower priority to do useful work. - - If multiple tasks in a microkernel application wait on the same nanokernel - stack, higher priority tasks are given data values in preference to lower - priority tasks. However, the order in which equal priority tasks are given - data values is unpredictable. - -Purpose -******* - -Use a nanokernel stack to store and retrieve 32-bit data values in a "last in, -first out" manner, when the maximum number of stored items is known. - -Usage -***** - -Example: Initializing a Nanokernel Stack -======================================== - -This code establishes an empty nanokernel stack capable of holding -up to 10 items. - -.. code-block:: c - - #define MAX_ALARMS 10 - - struct nano_stack alarm_stack; - - uint32_t stack_area[MAX_ALARMS]; - - ... - - nano_stack_init(&alarm_stack, stack_area); - -Example: Writing to a Nanokernel Stack -====================================== - -This code shows how an ISR can use a nanokernel stack to pass a 32-bit alarm -indication to a processing fiber. - -.. code-block:: c - - #define OVERHEAT_ALARM 17 - - void overheat_interrupt_handler(void *arg) - { - ... - /* report alarm */ - nano_isr_stack_push(&alarm_stack, OVERHEAT_ALARM); - ... - } - -Example: Reading from a Nanokernel Stack -======================================== - -This code shows how a fiber can use a nanokernel stack to retrieve 32-bit alarm -indications signalled by other parts of the application, -such as ISRs and other fibers. It is assumed that the fiber can handle -bursts of alarms before the stack overflows, and that the order -in which alarms are processed isn't significant. - -.. code-block:: c - - void alarm_handler_fiber(int arg1, int arg2) - { - uint32_t alarm_number; - - while (1) { - /* wait for an alarm to be reported */ - alarm_number = nano_fiber_stack_pop(&alarm_stack, TICKS_UNLIMITED); - /* process alarm indication */ - ... - } - } - -APIs -**** - -The following APIs for a nanokernel stack are provided by -:file:`nanokernel.h`: - -:cpp:func:`nano_stack_init()` - - Initializes a stack. - -:cpp:func:`nano_task_stack_push()`, :cpp:func:`nano_fiber_stack_push()`, -:cpp:func:`nano_isr_stack_push()`, :cpp:func:`nano_stack_push()` - - Add an item to a stack. - -:cpp:func:`nano_task_stack_pop()`, :cpp:func:`nano_fiber_stack_pop()`, -:cpp:func:`nano_isr_stack_pop()`, :cpp:func:`nano_stack_pop()` - - Remove an item from a stack, or wait for an item if it is empty. diff --git a/doc/kernel/nanokernel/nanokernel_synchronization.rst b/doc/kernel/nanokernel/nanokernel_synchronization.rst deleted file mode 100644 index e4e5111697a..00000000000 --- a/doc/kernel/nanokernel/nanokernel_synchronization.rst +++ /dev/null @@ -1,133 +0,0 @@ -.. _nanokernel_synchronization: - -Synchronization Services -######################## - -This section describes synchronization services provided by the nanokernel. -Currently, only a single service is provided. - -.. _nanokernel_semaphores: - -Nanokernel Semaphores -********************* - -Concepts -======== - -The nanokernel's :dfn:`semaphore` object type is an implementation of a -traditional counting semaphore. It is mainly intended for use by fibers. - -Any number of nanokernel semaphores can be defined. Each semaphore is a -distinct variable of type :c:type:`struct nano_sem`, and is referenced -using a pointer to that variable. A semaphore must be initialized before -it can be used. - -A nanokernel semaphore's count is set to zero when the semaphore is initialized. -This count is incremented each time the semaphore is given, and is decremented -each time the semaphore is taken. However, a semaphore cannot be taken if it is -unavailable; that is, when it has a count of zero. - -A nanokernel semaphore may be **given** by any context type: ISRs, fibers, -or tasks. - -A nanokernel semaphore may be **taken in a non-blocking manner** by any -context type; a special return code indicates if the semaphore is unavailable. -A semaphore can also be **taken in a blocking manner** by a fiber or task; -if the semaphore is unavailable, the thread waits for it to be given. - -Any number of threads may wait on an unavailable nanokernel semaphore -simultaneously. When the semaphore is signaled, it is given to the fiber -that has waited longest, or to a waiting task when no fiber is waiting. - -.. note:: - A task that waits on an unavailable nanokernel FIFO semaphore busy-waits. - This is not an issue for a nanokernel application's background task; - however, in a microkernel application a task that waits on a nanokernel - semaphore remains the current task. In contrast, a microkernel task that - waits on a microkernel synchronization object ceases to be the current task, - allowing other tasks of equal or lower priority to do useful work. - -When multiple tasks in a microkernel application are waiting on the same nanokernel -semaphore, higher priority tasks are given the semaphore in preference to -lower priority tasks. However, the order in which equal priority tasks are given -the semaphore is unpredictable. - -Purpose -======= - -Use a nanokernel semaphore to control access to a set of resources by multiple -fibers. - -Use a nanokernel semaphore to synchronize processing between a producing task and -fiber, or among an ISR and one or more consuming fibers. - -Usage -===== - -Example: Initializing a Nanokernel Semaphore --------------------------------------------- - -This code initializes a nanokernel semaphore, setting its count to zero. - -.. code-block:: c - - struct nano_sem input_sem; - - nano_sem_init(&input_sem); - -Example: Giving a Nanokernel Semaphore from an ISR --------------------------------------------------- - -This code uses a nanokernel semaphore to indicate that a unit of data -is available for processing by a consumer fiber. - -.. code-block:: c - - void input_data_interrupt_handler(void *arg) - { - /* notify fiber that data is available */ - nano_isr_sem_give(&input_sem); - - ... - } - -Example: Taking a Nanokernel Semaphore with a Conditional Time-out ------------------------------------------------------------------- - -This code waits up to 500 ticks for a nanokernel semaphore to be given, -and gives warning if it is not obtained in that time. - -.. code-block:: c - - void consumer_fiber(void) - { - ... - - if (nano_fiber_sem_take(&input_sem, 500) != 1) { - printk("Input data not available!"); - } else { - /* fetch available data */ - ... - } - ... - } - -APIs -==== - -The following APIs for a nanokernel semaphore are provided -by :file:`nanokernel.h`: - -:cpp:func:`nano_sem_init()` - - Initialize a semaphore. - -:cpp:func:`nano_task_sem_give()`, :cpp:func:`nano_fiber_sem_give()`, -:cpp:func:`nano_isr_sem_give()`, :cpp:func:`nano_sem_give()` - - Signal a sempahore. - -:cpp:func:`nano_task_sem_take()`, :cpp:func:`nano_fiber_sem_take()`, -:cpp:func:`nano_isr_sem_take()`, :cpp:func:`nano_sem_take()` - - Wait on a semaphore for a specified time period. diff --git a/doc/kernel/nanokernel/nanokernel_tasks.rst b/doc/kernel/nanokernel/nanokernel_tasks.rst deleted file mode 100644 index 27e9ba1dc01..00000000000 --- a/doc/kernel/nanokernel/nanokernel_tasks.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. _nanokernel_tasks: - -Task Services -############# - -Concepts -******** - -A :dfn:`task` is a preemptible thread of execution that implements a portion of -an application's processing. It is normally used to perform processing that is -too lengthy or too complex to be performed by a fiber or an ISR. - -A nanokernel application can define a single application task, known as the -*background task*, which can execute only when no fiber or ISR needs to -execute. The entry point function for the background task is :code:`main()`, -and it must be supplied by the application. - -.. note:: - The background task is very different from the tasks used by a microkernel - application; for more information see :ref:`microkernel_tasks`. - - -Task Lifecycle -============== - -The kernel automatically starts the background task during system -initialization. - -Once the background task is started, it executes forever. If the task attempts -to terminate by returning from :code:`main()`, the kernel puts the task into -a permanent idling state since the background task must always be available -to execute. - - -Task Scheduling -=============== - -The nanokernel's scheduler executes the background task only when no fiber or -ISR needs to execute; fiber and ISR executions always take precedence. - -The kernel automatically saves the background task's CPU register values when -prompted for a context switch to a fiber or ISR. These values are restored -when the background task later resumes execution. - - -Usage -***** - -Defining the Background Task -============================ - -The application must supply a function of the following form: - -.. code-block:: c - - void main(void) - { - /* background task processing */ - ... - /* (optional) enter permanent idling state */ - return; - } - -This function is used as the background task's entry point function. If a -nanokernel application does not need to perform any task-level processing, -:code:`main()` can simply do an immediate return. - -The :option:`CONFIG_MAIN_STACK_SIZE` configuration option specifies -the size, in bytes, of the memory region used for the background -task's stack and for other execution context information. - -APIs -**** - -The nanokernel provides the following API for manipulating the background task. - -:cpp:func:`task_sleep()` - Put the background task to sleep for a specified time period. diff --git a/doc/kernel/nanokernel/nanokernel_timers.rst b/doc/kernel/nanokernel/nanokernel_timers.rst deleted file mode 100644 index dbe0fe26bcc..00000000000 --- a/doc/kernel/nanokernel/nanokernel_timers.rst +++ /dev/null @@ -1,179 +0,0 @@ -.. _nanokernel_timers: - -Timer Services -############## - -Concepts -******** - -The nanokernel's :dfn:`timer` object type uses the kernel's system clock to -monitor the passage of time, as measured in ticks. It is mainly intended for use -by fibers. - -A *nanokernel timer* allows a fiber or task to determine whether or not a -specified time limit has been reached while the thread itself is busy performing -other work. A thread can use more than one timer when it needs to monitor multiple -time intervals simultaneously. - -A nanokernel timer points to a *user data structure* that is supplied by the -thread that uses it; this pointer is returned when the timer expires. The user -data structure must be at least 4 bytes long and aligned on a 4-byte boundary, -as the kernel reserves the first 32 bits of this area for its own use. Any -remaining bytes of this area can be used to hold data that is helpful to the -thread that uses the timer. - -Any number of nanokernel timers can be defined. Each timer is a distinct -variable of type :c:type:`struct nano_timer`, and is referenced using a pointer -to that variable. A timer must be initialized with its user data structure -before it can be used. - -A nanokernel timer is started by specifying a *duration*, which is the number -of ticks the timer counts before it expires. - -.. note:: - Care must be taken when specifying the duration of a nanokernel timer, - since the first tick measured by the timer after it is started will be - less than a full tick interval. For example, when the system clock period - is 10 milliseconds, starting a timer than expires after 1 tick will result - in the timer expiring anywhere from a fraction of a millisecond - later to just slightly less than 10 milliseconds later. To ensure that - a timer doesn't expire for at least ``N`` ticks it is necessary to specify - a duration of ``N+1`` ticks. - -Once started, a nanokernel timer can be tested in either a non-blocking or -blocking manner to allow a thread to determine if the timer has expired. -If the timer has expired, the kernel returns the pointer to the user data -structure. If the timer has not expired, the kernel either returns -:c:macro:`NULL` (for a non-blocking test), or it waits for the timer to expire -(for a blocking test). - -.. note:: - The nanokernel does not allow more than one thread to wait on a nanokernel - timer at any given time. If a second thread starts waiting, only the first - waiting thread wakes up when the timer expires. The second thread continues - waiting. - - A task that waits on a nanokernel timer does a ``busy wait``. This is - not an issue for a nanokernel application's background task; however, in - a microkernel application, a task that waits on a nanokernel timer remains - the *current task* and prevents other tasks of equal or lower priority - from doing useful work. - -A nanokernel timer can be cancelled after it has been started. Cancelling -a timer while it is still running causes the timer to expire immediately, -thereby unblocking any thread waiting on the timer. Cancelling a timer -that has already expired has no effect on the timer. - -A nanokernel timer can be reused once it has expired, but must **not** be -restarted while it is still running. If desired, a timer can be re-initialized -with a different user data structure before it is started again. - - -Purpose -******* - -Use a nanokernel timer to determine whether or not a specified number -of system clock ticks have elapsed while a fiber or task is busy performing -other work. - -.. note:: - If a fiber or task has no other work to perform while waiting - for time to pass, it can simply call :cpp:func:`fiber_sleep()` - or :cpp:func:`task_sleep()`, respectively. - -.. note:: - The kernel provides additional APIs that allow a fiber or task to monitor - the system clock, as well as the higher precision hardware clock, - without using a nanokernel timer. - - -Usage -***** - -Example: Initializing a Nanokernel Timer -======================================== - -This code initializes a nanokernel timer. - -.. code-block:: c - - struct nano_timer my_timer; - uint32_t data_area[3] = { 0, 1111, 2222 }; - - nano_timer_init(&my_timer, data_area); - - -Example: Starting a Nanokernel Timer -==================================== -This code uses the above nanokernel timer to limit the amount of time a fiber -spends gathering data before processing it. - -.. code-block:: c - - /* set timer to expire in 10 ticks */ - nano_fiber_timer_start(&my_timer, 10); - - /* gather data until timer expires */ - do { - ... - } while (nano_fiber_timer_test(&my_timer, TICKS_NONE) == NULL); - - /* process the data */ - ... - - -Example: Cancelling a Nanokernel Timer -====================================== -This code illustrates how an active nanokernel timer can be stopped prematurely. - -.. code-block:: c - - struct nano_timer my_timer; - uint32_t dummy; - - ... - - /* set timer to expire in 10 ticks */ - nano_timer_init(&my_timer, &dummy); - nano_fiber_timer_start(&my_timer, 10); - - /* do work while waiting for an input signal to arrive */ - ... - - /* now have input signal, so stop the timer if it is still running */ - nano_fiber_timer_stop(&my_timer); - - /* check to see if the timer expired before it was stopped */ - if (nano_fiber_timer_test(&my_timer, TICKS_NONE) != NULL) { - printf("Warning: Input signal took too long to arrive!"); - } - - -APIs -**** - -APIs for a nanokernel timer provided by :file:`nanokernel.h` -============================================================ - -:cpp:func:`nano_timer_init()` - - Initialize a timer. - -:cpp:func:`nano_task_timer_start()`, :cpp:func:`nano_fiber_timer_start()`, -:cpp:func:`nano_isr_timer_start()`, :cpp:func:`nano_timer_start()` - - Start a timer. - -:cpp:func:`nano_task_timer_test()`, :cpp:func:`nano_fiber_timer_test()`, -:cpp:func:`nano_isr_timer_test()`, :cpp:func:`nano_timer_test()` - - Wait or test for timer expiration. - -:cpp:func:`nano_task_timer_stop()`, :cpp:func:`nano_fiber_timer_stop()`, -:cpp:func:`nano_isr_timer_stop()`, :cpp:func:`nano_timer_stop()` - - Force timer expiration, if not already expired. - -:cpp:func:`nano_timer_ticks_remain()` - - Return timer ticks before timer expiration. diff --git a/doc/kernel/overview/figures/overview_nanokernel_1.svg b/doc/kernel/overview/figures/overview_nanokernel_1.svg deleted file mode 100644 index a4b9c4966df..00000000000 --- a/doc/kernel/overview/figures/overview_nanokernel_1.svg +++ /dev/null @@ -1,52 +0,0 @@ - - -image/svg+xmlHello World -! -Prints out -He ll o World -! -on the -console -. -TIMER -Starts a timer -. -Waits for timer -to expire -. -TIMER -SEMAPHORE -Signals the -semaphore of -the fiber -. -SEMAPHORE -Waits for -semaphore to -be signaled -. -Waits for -semaphore to -be signaled -. -Prints out -Hello World -! -on the -console -. -TIMER -Starts a timer -. -Waits for timer -to expire -. -TIMER -Signals the -semaphore of -the task -. -TASK -FIBER -NANOKERNEL - diff --git a/doc/kernel/overview/kernel_fundamentals.rst b/doc/kernel/overview/kernel_fundamentals.rst deleted file mode 100644 index 05394aa4be8..00000000000 --- a/doc/kernel/overview/kernel_fundamentals.rst +++ /dev/null @@ -1,372 +0,0 @@ -.. _kernel_fundamentals: - -Kernel Fundamentals -################### - -This section provides a high-level overview of the concepts and capabilities -of the Zephyr kernel. - -Organization -************ - -The central elements of the Zephyr kernel are its *microkernel* and underlying -*nanokernel*. The kernel also contains a variety of auxiliary subsystems, -including a library of device drivers and networking software. - -Applications can be developed using both the microkernel and the nanokernel, -or using the nanokernel only. - -The nanokernel is a high-performance, multi-threaded execution environment -with a basic set of kernel features. The nanokernel is ideal for systems -with sparse memory (the kernel itself requires as little as 2 KB!) or only -simple multi-threading requirements (such as a set of interrupt -handlers and a single background task). Examples of such systems include: -embedded sensor hubs, environmental sensors, simple LED wearables, and -store inventory tags. - -The microkernel supplements the capabilities of the nanokernel to provide -a richer set of kernel features. The microkernel is suitable for systems -with heftier memory (50 to 900 KB), multiple communication devices -(like WIFI and Bluetooth Low Energy), and multiple data processing tasks. -Examples of such systems include: fitness wearables, smart watches, and -IoT wireless gateways. - -Related sections: - -* :ref:`common` -* :ref:`nanokernel` -* :ref:`microkernel` - -Multi-threading -*************** - -The Zephyr kernel supports multi-threaded processing for three types -of execution contexts. - -* A **task context** is a preemptible thread, normally used to perform - processing that is lengthy or complex. Task scheduling is priority-based, - so that the execution of a higher priority task preempts the execution - of a lower priority task. The kernel also supports an optional round-robin - time slicing capability so that equal priority tasks can execute in turn, - without the risk of any one task monopolizing the CPU. - -* A **fiber context** is a lightweight and non-preemptible thread, typically - used for device drivers and performance critical work. Fiber scheduling is - priority-based, so that a higher priority fiber is scheduled for execution - before a lower priority fiber; however, once a fiber is scheduled it remains - scheduled until it performs an operation that blocks its own execution. - Fiber execution takes precedence over task execution, so tasks execute only - when no fiber can be scheduled. - -* The **interrupt context** is a special kernel context used to execute - :abbr:`ISRs Interrupt Service Routines`. The interrupt context takes - precedence over all other contexts, so tasks and fibers execute only - when no ISR needs to run. (See below for more on interrupt handling.) - -The Zephyr microkernel does not limit the number of tasks or fibers used -in an application; however, an application that uses only the nanokernel -is limited to a single task. - -Related sections: - -* :ref:`Nanokernel Fiber Services ` -* :ref:`Microkernel Task Services ` - -Interrupts -********** - -The Zephyr kernel supports the handling of hardware interrupts and software -interrupts by interrupt handlers, also known as ISRs. Interrupt handling takes -precedence over task and fiber processing, so that an ISR preempts the currently -scheduled task or fiber whenever it needs to run. The kernel also supports nested -interrupt handling, allowing a higher priority ISR to interrupt the execution of -a lower priority ISR, should the need arise. - -The nanokernel supplies ISRs for a few interrupt sources (IRQs), such as the -hardware timer device and system console device. The ISRs for all other IRQs -are supplied by either device drivers or application code. Each ISR can -be registered with the kernel at compile time, but can also be registered -dynamically once the kernel is up and running. Zephyr supports ISRs that -are written entirely in C, but also permits the use of assembly language. - -In situations where an ISR cannot complete the processing of an interrupt in a -timely manner by itself, the kernel's synchronization and data passing mechanisms -can hand off the remaining processing to a fiber or task. - -Related sections: - -* :ref:`Nanokernel Interrupt Services ` - -Clocks and Timers -***************** - -Kernel clocking is based on time units called :dfn:`ticks` which have a -configurable duration. A 64-bit *system clock* counts the number of ticks -that have elapsed since the kernel started executing. - -Zephyr also supports a higher-resolution *hardware clock*, which can be used -to measure durations requiring sub-tick interval precision. - -The nanokernel allows a fiber or thread to perform time-based processing -based on the system clock. This can be done either by using a nanokernel API -that supports a *timeout* argument, or by using a *timer* object that can -be set to expire after a specified number of ticks. - -The microkernel also allows tasks to perform time-based processing using -timeouts and timers. Microkernel timers have additional capabilities -not provided by nanokernel timers, such as a periodic expiration mode. - -Related sections: - -* :ref:`common_kernel_clocks` -* :ref:`Nanokernel Timer Services ` -* :ref:`Microkernel Timers Services ` - -Synchronization -*************** - -The Zephyr kernel provides four types of objects that allow different -contexts to synchronize their execution. - -The microkernel provides the object types listed below. These types -are intended for tasks, with limited ability to be used by fibers and ISRs. - -* A :dfn:`semaphore` is a counting semaphore, which indicates how many units - of a particular resource are available. - -* An :dfn:`event` is a binary semaphore, which simply indicates if a particular - resource is available or not. - -* A :dfn:`mutex` is a reentrant mutex with priority inversion protection. It is - similar to a binary semaphore, but contains additional logic to ensure that - only the owner of the associated resource can release it and to expedite the - execution of a lower priority thread that holds a resource needed by a - higher priority thread. - -The nanokernel provides the object type listed below. This type -is intended for fibers, with only limited ability to be used by tasks and ISRs. - -* A :dfn:`nanokernel semaphore` is a counting semaphore that indicates - how many units of a particular resource are available. - -Each type has specific capabilities and limitations that affect suitability -of use in a given situation. For more details, see the documentation for each -specific object type. - -Related sections: - -* :ref:`Microkernel Synchronization Services ` -* :ref:`Nanokernel Synchronization Services ` - -Data Passing -************ - -The Zephyr kernel provides six types of objects that allow different -contexts to exchange data. - -The microkernel provides the object types listed below. These types are -designed to be used by tasks, and cannot be used by fibers and ISRs. - -* A :dfn:`microkernel FIFO` is a queuing mechanism that allows tasks to exchange - fixed-size data items in an asychronous :abbr:`First In, First Out (FIFO)` - manner. - -* A :dfn:`mailbox` is a queuing mechanism that allows tasks to exchange - variable-size data items in a synchronous, "first in, first out" manner. - Mailboxes also support asynchronous exchanges, and allow tasks to exchange - messages both anonymously and non-anonymously using the same mailbox. - -* A :dfn:`pipe` is a queuing mechanism that allows a task to send a stream - of bytes to another task. Both asynchronous and synchronous exchanges - can be supported by a pipe. - -The nanokernel provides the object types listed below. These types are -primarily designed to be used by fibers, and have only a limited ability -to be used by tasks and ISRs. - -* A :dfn:`nanokernel FIFO` is a queuing mechanism that allows contexts to exchange - variable-size data items in an asychronous, first-in, first-out manner. - -* A :dfn:`nanokernel LIFO` is a queuing mechanism that allows contexts to exchange - variable-size data items in an asychronous, last-in, first-out manner. - -* A :dfn:`nanokernel stack` is a queuing mechanism that allows contexts to exchange - 32-bit data items in an asynchronous first-in, first-out manner. - -Each of these types has specific capabilities and limitations that affect -suitability for use in a given situation. For more details, see the -documentation for each specific object type. - -Related sections: - -* :ref:`Microkernel Data Passing Services ` -* :ref:`Nanokernel Data Passing Services ` - -Dynamic Memory Allocation -************************* - -The Zephyr kernel requires all system resources to be defined at compile-time, -and therefore provides only limited support for dynamic memory allocation. -This support can be used in place of C standard library calls like -:c:func:`malloc()` and :c:func:`free()`, albeit with certain differences. - -The microkernel provides two types of objects that allow tasks to dynamically -allocate memory blocks. These object types cannot be used by fibers or ISRs. - -* A :dfn:`memory map` is a memory region that supports the dynamic allocation and - release of memory blocks of a single fixed size. An application can have - multiple memory maps, whose block size and block capacity can be configured - individually. - -* A :dfn:`memory pool` is a memory region that supports the dynamic allocation and - release of memory blocks of multiple fixed sizes. This allows more efficient - use of available memory when an application requires blocks of different - sizes. An application can have multiple memory pools, whose block sizes - and block capacity can be configured individually. - -The nanokernel does not provide any support for dynamic memory allocation. - -For additional information see: - -* :ref:`Microkernel Memory Maps ` -* :ref:`Microkernel Pools ` - -Public and Private Microkernel Objects -************************************** - -Microkernel objects, such as semaphores, mailboxes, or tasks, -can usually be defined as a public object or a private object. - -* A :dfn:`public object` is one that is available for general use by all parts - of the application. Any code that includes :file:`zephyr.h` can interact - with the object by referencing the object's name. - -* A :dfn:`private object` is one that is intended for use only by a specific - part of the application, such as a single device driver or subsystem. - The object's name is visible only to code within the file where the object - is defined, hiding it from general use unless the code which defined the - object takes additional steps to share the name with other files. - -Aside from the way they are defined, and the resulting visibility of -the object's name, a public object and a private object of the same type -operate in exactly the same manner using the same set of APIs. - -In most cases, the decision to make a given microkernel object a public -object or a private object is simply a matter of convenience. For example, -when defining a server-type subsystem that handles requests from multiple -clients, it usually makes sense to define public objects. - -.. note:: - Nanokernel object types can only be defined as private objects. This means - a nanokernel object must be defined using a global variable to allow it to - be accessed by code outside the file in which the object is defined. - - -.. _microkernel_server: - -Microkernel Server -****************** - -The microkernel performs most operations involving microkernel objects -using a special *microkernel server* fiber, called :c:func:`_k_server`. - -When a task invokes an API associated with a microkernel object type, -such as :c:func:`task_fifo_put()`, the associated operation is not -carried out directly. Instead, the following sequence of steps typically -occurs: - -#. The task creates a *command packet*, which contains the input parameters - needed to carry out the desired operation. - -#. The task queues the command packet on the microkernel server's - *command stack*. The kernel then preempts the task and schedules - the microkernel server. - -#. The microkernel server dequeues the command packet from its command - stack and performs the desired operation. All output parameters for the - operation, such as the return code, are saved in the command packet. - -#. When the operation is complete the microkernel server attempts - to fetch a command packet from its now empty command stack - and becomes blocked. The kernel then schedules the requesting task. - -#. The task processes the command packet's output parameters to determine - the results of the operation. - -The actual sequence of steps may vary from the above guideline in some -instances. For example, if the operation causes a higher-priority task -to become runnable, the requesting task is not scheduled for execution by -the kernel until *after* the higher priority task is first scheduled. -In addition, a few operations involving microkernel objects do not require -the use of a command packet at all. - -While this indirect execution approach may seem somewhat inefficient, -it actually has a number of important benefits: - -* All operations performed by the microkernel server are inherently free - from race conditions; operations are processed serially by a single fiber - that cannot be preempted by tasks or other fibers. This means the - microkernel server can manipulate any of the microkernel objects in the - system during any operation without having to take additional steps - to prevent interference by other contexts. - -* Microkernel operations have minimal impact on interrupt latency; - interrupts are never locked for a significant period to prevent race - conditions. - -* The microkernel server can easily decompose complex operations into two or - more simpler operations by creating additional command packets and queueing - them on the command stack. - -* The overall memory footprint of the system is reduced; a task using microkernel - objects only needs to provide stack space for the first step of the above sequence, - rather than for all steps required to perform the operation. - -For additional information see: - -* :ref:`Microkernel Server Fiber ` - -Standard C Library -****************** - -The Zephyr kernel currently provides only the minimal subset of the -standard C library required to meet the kernel's own needs, primarily -in the areas of string manipulation and display. - -Applications that require a more extensive C library can either submit -contributions that enhance the existing library or substitute -a replacement library. - -C++ Support for Applications -**************************** - -The Zephyr kernel supports applications written in both C and C++. However, to -use C++ in an application, you must configure your kernel to include C++ -support and the build system must select the correct compiler. - -The build system selects the C++ compiler based on the suffix of the files. -Files identified with either a **cxx** or a **cpp** suffix are compiled using -the C++ compiler. For example, :file:`myCplusplusApp.cpp`. - -The Zephyr kernel currently provides only a subset of C++ functionality. The -following features are not supported: - -* Dynamic object management with the **new** and **delete** operators -* :abbr:`RTTI (run-time type information)` -* Exceptions -* Static global object destruction - -While not an exhaustive list, support for the following functionality is -included: - -* Inheritance -* Virtual functions -* Virtual tables -* Static global object constructors - -Static global object constructors are initialized after the drivers are -initialized but before the application :c:func:`main()` function. Therefore, -use of C++ is restricted to application code. - -.. note:: - Do not use C++ for kernel, driver, or system initialization code. diff --git a/doc/kernel/overview/overview.rst b/doc/kernel/overview/overview.rst deleted file mode 100644 index ddbf64975ba..00000000000 --- a/doc/kernel/overview/overview.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _overview: - -Overview -######## - -This section provides a high level overview of the Zephyr kernel ecosystem. - -.. toctree:: - :maxdepth: 1 - - kernel_fundamentals.rst - source_tree.rst diff --git a/doc/kernel/overview/source_tree.rst b/doc/kernel/overview/source_tree.rst deleted file mode 100644 index b14577ebc25..00000000000 --- a/doc/kernel/overview/source_tree.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _source_tree: - -Source Tree Structure -##################### - -The Zephyr source tree provides the following top-level directories, -each of which may have one or more additional levels of subdirectories -which are not described here. - -:file:`arch` - Architecture-specific nanokernel and board code. Each supported - architecture has its own subdirectory, which contains additional - subdirectories for the following areas: - - * architecture-specific nanokernel source files - * architecture-specific nanokernel include files for private APIs - * board-specific code - -:file:`boards` - Board related code and configuration files. - -:file:`doc` - Zephyr documentation-related material and tools. - -:file:`drivers` - Device driver code. - -:file:`include` - Include files for all public APIs, except those defined under :file:`lib`. - -:file:`kernel` - Microkernel code, and architecture-independent nanokernel code. - -:file:`lib` - Library code, including the minimal standard C library. - -:file:`misc` - Miscellaneous code. - -:file:`net` - Networking code, including the Bluetooth stack and networking stacks. - -:file:`samples` - Sample applications for the microkernel, nanokernel, Bluetooth stack, - and networking stacks. - -:file:`tests` - Test code and benchmarks for the various kernel features. - -:file:`scripts` - Various programs and other files used to build and test Zephyr - applications. diff --git a/doc/kernel_v2/memory/pools.rst b/doc/kernel_v2/memory/pools.rst index 5a09eb94718..5c774841b3a 100644 --- a/doc/kernel_v2/memory/pools.rst +++ b/doc/kernel_v2/memory/pools.rst @@ -5,8 +5,7 @@ Memory Pools A :dfn:`memory pool` is a kernel object that allows memory blocks to be dynamically allocated from a designated memory region. -Unlike :ref:`memory map ` objects, -the memory blocks in a memory pool can be of any size, +The memory blocks in a memory pool can be of any size, thereby reducing the amount of wasted memory when an application needs to allocate storage for data structures of different sizes. The memory pool uses a "buddy memory allocation" algorithm diff --git a/doc/porting/arch.rst b/doc/porting/arch.rst index 8587f35fe7f..4f154174907 100644 --- a/doc/porting/arch.rst +++ b/doc/porting/arch.rst @@ -178,9 +178,6 @@ Two crucial concepts when writing an architecture port are the following: When talking about "the task" in this document, it refers to the task the nanokernel is currently aware of. -For a refresher on nanokernel and microkernel concepts, see -:ref:`kernel_fundamentals`. - A context switch can happen in several circumstances: * When a thread executes a blocking operation, such as taking a semaphore that