4
4
//!
5
5
//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
6
6
7
- use crate :: bindings;
8
- use core:: { marker :: PhantomData , mem :: ManuallyDrop , ops:: Deref } ;
7
+ use crate :: { bindings, ARef , AlwaysRefCounted } ;
8
+ use core:: { cell :: UnsafeCell , marker :: PhantomData , ops:: Deref , ptr } ;
9
9
10
10
/// Wraps the kernel's `struct task_struct`.
11
11
///
12
12
/// # Invariants
13
13
///
14
- /// The pointer `Task::ptr` is non-null and valid. Its reference count is also non-zero.
14
+ /// Instances of this type are always ref-counted, that is, a call to `get_task_struct` ensures
15
+ /// that the allocation remains valid at least until the matching call to `put_task_struct`.
15
16
///
16
17
/// # Examples
17
18
///
@@ -36,28 +37,24 @@ use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
36
37
/// incremented when creating `State` and decremented when it is dropped:
37
38
///
38
39
/// ```
39
- /// use kernel::task::Task;
40
+ /// use kernel::{ARef, task::Task} ;
40
41
///
41
42
/// struct State {
42
- /// creator: Task,
43
+ /// creator: ARef< Task> ,
43
44
/// index: u32,
44
45
/// }
45
46
///
46
47
/// impl State {
47
48
/// fn new() -> Self {
48
49
/// Self {
49
- /// creator: Task::current().clone (),
50
+ /// creator: Task::current().into (),
50
51
/// index: 0,
51
52
/// }
52
53
/// }
53
54
/// }
54
55
/// ```
55
- pub struct Task {
56
- pub ( crate ) ptr : * mut bindings:: task_struct ,
57
- }
58
-
59
- // SAFETY: Given that the task is referenced, it is OK to send it to another thread.
60
- unsafe impl Send for Task { }
56
+ #[ repr( transparent) ]
57
+ pub struct Task ( pub ( crate ) UnsafeCell < bindings:: task_struct > ) ;
61
58
62
59
// SAFETY: It's OK to access `Task` through references from other threads because we're either
63
60
// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
@@ -73,103 +70,75 @@ impl Task {
73
70
// SAFETY: Just an FFI call.
74
71
let ptr = unsafe { bindings:: get_current ( ) } ;
75
72
76
- // SAFETY: If the current thread is still running, the current task is valid. Given
77
- // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where
78
- // it could potentially outlive the caller).
79
- unsafe { TaskRef :: from_ptr ( ptr) }
73
+ TaskRef {
74
+ // SAFETY: If the current thread is still running, the current task is valid. Given
75
+ // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread
76
+ // (where it could potentially outlive the caller).
77
+ task : unsafe { & * ptr. cast ( ) } ,
78
+ _not_send : PhantomData ,
79
+ }
80
80
}
81
81
82
82
/// Returns the group leader of the given task.
83
- pub fn group_leader ( & self ) -> TaskRef < ' _ > {
84
- // SAFETY: By the type invariant, we know that `self.ptr ` is non-null and valid.
85
- let ptr = unsafe { ( * self . ptr ) . group_leader } ;
83
+ pub fn group_leader ( & self ) -> & Task {
84
+ // SAFETY: By the type invariant, we know that `self.0 ` is valid.
85
+ let ptr = unsafe { core :: ptr :: addr_of! ( ( * self . 0 . get ( ) ) . group_leader) . read ( ) } ;
86
86
87
87
// SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
88
88
// and given that a task has a reference to its group leader, we know it must be valid for
89
89
// the lifetime of the returned task reference.
90
- unsafe { TaskRef :: from_ptr ( ptr) }
90
+ unsafe { & * ptr. cast ( ) }
91
91
}
92
92
93
93
/// Returns the PID of the given task.
94
94
pub fn pid ( & self ) -> Pid {
95
- // SAFETY: By the type invariant, we know that `self.ptr ` is non-null and valid.
96
- unsafe { ( * self . ptr ) . pid }
95
+ // SAFETY: By the type invariant, we know that `self.0 ` is valid.
96
+ unsafe { core :: ptr :: addr_of! ( ( * self . 0 . get ( ) ) . pid) . read ( ) }
97
97
}
98
98
99
99
/// Determines whether the given task has pending signals.
100
100
pub fn signal_pending ( & self ) -> bool {
101
- // SAFETY: By the type invariant, we know that `self.ptr ` is non-null and valid.
102
- unsafe { bindings:: signal_pending ( self . ptr ) != 0 }
101
+ // SAFETY: By the type invariant, we know that `self.0 ` is valid.
102
+ unsafe { bindings:: signal_pending ( self . 0 . get ( ) ) != 0 }
103
103
}
104
104
}
105
105
106
- impl PartialEq for Task {
107
- fn eq ( & self , other : & Self ) -> bool {
108
- self . ptr == other. ptr
106
+ // SAFETY: The type invariants guarantee that `Task` is always ref-counted.
107
+ unsafe impl AlwaysRefCounted for Task {
108
+ fn inc_ref ( & self ) {
109
+ // SAFETY: The existence of a shared reference means that the refcount is nonzero.
110
+ unsafe { bindings:: get_task_struct ( self . 0 . get ( ) ) } ;
109
111
}
110
- }
111
-
112
- impl Eq for Task { }
113
-
114
- impl Clone for Task {
115
- fn clone ( & self ) -> Self {
116
- // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
117
- unsafe { bindings:: get_task_struct ( self . ptr ) } ;
118
-
119
- // INVARIANT: We incremented the reference count to account for the new `Task` being
120
- // created.
121
- Self { ptr : self . ptr }
122
- }
123
- }
124
112
125
- impl Drop for Task {
126
- fn drop ( & mut self ) {
127
- // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so
128
- // this is not observable.
129
- // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count.
130
- unsafe { bindings:: put_task_struct ( self . ptr ) } ;
113
+ unsafe fn dec_ref ( obj : ptr:: NonNull < Self > ) {
114
+ // SAFETY: The safety requirements guarantee that the refcount is nonzero.
115
+ unsafe { bindings:: put_task_struct ( obj. cast ( ) . as_ptr ( ) ) }
131
116
}
132
117
}
133
118
134
- /// A wrapper for [`Task`] that doesn't automatically decrement the refcount when dropped.
135
- ///
136
- /// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
137
- /// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
138
- /// `unsafe` blocks because it would trigger an unbalanced call to `put_task_struct`.
119
+ /// A wrapper for a shared reference to [`Task`] that isn't [`Send`].
139
120
///
140
121
/// We make this explicitly not [`Send`] so that we can use it to represent the current thread
141
- /// without having to increment/decrement its reference count.
122
+ /// without having to increment/decrement the task's reference count.
142
123
///
143
124
/// # Invariants
144
125
///
145
126
/// The wrapped [`Task`] remains valid for the lifetime of the object.
146
127
pub struct TaskRef < ' a > {
147
- task : ManuallyDrop < Task > ,
148
- _not_send : PhantomData < ( & ' a ( ) , * mut ( ) ) > ,
149
- }
150
-
151
- impl TaskRef < ' _ > {
152
- /// Constructs a new `struct task_struct` wrapper that doesn't change its reference count.
153
- ///
154
- /// # Safety
155
- ///
156
- /// The pointer `ptr` must be non-null and valid for the lifetime of the object.
157
- pub ( crate ) unsafe fn from_ptr ( ptr : * mut bindings:: task_struct ) -> Self {
158
- Self {
159
- task : ManuallyDrop :: new ( Task { ptr } ) ,
160
- _not_send : PhantomData ,
161
- }
162
- }
128
+ task : & ' a Task ,
129
+ _not_send : PhantomData < * mut ( ) > ,
163
130
}
164
131
165
- // SAFETY: It is OK to share a reference to the current thread with another thread because we know
166
- // the owner cannot go away while the shared reference exists (and `Task` itself is `Sync`).
167
- unsafe impl Sync for TaskRef < ' _ > { }
168
-
169
132
impl Deref for TaskRef < ' _ > {
170
133
type Target = Task ;
171
134
172
135
fn deref ( & self ) -> & Self :: Target {
173
- self . task . deref ( )
136
+ self . task
137
+ }
138
+ }
139
+
140
+ impl From < TaskRef < ' _ > > for ARef < Task > {
141
+ fn from ( t : TaskRef < ' _ > ) -> Self {
142
+ t. deref ( ) . into ( )
174
143
}
175
144
}
0 commit comments