xref: /linux/rust/kernel/sync/poll.rs (revision dfa35434d7f20142fedd7120277b1044a0a2bb64)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2024 Google LLC.
4 
5 //! Utilities for working with `struct poll_table`.
6 
7 use crate::{
8     bindings,
9     fs::File,
10     prelude::*,
11     sync::{
12         rcu::synchronize_rcu,
13         CondVar,
14         LockClassKey, //
15     }, //
16 };
17 use core::{marker::PhantomData, ops::Deref};
18 
19 /// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class.
20 #[macro_export]
21 macro_rules! new_poll_condvar {
22     ($($name:literal)?) => {
23         $crate::sync::poll::PollCondVar::new(
24             $crate::optional_name!($($name)?), $crate::static_lock_class!()
25         )
26     };
27 }
28 
29 /// Wraps the kernel's `poll_table`.
30 ///
31 /// # Invariants
32 ///
33 /// The pointer must be null or reference a valid `poll_table`.
34 #[repr(transparent)]
35 pub struct PollTable<'a> {
36     table: *mut bindings::poll_table,
37     _lifetime: PhantomData<&'a bindings::poll_table>,
38 }
39 
40 impl<'a> PollTable<'a> {
41     /// Creates a [`PollTable`] from a valid pointer.
42     ///
43     /// # Safety
44     ///
45     /// The pointer must be null or reference a valid `poll_table` for the duration of `'a`.
46     pub unsafe fn from_raw(table: *mut bindings::poll_table) -> Self {
47         // INVARIANTS: The safety requirements are the same as the struct invariants.
48         PollTable {
49             table,
50             _lifetime: PhantomData,
51         }
52     }
53 
54     /// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified
55     /// using the condition variable.
56     pub fn register_wait(&self, file: &File, cv: &PollCondVar) {
57         // SAFETY:
58         // * `file.as_ptr()` references a valid file for the duration of this call.
59         // * `self.table` is null or references a valid poll_table for the duration of this call.
60         // * Since `PollCondVar` is pinned, its destructor is guaranteed to run before the memory
61         //   containing `cv.wait_queue_head` is invalidated. Since the destructor clears all
62         //   waiters and then waits for an rcu grace period, it's guaranteed that
63         //   `cv.wait_queue_head` remains valid for at least an rcu grace period after the removal
64         //   of the last waiter.
65         unsafe { bindings::poll_wait(file.as_ptr(), cv.wait_queue_head.get(), self.table) }
66     }
67 }
68 
69 /// A wrapper around [`CondVar`] that makes it usable with [`PollTable`].
70 ///
71 /// [`CondVar`]: crate::sync::CondVar
72 #[pin_data(PinnedDrop)]
73 pub struct PollCondVar {
74     #[pin]
75     inner: CondVar,
76 }
77 
78 impl PollCondVar {
79     /// Constructs a new condvar initialiser.
80     pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
81         pin_init!(Self {
82             inner <- CondVar::new(name, key),
83         })
84     }
85 }
86 
87 // Make the `CondVar` methods callable on `PollCondVar`.
88 impl Deref for PollCondVar {
89     type Target = CondVar;
90 
91     fn deref(&self) -> &CondVar {
92         &self.inner
93     }
94 }
95 
96 #[pinned_drop]
97 impl PinnedDrop for PollCondVar {
98     #[inline]
99     fn drop(self: Pin<&mut Self>) {
100         // Clear anything registered using `register_wait`.
101         //
102         // SAFETY: The pointer points at a valid `wait_queue_head`.
103         unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.get()) };
104 
105         // Wait for epoll items to be properly removed.
106         synchronize_rcu();
107     }
108 }
109