From 16691f29a90b997fa399f4cfef0810ad75c0aa63 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Tue, 7 Nov 2023 19:09:06 +0100 Subject: [PATCH] Documentation: migrate "Bottom-Half Interrupt Handlers" from wiki link: https://cwiki.apache.org/confluence/display/NUTTX/Bottom-Half+Interrupt+Handlers Co-authored-by: hartmannathan <59230071+hartmannathan@users.noreply.github.com> --- .../implementation/bottomhalf_interrupt.rst | 135 ++++++++++++++++++ Documentation/implementation/index.rst | 1 + 2 files changed, 136 insertions(+) create mode 100644 Documentation/implementation/bottomhalf_interrupt.rst diff --git a/Documentation/implementation/bottomhalf_interrupt.rst b/Documentation/implementation/bottomhalf_interrupt.rst new file mode 100644 index 0000000000..18862dadfe --- /dev/null +++ b/Documentation/implementation/bottomhalf_interrupt.rst @@ -0,0 +1,135 @@ +============================== +Bottom-Half Interrupt Handlers +============================== + +RTOS Interrupts +=============== + +A well-design RTOS depends on the most minimal of interrupt level processing. +This is a very different concept that for bare metal programming: + +* With bare metal programming most of the real-time work is usually performed + in interrupt handlers. Interrupt handler execution may then extend in time + considerably due to this interrupt level processing. + +To compensate for this extended interrupt processing time, bare metal programmers +also need prioritized interrupts: + +* If an interrupt request for a higher priority interrupt occurs during the + extended processing of the lower priority interrupt, then that interrupt handler + will itself be interrupted to service the higher priority interrupt requests. + In this way bare metal interrupt handling is nested. + +With an RTOS, the real-time strategy is very different: + +* Interrupts must run very, very briefly so that they do not interfere with the + RTOS real-time scheduling. Normally, the interrupt simply performs whatever + minor housekeeping is necessary and then immediately defers processing by waking up + some task via some Inter-Process Communication(IPC). The RTOS is then responsible for + the real-time behavior, not the interrupt. And, + +* since the interrupts must be very brief, there is little or no gain from nesting of interrupts. + +Extending interrupt processing +============================== + +But what if extended interrupt processing is required? +What if there is a significant amount of hardware-related operations that absolutely +must be performed as quickly as possible before we can turn processing over to +general, real-time tasking? + +In NuttX, this is handled through a high priority trampoline called +the "High Priority Work Queue". It is a trampoline because it changes the interrupt +processing context for extended interrupt processing before notifying the normal +real-time task. + +Processing on that ultra-high priority work thread then completes the extended +interrupt processing with interrupts enabled, but without interference from any +other real-time tasks. + +At the completion of the extended processing, the high priority worker thread can +then continue processing via some IPC to a normal real-time task. + +The portion of interrupt processing that is performed in the interrupt handler with +interrupts disabled is referred to as Top Half Interrupt processing; the portion of +interrupt processing that is performed on the high priority work queue with interrupts +enabled is referred to as Bottom Half Interrupt processing. + +High Priority Work Queue +======================== + +NuttX supports a high priority work queue as well as a low priority work queue with +somewhat different properties. +The high priority work queue is dedicated to the support of Bottom Half Interrupt +processing. +Other uses of the high priority work queue may be inappropriate and may harm the +real-time performance of your system. + +The high priority work queue must have these properties: + +* **Highest Priority** The high priority work queue must be the highest priority + task in your system. No other task should execute at a higher priority; No other + task can be permitted to interfere with execution of the high priority work queue. + +* **Zero Latency Context Switches** Provided that the priority of the high priority + work queue is the highest in the system, then there will be no context switch + overhead in getting from the Top Half Interrupt processing to the Bottom Half + Interrupt processing other that the normal overhead of returning from an interrupt. + Upon return from the interrupt, the system will immediately vector to high priority + worker thread. + +* **Brief Processing** Processing on the high priority work queue must still be brief. + If there is high priority work in progress when the high priority worker is signaled, + then that processing will be queued and delayed until it can be processed. That delay + will add jitter to your real-time response. You must not generate a backlog of work + for the high priority worker thread! + +* **No Waiting** Work executing on the high priority work queue must not wait for + resources or events on the high priority worker thread. Waiting on the high priority + work queue blocks the queue and will, again, damage real-time performance. + +Setting Up Bottom Half Interrupt Processing +=========================================== + +Bottom half interrupt processing is scheduled by top half interrupt processing by +simply calling the function ``work_queue()``: + +.. code-block:: C + + int work_queue(int qid, FAR struct work_s *work, worker_t worker, + FAR void *arg, clock_t delay); + +This same interface is the same for both high- and low-priority. +The qid argument distinguishes which work queue will be used. For bottom half +interrupt processing, ``qid`` must be set to ``HPWORK``. + +The work argument is memory that will be used to actually queue the work. +It has no meaning to the caller; it is simply a memory allocation by the caller. +Otherwise, the work structure is completely managed by the work queue logic. +The caller should never modify the contents of the work queue structure directly. +If ``work_queue()`` is called before the previous work as been performed and removed +from the queue, then any pending work will be canceled and lost. +The ``work_available()`` function can be called to determine if the work represented +by the work structure is still in-use. + +For the interrupt handling case at hand, the work structure must be pre-allocated +or statically allocated since dynamic allocations are not supported from the +interrupt handling context. + +The ``worker`` is the name of the function that will perform the bottom half interrupt +work. +``arg`` is an arbitrary value that the user provides and will be given to the worker +function when it executes. +Normally ``arg`` produces some context in which the work will be performed. +The type of the worker function is given by: + +.. code-block:: C + + typedef CODE void (*worker_t)(FAR void *arg); + +Where ``arg`` has the same value as was passed to ``work_queue()``. + +Processing or work can be delayed in time. +The ``work_queue()`` ``delay`` argument provides that time delay in units of system +clock ticks. However, when used to provide bottom half interrupt processing, the +delay should always be zero. diff --git a/Documentation/implementation/index.rst b/Documentation/implementation/index.rst index ba0be0b7a9..f0b2433186 100644 --- a/Documentation/implementation/index.rst +++ b/Documentation/implementation/index.rst @@ -10,3 +10,4 @@ Implementation Details critical_sections.rst interrupt_controls.rst preemption_latency.rst + bottomhalf_interrupt.rst