|
2 | 2 |
|
3 | 3 | //! Work queues.
|
4 | 4 | //!
|
| 5 | +//! This file has two components: The raw work item API, and the safe work item API. |
| 6 | +//! |
| 7 | +//! One pattern that is used in both APIs is the `ID` const generic, which exists to allow a single |
| 8 | +//! type to define multiple `work_struct` fields. This is done by choosing an id for each field, |
| 9 | +//! and using that id to specify which field you wish to use. (The actual value doesn't matter, as |
| 10 | +//! long as you use different values for different fields of the same struct.) Since these IDs are |
| 11 | +//! generic, they are used only at compile-time, so they shouldn't exist in the final binary. |
| 12 | +//! |
| 13 | +//! # The raw API |
| 14 | +//! |
| 15 | +//! The raw API consists of the `RawWorkItem` trait, where the work item needs to provide an |
| 16 | +//! arbitrary function that knows how to enqueue the work item. It should usually not be used |
| 17 | +//! directly, but if you want to, you can use it without using the pieces from the safe API. |
| 18 | +//! |
| 19 | +//! # The safe API |
| 20 | +//! |
| 21 | +//! The safe API is used via the `Work` struct and `WorkItem` traits. Furthermore, it also includes |
| 22 | +//! a trait called `WorkItemPointer`, which is usually not used directly by the user. |
| 23 | +//! |
| 24 | +//! * The `Work` struct is the Rust wrapper for the C `work_struct` type. |
| 25 | +//! * The `WorkItem` trait is implemented for structs that can be enqueued to a workqueue. |
| 26 | +//! * The `WorkItemPointer` trait is implemented for the pointer type that points at a something |
| 27 | +//! that implements `WorkItem`. |
| 28 | +//! |
5 | 29 | //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
|
6 | 30 |
|
7 |
| -use crate::{bindings, types::Opaque}; |
| 31 | +use crate::{bindings, prelude::*, sync::LockClassKey, types::Opaque}; |
| 32 | +use core::marker::PhantomData; |
| 33 | + |
| 34 | +/// Creates a [`Work`] initialiser with the given name and a newly-created lock class. |
| 35 | +#[macro_export] |
| 36 | +macro_rules! new_work { |
| 37 | + ($($name:literal)?) => { |
| 38 | + $crate::workqueue::Work::new($crate::optional_name!($($name)?), $crate::static_lock_class!()) |
| 39 | + }; |
| 40 | +} |
8 | 41 |
|
9 | 42 | /// A kernel work queue.
|
10 | 43 | ///
|
@@ -108,6 +141,228 @@ pub unsafe trait RawWorkItem<const ID: u64> {
|
108 | 141 | F: FnOnce(*mut bindings::work_struct) -> bool;
|
109 | 142 | }
|
110 | 143 |
|
| 144 | +/// Defines the method that should be called directly when a work item is executed. |
| 145 | +/// |
| 146 | +/// This trait is implemented by `Pin<Box<T>>` and `Arc<T>`, and is mainly intended to be |
| 147 | +/// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`] |
| 148 | +/// instead. The `run` method on this trait will usually just perform the appropriate |
| 149 | +/// `container_of` translation and then call into the `run` method from the [`WorkItem`] trait. |
| 150 | +/// |
| 151 | +/// This trait is used when the `work_struct` field is defined using the [`Work`] helper. |
| 152 | +/// |
| 153 | +/// # Safety |
| 154 | +/// |
| 155 | +/// Implementers must ensure that [`__enqueue`] uses a `work_struct` initialized with the [`run`] |
| 156 | +/// method of this trait as the function pointer. |
| 157 | +/// |
| 158 | +/// [`__enqueue`]: RawWorkItem::__enqueue |
| 159 | +/// [`run`]: WorkItemPointer::run |
| 160 | +pub unsafe trait WorkItemPointer<const ID: u64>: RawWorkItem<ID> { |
| 161 | + /// Run this work item. |
| 162 | + /// |
| 163 | + /// # Safety |
| 164 | + /// |
| 165 | + /// The provided `work_struct` pointer must originate from a previous call to `__enqueue` where |
| 166 | + /// the `queue_work_on` closure returned true, and the pointer must still be valid. |
| 167 | + unsafe extern "C" fn run(ptr: *mut bindings::work_struct); |
| 168 | +} |
| 169 | + |
| 170 | +/// Defines the method that should be called when this work item is executed. |
| 171 | +/// |
| 172 | +/// This trait is used when the `work_struct` field is defined using the [`Work`] helper. |
| 173 | +pub trait WorkItem<const ID: u64 = 0> { |
| 174 | + /// The pointer type that this struct is wrapped in. This will typically be `Arc<Self>` or |
| 175 | + /// `Pin<Box<Self>>`. |
| 176 | + type Pointer: WorkItemPointer<ID>; |
| 177 | + |
| 178 | + /// The method that should be called when this work item is executed. |
| 179 | + fn run(this: Self::Pointer); |
| 180 | +} |
| 181 | + |
| 182 | +/// Links for a work item. |
| 183 | +/// |
| 184 | +/// This struct contains a function pointer to the `run` function from the [`WorkItemPointer`] |
| 185 | +/// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue. |
| 186 | +/// |
| 187 | +/// Wraps the kernel's C `struct work_struct`. |
| 188 | +/// |
| 189 | +/// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it. |
| 190 | +#[repr(transparent)] |
| 191 | +pub struct Work<T: ?Sized, const ID: u64 = 0> { |
| 192 | + work: Opaque<bindings::work_struct>, |
| 193 | + _inner: PhantomData<T>, |
| 194 | +} |
| 195 | + |
| 196 | +// SAFETY: Kernel work items are usable from any thread. |
| 197 | +// |
| 198 | +// We do not need to constrain `T` since the work item does not actually contain a `T`. |
| 199 | +unsafe impl<T: ?Sized, const ID: u64> Send for Work<T, ID> {} |
| 200 | +// SAFETY: Kernel work items are usable from any thread. |
| 201 | +// |
| 202 | +// We do not need to constrain `T` since the work item does not actually contain a `T`. |
| 203 | +unsafe impl<T: ?Sized, const ID: u64> Sync for Work<T, ID> {} |
| 204 | + |
| 205 | +impl<T: ?Sized, const ID: u64> Work<T, ID> { |
| 206 | + /// Creates a new instance of [`Work`]. |
| 207 | + #[inline] |
| 208 | + #[allow(clippy::new_ret_no_self)] |
| 209 | + pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> |
| 210 | + where |
| 211 | + T: WorkItem<ID>, |
| 212 | + { |
| 213 | + // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as the work |
| 214 | + // item function. |
| 215 | + unsafe { |
| 216 | + kernel::init::pin_init_from_closure(move |slot| { |
| 217 | + let slot = Self::raw_get(slot); |
| 218 | + bindings::init_work_with_key( |
| 219 | + slot, |
| 220 | + Some(T::Pointer::run), |
| 221 | + false, |
| 222 | + name.as_char_ptr(), |
| 223 | + key.as_ptr(), |
| 224 | + ); |
| 225 | + Ok(()) |
| 226 | + }) |
| 227 | + } |
| 228 | + } |
| 229 | + |
| 230 | + /// Get a pointer to the inner `work_struct`. |
| 231 | + /// |
| 232 | + /// # Safety |
| 233 | + /// |
| 234 | + /// The provided pointer must not be dangling and must be properly aligned. (But the memory |
| 235 | + /// need not be initialized.) |
| 236 | + #[inline] |
| 237 | + pub unsafe fn raw_get(ptr: *const Self) -> *mut bindings::work_struct { |
| 238 | + // SAFETY: The caller promises that the pointer is aligned and not dangling. |
| 239 | + // |
| 240 | + // A pointer cast would also be ok due to `#[repr(transparent)]`. We use `addr_of!` so that |
| 241 | + // the compiler does not complain that the `work` field is unused. |
| 242 | + unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).work)) } |
| 243 | + } |
| 244 | +} |
| 245 | + |
| 246 | +/// Declares that a type has a [`Work<T, ID>`] field. |
| 247 | +/// |
| 248 | +/// The intended way of using this trait is via the [`impl_has_work!`] macro. You can use the macro |
| 249 | +/// like this: |
| 250 | +/// |
| 251 | +/// ```no_run |
| 252 | +/// use kernel::impl_has_work; |
| 253 | +/// use kernel::prelude::*; |
| 254 | +/// use kernel::workqueue::Work; |
| 255 | +/// |
| 256 | +/// struct MyWorkItem { |
| 257 | +/// work_field: Work<MyWorkItem, 1>, |
| 258 | +/// } |
| 259 | +/// |
| 260 | +/// impl_has_work! { |
| 261 | +/// impl HasWork<MyWorkItem, 1> for MyWorkItem { self.work_field } |
| 262 | +/// } |
| 263 | +/// ``` |
| 264 | +/// |
| 265 | +/// Note that since the `Work` type is annotated with an id, you can have several `work_struct` |
| 266 | +/// fields by using a different id for each one. |
| 267 | +/// |
| 268 | +/// # Safety |
| 269 | +/// |
| 270 | +/// The [`OFFSET`] constant must be the offset of a field in Self of type [`Work<T, ID>`]. The methods on |
| 271 | +/// this trait must have exactly the behavior that the definitions given below have. |
| 272 | +/// |
| 273 | +/// [`Work<T, ID>`]: Work |
| 274 | +/// [`impl_has_work!`]: crate::impl_has_work |
| 275 | +/// [`OFFSET`]: HasWork::OFFSET |
| 276 | +pub unsafe trait HasWork<T, const ID: u64 = 0> { |
| 277 | + /// The offset of the [`Work<T, ID>`] field. |
| 278 | + /// |
| 279 | + /// [`Work<T, ID>`]: Work |
| 280 | + const OFFSET: usize; |
| 281 | + |
| 282 | + /// Returns the offset of the [`Work<T, ID>`] field. |
| 283 | + /// |
| 284 | + /// This method exists because the [`OFFSET`] constant cannot be accessed if the type is not Sized. |
| 285 | + /// |
| 286 | + /// [`Work<T, ID>`]: Work |
| 287 | + /// [`OFFSET`]: HasWork::OFFSET |
| 288 | + #[inline] |
| 289 | + fn get_work_offset(&self) -> usize { |
| 290 | + Self::OFFSET |
| 291 | + } |
| 292 | + |
| 293 | + /// Returns a pointer to the [`Work<T, ID>`] field. |
| 294 | + /// |
| 295 | + /// # Safety |
| 296 | + /// |
| 297 | + /// The provided pointer must point at a valid struct of type `Self`. |
| 298 | + /// |
| 299 | + /// [`Work<T, ID>`]: Work |
| 300 | + #[inline] |
| 301 | + unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work<T, ID> { |
| 302 | + // SAFETY: The caller promises that the pointer is valid. |
| 303 | + unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut Work<T, ID> } |
| 304 | + } |
| 305 | + |
| 306 | + /// Returns a pointer to the struct containing the [`Work<T, ID>`] field. |
| 307 | + /// |
| 308 | + /// # Safety |
| 309 | + /// |
| 310 | + /// The pointer must point at a [`Work<T, ID>`] field in a struct of type `Self`. |
| 311 | + /// |
| 312 | + /// [`Work<T, ID>`]: Work |
| 313 | + #[inline] |
| 314 | + unsafe fn work_container_of(ptr: *mut Work<T, ID>) -> *mut Self |
| 315 | + where |
| 316 | + Self: Sized, |
| 317 | + { |
| 318 | + // SAFETY: The caller promises that the pointer points at a field of the right type in the |
| 319 | + // right kind of struct. |
| 320 | + unsafe { (ptr as *mut u8).sub(Self::OFFSET) as *mut Self } |
| 321 | + } |
| 322 | +} |
| 323 | + |
| 324 | +/// Used to safely implement the [`HasWork<T, ID>`] trait. |
| 325 | +/// |
| 326 | +/// # Examples |
| 327 | +/// |
| 328 | +/// ``` |
| 329 | +/// use kernel::impl_has_work; |
| 330 | +/// use kernel::sync::Arc; |
| 331 | +/// use kernel::workqueue::{self, Work}; |
| 332 | +/// |
| 333 | +/// struct MyStruct { |
| 334 | +/// work_field: Work<MyStruct, 17>, |
| 335 | +/// } |
| 336 | +/// |
| 337 | +/// impl_has_work! { |
| 338 | +/// impl HasWork<MyStruct, 17> for MyStruct { self.work_field } |
| 339 | +/// } |
| 340 | +/// ``` |
| 341 | +/// |
| 342 | +/// [`HasWork<T, ID>`]: HasWork |
| 343 | +#[macro_export] |
| 344 | +macro_rules! impl_has_work { |
| 345 | + ($(impl$(<$($implarg:ident),*>)? |
| 346 | + HasWork<$work_type:ty $(, $id:tt)?> |
| 347 | + for $self:ident $(<$($selfarg:ident),*>)? |
| 348 | + { self.$field:ident } |
| 349 | + )*) => {$( |
| 350 | + // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right |
| 351 | + // type. |
| 352 | + unsafe impl$(<$($implarg),*>)? $crate::workqueue::HasWork<$work_type $(, $id)?> for $self $(<$($selfarg),*>)? { |
| 353 | + const OFFSET: usize = ::core::mem::offset_of!(Self, $field) as usize; |
| 354 | + |
| 355 | + #[inline] |
| 356 | + unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_type $(, $id)?> { |
| 357 | + // SAFETY: The caller promises that the pointer is not dangling. |
| 358 | + unsafe { |
| 359 | + ::core::ptr::addr_of_mut!((*ptr).$field) |
| 360 | + } |
| 361 | + } |
| 362 | + } |
| 363 | + )*}; |
| 364 | +} |
| 365 | + |
111 | 366 | /// Returns the system work queue (`system_wq`).
|
112 | 367 | ///
|
113 | 368 | /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are
|
|
0 commit comments