differences.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. .. SPDX-License-Identifier: GPL-2.0
  2. ===========================
  3. How realtime kernels differ
  4. ===========================
  5. :Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  6. Preface
  7. =======
  8. With forced-threaded interrupts and sleeping spin locks, code paths that
  9. previously caused long scheduling latencies have been made preemptible and
  10. moved into process context. This allows the scheduler to manage them more
  11. effectively and respond to higher-priority tasks with reduced latency.
  12. The following chapters provide an overview of key differences between a
  13. PREEMPT_RT kernel and a standard, non-PREEMPT_RT kernel.
  14. Locking
  15. =======
  16. Spinning locks such as spinlock_t are used to provide synchronization for data
  17. structures accessed from both interrupt context and process context. For this
  18. reason, locking functions are also available with the _irq() or _irqsave()
  19. suffixes, which disable interrupts before acquiring the lock. This ensures that
  20. the lock can be safely acquired in process context when interrupts are enabled.
  21. However, on a PREEMPT_RT system, interrupts are forced-threaded and no longer
  22. run in hard IRQ context. As a result, there is no need to disable interrupts as
  23. part of the locking procedure when using spinlock_t.
  24. For low-level core components such as interrupt handling, the scheduler, or the
  25. timer subsystem the kernel uses raw_spinlock_t. This lock type preserves
  26. traditional semantics: it disables preemption and, when used with _irq() or
  27. _irqsave(), also disables interrupts. This ensures proper synchronization in
  28. critical sections that must remain non-preemptible or with interrupts disabled.
  29. Execution context
  30. =================
  31. Interrupt handling in a PREEMPT_RT system is invoked in process context through
  32. the use of threaded interrupts. Other parts of the kernel also shift their
  33. execution into threaded context by different mechanisms. The goal is to keep
  34. execution paths preemptible, allowing the scheduler to interrupt them when a
  35. higher-priority task needs to run.
  36. Below is an overview of the kernel subsystems involved in this transition to
  37. threaded, preemptible execution.
  38. Interrupt handling
  39. ------------------
  40. All interrupts are forced-threaded in a PREEMPT_RT system. The exceptions are
  41. interrupts that are requested with the IRQF_NO_THREAD, IRQF_PERCPU, or
  42. IRQF_ONESHOT flags.
  43. The IRQF_ONESHOT flag is used together with threaded interrupts, meaning those
  44. registered using request_threaded_irq() and providing only a threaded handler.
  45. Its purpose is to keep the interrupt line masked until the threaded handler has
  46. completed.
  47. If a primary handler is also provided in this case, it is essential that the
  48. handler does not acquire any sleeping locks, as it will not be threaded. The
  49. handler should be minimal and must avoid introducing delays, such as
  50. busy-waiting on hardware registers.
  51. Soft interrupts, bottom half handling
  52. -------------------------------------
  53. Soft interrupts are raised by the interrupt handler and are executed after the
  54. handler returns. Since they run in thread context, they can be preempted by
  55. other threads. Do not assume that softirq context runs with preemption
  56. disabled. This means you must not rely on mechanisms like local_bh_disable() in
  57. process context to protect per-CPU variables. Because softirq handlers are
  58. preemptible under PREEMPT_RT, this approach does not provide reliable
  59. synchronization.
  60. If this kind of protection is required for performance reasons, consider using
  61. local_lock_nested_bh(). On non-PREEMPT_RT kernels, this allows lockdep to
  62. verify that bottom halves are disabled. On PREEMPT_RT systems, it adds the
  63. necessary locking to ensure proper protection.
  64. Using local_lock_nested_bh() also makes the locking scope explicit and easier
  65. for readers and maintainers to understand.
  66. per-CPU variables
  67. -----------------
  68. Protecting access to per-CPU variables solely by using preempt_disable() should
  69. be avoided, especially if the critical section has unbounded runtime or may
  70. call APIs that can sleep.
  71. If using a spinlock_t is considered too costly for performance reasons,
  72. consider using local_lock_t. On non-PREEMPT_RT configurations, this introduces
  73. no runtime overhead when lockdep is disabled. With lockdep enabled, it verifies
  74. that the lock is only acquired in process context and never from softirq or
  75. hard IRQ context.
  76. On a PREEMPT_RT kernel, local_lock_t is implemented using a per-CPU spinlock_t,
  77. which provides safe local protection for per-CPU data while keeping the system
  78. preemptible.
  79. Because spinlock_t on PREEMPT_RT does not disable preemption, it cannot be used
  80. to protect per-CPU data by relying on implicit preemption disabling. If this
  81. inherited preemption disabling is essential and if local_lock_t cannot be used
  82. due to performance constraints, brevity of the code, or abstraction boundaries
  83. within an API then preempt_disable_nested() may be a suitable alternative. On
  84. non-PREEMPT_RT kernels, it verifies with lockdep that preemption is already
  85. disabled. On PREEMPT_RT, it explicitly disables preemption.
  86. Timers
  87. ------
  88. By default, an hrtimer is executed in hard interrupt context. The exception is
  89. timers initialized with the HRTIMER_MODE_SOFT flag, which are executed in
  90. softirq context.
  91. On a PREEMPT_RT kernel, this behavior is reversed: hrtimers are executed in
  92. softirq context by default, typically within the ktimersd thread. This thread
  93. runs at the lowest real-time priority, ensuring it executes before any
  94. SCHED_OTHER tasks but does not interfere with higher-priority real-time
  95. threads. To explicitly request execution in hard interrupt context on
  96. PREEMPT_RT, the timer must be marked with the HRTIMER_MODE_HARD flag.
  97. Memory allocation
  98. -----------------
  99. The memory allocation APIs, such as kmalloc() and alloc_pages(), require a
  100. gfp_t flag to indicate the allocation context. On non-PREEMPT_RT kernels, it is
  101. necessary to use GFP_ATOMIC when allocating memory from interrupt context or
  102. from sections where preemption is disabled. This is because the allocator must
  103. not sleep in these contexts waiting for memory to become available.
  104. However, this approach does not work on PREEMPT_RT kernels. The memory
  105. allocator in PREEMPT_RT uses sleeping locks internally, which cannot be
  106. acquired when preemption is disabled. Fortunately, this is generally not a
  107. problem, because PREEMPT_RT moves most contexts that would traditionally run
  108. with preemption or interrupts disabled into threaded context, where sleeping is
  109. allowed.
  110. What remains problematic is code that explicitly disables preemption or
  111. interrupts. In such cases, memory allocation must be performed outside the
  112. critical section.
  113. This restriction also applies to memory deallocation routines such as kfree()
  114. and free_pages(), which may also involve internal locking and must not be
  115. called from non-preemptible contexts.
  116. IRQ work
  117. --------
  118. The irq_work API provides a mechanism to schedule a callback in interrupt
  119. context. It is designed for use in contexts where traditional scheduling is not
  120. possible, such as from within NMI handlers or from inside the scheduler, where
  121. using a workqueue would be unsafe.
  122. On non-PREEMPT_RT systems, all irq_work items are executed immediately in
  123. interrupt context. Items marked with IRQ_WORK_LAZY are deferred until the next
  124. timer tick but are still executed in interrupt context.
  125. On PREEMPT_RT systems, the execution model changes. Because irq_work callbacks
  126. may acquire sleeping locks or have unbounded execution time, they are handled
  127. in thread context by a per-CPU irq_work kernel thread. This thread runs at the
  128. lowest real-time priority, ensuring it executes before any SCHED_OTHER tasks
  129. but does not interfere with higher-priority real-time threads.
  130. The exception are work items marked with IRQ_WORK_HARD_IRQ, which are still
  131. executed in hard interrupt context. Lazy items (IRQ_WORK_LAZY) continue to be
  132. deferred until the next timer tick and are also executed by the irq_work/
  133. thread.
  134. RCU callbacks
  135. -------------
  136. RCU callbacks are invoked by default in softirq context. Their execution is
  137. important because, depending on the use case, they either free memory or ensure
  138. progress in state transitions. Running these callbacks as part of the softirq
  139. chain can lead to undesired situations, such as contention for CPU resources
  140. with other SCHED_OTHER tasks when executed within ksoftirqd.
  141. To avoid running callbacks in softirq context, the RCU subsystem provides a
  142. mechanism to execute them in process context instead. This behavior can be
  143. enabled by setting the boot command-line parameter rcutree.use_softirq=0. This
  144. setting is enforced in kernels configured with PREEMPT_RT.
  145. Spin until ready
  146. ================
  147. The "spin until ready" pattern involves repeatedly checking (spinning on) the
  148. state of a data structure until it becomes available. This pattern assumes that
  149. preemption, soft interrupts, or interrupts are disabled. If the data structure
  150. is marked busy, it is presumed to be in use by another CPU, and spinning should
  151. eventually succeed as that CPU makes progress.
  152. Some examples are hrtimer_cancel() or timer_delete_sync(). These functions
  153. cancel timers that execute with interrupts or soft interrupts disabled. If a
  154. thread attempts to cancel a timer and finds it active, spinning until the
  155. callback completes is safe because the callback can only run on another CPU and
  156. will eventually finish.
  157. On PREEMPT_RT kernels, however, timer callbacks run in thread context. This
  158. introduces a challenge: a higher-priority thread attempting to cancel the timer
  159. may preempt the timer callback thread. Since the scheduler cannot migrate the
  160. callback thread to another CPU due to affinity constraints, spinning can result
  161. in livelock even on multiprocessor systems.
  162. To avoid this, both the canceling and callback sides must use a handshake
  163. mechanism that supports priority inheritance. This allows the canceling thread
  164. to suspend until the callback completes, ensuring forward progress without
  165. risking livelock.
  166. In order to solve the problem at the API level, the sequence locks were extended
  167. to allow a proper handover between the the spinning reader and the maybe
  168. blocked writer.
  169. Sequence locks
  170. --------------
  171. Sequence counters and sequential locks are documented in
  172. Documentation/locking/seqlock.rst.
  173. The interface has been extended to ensure proper preemption states for the
  174. writer and spinning reader contexts. This is achieved by embedding the writer
  175. serialization lock directly into the sequence counter type, resulting in
  176. composite types such as seqcount_spinlock_t or seqcount_mutex_t.
  177. These composite types allow readers to detect an ongoing write and actively
  178. boost the writer’s priority to help it complete its update instead of spinning
  179. and waiting for its completion.
  180. If the plain seqcount_t is used, extra care must be taken to synchronize the
  181. reader with the writer during updates. The writer must ensure its update is
  182. serialized and non-preemptible relative to the reader. This cannot be achieved
  183. using a regular spinlock_t because spinlock_t on PREEMPT_RT does not disable
  184. preemption. In such cases, using seqcount_spinlock_t is the preferred solution.
  185. However, if there is no spinning involved i.e., if the reader only needs to
  186. detect whether a write has started and not serialize against it then using
  187. seqcount_t is reasonable.