1ac681835SAlice Ryhl // SPDX-License-Identifier: GPL-2.0 2ac681835SAlice Ryhl 3ac681835SAlice Ryhl // Copyright (C) 2024 Google LLC. 4ac681835SAlice Ryhl 5ac681835SAlice Ryhl //! Utilities for working with `struct poll_table`. 6ac681835SAlice Ryhl 7ac681835SAlice Ryhl use crate::{ 8ac681835SAlice Ryhl bindings, 9ac681835SAlice Ryhl fs::File, 10ac681835SAlice Ryhl prelude::*, 11ac681835SAlice Ryhl sync::{CondVar, LockClassKey}, 12ac681835SAlice Ryhl types::Opaque, 13ac681835SAlice Ryhl }; 14ac681835SAlice Ryhl use core::ops::Deref; 15ac681835SAlice Ryhl 16ac681835SAlice Ryhl /// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class. 17ac681835SAlice Ryhl #[macro_export] 18ac681835SAlice Ryhl macro_rules! new_poll_condvar { 19ac681835SAlice Ryhl ($($name:literal)?) => { 20ac681835SAlice Ryhl $crate::sync::poll::PollCondVar::new( 21ac681835SAlice Ryhl $crate::optional_name!($($name)?), $crate::static_lock_class!() 22ac681835SAlice Ryhl ) 23ac681835SAlice Ryhl }; 24ac681835SAlice Ryhl } 25ac681835SAlice Ryhl 26ac681835SAlice Ryhl /// Wraps the kernel's `struct poll_table`. 27ac681835SAlice Ryhl /// 28ac681835SAlice Ryhl /// # Invariants 29ac681835SAlice Ryhl /// 30ac681835SAlice Ryhl /// This struct contains a valid `struct poll_table`. 31ac681835SAlice Ryhl /// 32ac681835SAlice Ryhl /// For a `struct poll_table` to be valid, its `_qproc` function must follow the safety 33ac681835SAlice Ryhl /// requirements of `_qproc` functions: 34ac681835SAlice Ryhl /// 35ac681835SAlice Ryhl /// * The `_qproc` function is given permission to enqueue a waiter to the provided `poll_table` 36ac681835SAlice Ryhl /// during the call. Once the waiter is removed and an rcu grace period has passed, it must no 37ac681835SAlice Ryhl /// longer access the `wait_queue_head`. 38ac681835SAlice Ryhl #[repr(transparent)] 39ac681835SAlice Ryhl pub struct PollTable(Opaque<bindings::poll_table>); 40ac681835SAlice Ryhl 41ac681835SAlice Ryhl impl PollTable { 42ac681835SAlice Ryhl /// Creates a reference to a [`PollTable`] from a valid pointer. 43ac681835SAlice Ryhl /// 44ac681835SAlice Ryhl /// # Safety 45ac681835SAlice Ryhl /// 46*cd1ed11aSBorys Tyran /// The caller must ensure that for the duration of `'a`, the pointer will point at a valid poll 47ac681835SAlice Ryhl /// table (as defined in the type invariants). 48ac681835SAlice Ryhl /// 49ac681835SAlice Ryhl /// The caller must also ensure that the `poll_table` is only accessed via the returned 50*cd1ed11aSBorys Tyran /// reference for the duration of `'a`. 51ac681835SAlice Ryhl pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable { 52ac681835SAlice Ryhl // SAFETY: The safety requirements guarantee the validity of the dereference, while the 53ac681835SAlice Ryhl // `PollTable` type being transparent makes the cast ok. 54ac681835SAlice Ryhl unsafe { &mut *ptr.cast() } 55ac681835SAlice Ryhl } 56ac681835SAlice Ryhl 57ac681835SAlice Ryhl fn get_qproc(&self) -> bindings::poll_queue_proc { 58ac681835SAlice Ryhl let ptr = self.0.get(); 59ac681835SAlice Ryhl // SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc` 60ac681835SAlice Ryhl // field is not modified concurrently with this call since we have an immutable reference. 61ac681835SAlice Ryhl unsafe { (*ptr)._qproc } 62ac681835SAlice Ryhl } 63ac681835SAlice Ryhl 64ac681835SAlice Ryhl /// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified 65ac681835SAlice Ryhl /// using the condition variable. 66ac681835SAlice Ryhl pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) { 67ac681835SAlice Ryhl if let Some(qproc) = self.get_qproc() { 68ac681835SAlice Ryhl // SAFETY: The pointers to `file` and `self` need to be valid for the duration of this 69ac681835SAlice Ryhl // call to `qproc`, which they are because they are references. 70ac681835SAlice Ryhl // 71ac681835SAlice Ryhl // The `cv.wait_queue_head` pointer must be valid until an rcu grace period after the 72ac681835SAlice Ryhl // waiter is removed. The `PollCondVar` is pinned, so before `cv.wait_queue_head` can 73ac681835SAlice Ryhl // be destroyed, the destructor must run. That destructor first removes all waiters, 74ac681835SAlice Ryhl // and then waits for an rcu grace period. Therefore, `cv.wait_queue_head` is valid for 75ac681835SAlice Ryhl // long enough. 76ac681835SAlice Ryhl unsafe { qproc(file.as_ptr() as _, cv.wait_queue_head.get(), self.0.get()) }; 77ac681835SAlice Ryhl } 78ac681835SAlice Ryhl } 79ac681835SAlice Ryhl } 80ac681835SAlice Ryhl 81ac681835SAlice Ryhl /// A wrapper around [`CondVar`] that makes it usable with [`PollTable`]. 82ac681835SAlice Ryhl /// 83ac681835SAlice Ryhl /// [`CondVar`]: crate::sync::CondVar 84ac681835SAlice Ryhl #[pin_data(PinnedDrop)] 85ac681835SAlice Ryhl pub struct PollCondVar { 86ac681835SAlice Ryhl #[pin] 87ac681835SAlice Ryhl inner: CondVar, 88ac681835SAlice Ryhl } 89ac681835SAlice Ryhl 90ac681835SAlice Ryhl impl PollCondVar { 91ac681835SAlice Ryhl /// Constructs a new condvar initialiser. 92f73ca66fSMitchell Levy pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> { 93ac681835SAlice Ryhl pin_init!(Self { 94ac681835SAlice Ryhl inner <- CondVar::new(name, key), 95ac681835SAlice Ryhl }) 96ac681835SAlice Ryhl } 97ac681835SAlice Ryhl } 98ac681835SAlice Ryhl 99ac681835SAlice Ryhl // Make the `CondVar` methods callable on `PollCondVar`. 100ac681835SAlice Ryhl impl Deref for PollCondVar { 101ac681835SAlice Ryhl type Target = CondVar; 102ac681835SAlice Ryhl 103ac681835SAlice Ryhl fn deref(&self) -> &CondVar { 104ac681835SAlice Ryhl &self.inner 105ac681835SAlice Ryhl } 106ac681835SAlice Ryhl } 107ac681835SAlice Ryhl 108ac681835SAlice Ryhl #[pinned_drop] 109ac681835SAlice Ryhl impl PinnedDrop for PollCondVar { 110ac681835SAlice Ryhl fn drop(self: Pin<&mut Self>) { 111ac681835SAlice Ryhl // Clear anything registered using `register_wait`. 112ac681835SAlice Ryhl // 113ac681835SAlice Ryhl // SAFETY: The pointer points at a valid `wait_queue_head`. 114ac681835SAlice Ryhl unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.get()) }; 115ac681835SAlice Ryhl 116ac681835SAlice Ryhl // Wait for epoll items to be properly removed. 117ac681835SAlice Ryhl // 118ac681835SAlice Ryhl // SAFETY: Just an FFI call. 119ac681835SAlice Ryhl unsafe { bindings::synchronize_rcu() }; 120ac681835SAlice Ryhl } 121ac681835SAlice Ryhl } 122