@@ -9,9 +9,8 @@ use crate::{
9
9
fs:: File ,
10
10
prelude:: * ,
11
11
sync:: { CondVar , LockClassKey } ,
12
- types:: Opaque ,
13
12
} ;
14
- use core:: ops:: Deref ;
13
+ use core:: { marker :: PhantomData , ops:: Deref } ;
15
14
16
15
/// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class.
17
16
#[ macro_export]
@@ -23,58 +22,43 @@ macro_rules! new_poll_condvar {
23
22
} ;
24
23
}
25
24
26
- /// Wraps the kernel's `struct poll_table`.
25
+ /// Wraps the kernel's `poll_table`.
27
26
///
28
27
/// # Invariants
29
28
///
30
- /// This struct contains a valid `struct poll_table`.
31
- ///
32
- /// For a `struct poll_table` to be valid, its `_qproc` function must follow the safety
33
- /// requirements of `_qproc` functions:
34
- ///
35
- /// * The `_qproc` function is given permission to enqueue a waiter to the provided `poll_table`
36
- /// during the call. Once the waiter is removed and an rcu grace period has passed, it must no
37
- /// longer access the `wait_queue_head`.
29
+ /// The pointer must be null or reference a valid `poll_table`.
38
30
#[ repr( transparent) ]
39
- pub struct PollTable ( Opaque < bindings:: poll_table > ) ;
31
+ pub struct PollTable < ' a > {
32
+ table : * mut bindings:: poll_table ,
33
+ _lifetime : PhantomData < & ' a bindings:: poll_table > ,
34
+ }
40
35
41
- impl PollTable {
42
- /// Creates a reference to a [`PollTable`] from a valid pointer.
36
+ impl < ' a > PollTable < ' a > {
37
+ /// Creates a [`PollTable`] from a valid pointer.
43
38
///
44
39
/// # Safety
45
40
///
46
- /// The caller must ensure that for the duration of `'a`, the pointer will point at a valid poll
47
- /// table (as defined in the type invariants).
48
- ///
49
- /// The caller must also ensure that the `poll_table` is only accessed via the returned
50
- /// reference for the duration of `'a`.
51
- pub unsafe fn from_ptr < ' a > ( ptr : * mut bindings:: poll_table ) -> & ' a mut PollTable {
52
- // SAFETY: The safety requirements guarantee the validity of the dereference, while the
53
- // `PollTable` type being transparent makes the cast ok.
54
- unsafe { & mut * ptr. cast ( ) }
55
- }
56
-
57
- fn get_qproc ( & self ) -> bindings:: poll_queue_proc {
58
- let ptr = self . 0 . get ( ) ;
59
- // SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc`
60
- // field is not modified concurrently with this call since we have an immutable reference.
61
- unsafe { ( * ptr) . _qproc }
41
+ /// The pointer must be null or reference a valid `poll_table` for the duration of `'a`.
42
+ pub unsafe fn from_raw ( table : * mut bindings:: poll_table ) -> Self {
43
+ // INVARIANTS: The safety requirements are the same as the struct invariants.
44
+ PollTable {
45
+ table,
46
+ _lifetime : PhantomData ,
47
+ }
62
48
}
63
49
64
50
/// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified
65
51
/// using the condition variable.
66
- pub fn register_wait ( & mut self , file : & File , cv : & PollCondVar ) {
67
- if let Some ( qproc) = self . get_qproc ( ) {
68
- // SAFETY: The pointers to `file` and `self` need to be valid for the duration of this
69
- // call to `qproc`, which they are because they are references.
70
- //
71
- // The `cv.wait_queue_head` pointer must be valid until an rcu grace period after the
72
- // waiter is removed. The `PollCondVar` is pinned, so before `cv.wait_queue_head` can
73
- // be destroyed, the destructor must run. That destructor first removes all waiters,
74
- // and then waits for an rcu grace period. Therefore, `cv.wait_queue_head` is valid for
75
- // long enough.
76
- unsafe { qproc ( file. as_ptr ( ) as _ , cv. wait_queue_head . get ( ) , self . 0 . get ( ) ) } ;
77
- }
52
+ pub fn register_wait ( & self , file : & File , cv : & PollCondVar ) {
53
+ // SAFETY:
54
+ // * `file.as_ptr()` references a valid file for the duration of this call.
55
+ // * `self.table` is null or references a valid poll_table for the duration of this call.
56
+ // * Since `PollCondVar` is pinned, its destructor is guaranteed to run before the memory
57
+ // containing `cv.wait_queue_head` is invalidated. Since the destructor clears all
58
+ // waiters and then waits for an rcu grace period, it's guaranteed that
59
+ // `cv.wait_queue_head` remains valid for at least an rcu grace period after the removal
60
+ // of the last waiter.
61
+ unsafe { bindings:: poll_wait ( file. as_ptr ( ) , cv. wait_queue_head . get ( ) , self . table ) }
78
62
}
79
63
}
80
64
0 commit comments