kernel/interrupt.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Interrupt controls
4//!
5//! This module allows Rust code to annotate areas of code where local processor interrupts should
6//! be disabled, along with actually disabling local processor interrupts.
7//!
8//! # ⚠️ Warning! ⚠️
9//!
10//! The usage of this module can be more complicated than meets the eye, especially surrounding
11//! [preemptible kernels]. It's recommended to take care when using the functions and types defined
12//! here and familiarize yourself with the various documentation we have before using them, along
13//! with the various documents we link to here.
14//!
15//! # Reading material
16//!
17//! - [Software interrupts and realtime (LWN)](https://lwn.net/Articles/520076)
18//!
19//! [preemptible kernels]: https://www.kernel.org/doc/html/latest/locking/preempt-locking.html
20
21use crate::types::NotThreadSafe;
22
23/// A guard that represents local processor interrupt disablement on preemptible kernels.
24///
25/// [`LocalInterruptDisabled`] is a guard type that represents that local processor interrupts have
26/// been disabled on a preemptible kernel.
27///
28/// Certain functions take an immutable reference of [`LocalInterruptDisabled`] in order to require
29/// that they may only be run in local-interrupt-disabled contexts on preemptible kernels.
30///
31/// This is a marker type; it has no size, and is simply used as a compile-time guarantee that local
32/// processor interrupts are disabled on preemptible kernels. Note that no guarantees about the
33/// state of interrupts are made by this type on non-preemptible kernels.
34///
35/// # Invariants
36///
37/// Local processor interrupts are disabled on preemptible kernels for as long as an object of this
38/// type exists.
39pub struct LocalInterruptDisabled(NotThreadSafe);
40
41/// Disable local processor interrupts on a preemptible kernel.
42///
43/// This function disables local processor interrupts on a preemptible kernel, and returns a
44/// [`LocalInterruptDisabled`] token as proof of this. On non-preemptible kernels, this function is
45/// a no-op.
46///
47/// **Usage of this function is discouraged** unless you are absolutely sure you know what you are
48/// doing, as kernel interfaces for Rust that deal with interrupt state will typically handle local
49/// processor interrupt state management on their own and managing this by hand is quite error
50/// prone.
51#[inline]
52pub fn local_interrupt_disable() -> LocalInterruptDisabled {
53 // SAFETY: It's always safe to call `local_interrupt_disable()`.
54 unsafe { bindings::local_interrupt_disable() };
55
56 LocalInterruptDisabled(NotThreadSafe)
57}
58
59impl Drop for LocalInterruptDisabled {
60 #[inline]
61 fn drop(&mut self) {
62 // SAFETY: Per type invariants, a `local_interrupt_disable()` must be called to create this
63 // object, hence calling the corresponding `local_interrupt_enable()` is safe.
64 unsafe { bindings::local_interrupt_enable() };
65 }
66}
67
68impl LocalInterruptDisabled {
69 /// Assume that local processor interrupts are disabled on preemptible kernels.
70 ///
71 /// This can be used for annotating code that is known to be run in contexts where local
72 /// processor interrupts are disabled on preemptible kernels. It makes no changes to the local
73 /// interrupt state on its own.
74 ///
75 /// # Safety
76 ///
77 /// For the whole life `'a`, local interrupts must be disabled on preemptible kernels. This
78 /// could be a context like, for example, an interrupt handler.
79 #[inline]
80 pub unsafe fn assume_disabled<'a>() -> &'a LocalInterruptDisabled {
81 const ASSUME_DISABLED: &LocalInterruptDisabled = &LocalInterruptDisabled(NotThreadSafe);
82
83 // Confirm they're actually disabled if lockdep is available
84 // SAFETY: It's always safe to call `lockdep_assert_irqs_disabled()`.
85 unsafe { bindings::lockdep_assert_irqs_disabled() };
86
87 ASSUME_DISABLED
88 }
89}