Skip to content

Commit f56c5f3

Browse files
authored
Merge pull request #774 from wedsonaf/task-aref
rust: convert `Task` to use `ARef`
2 parents f7d8102 + 5cf1aaa commit f56c5f3

File tree

2 files changed

+46
-77
lines changed

2 files changed

+46
-77
lines changed

drivers/android/process.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ pub(crate) struct Process {
244244
ctx: Ref<Context>,
245245

246246
// The task leader (process).
247-
pub(crate) task: Task,
247+
pub(crate) task: ARef<Task>,
248248

249249
// Credential associated with file when `Process` is created.
250250
pub(crate) cred: ARef<Credential>,
@@ -269,7 +269,7 @@ impl Process {
269269
let mut process = Pin::from(UniqueRef::try_new(Self {
270270
ctx,
271271
cred,
272-
task: Task::current().group_leader().clone(),
272+
task: Task::current().group_leader().into(),
273273
// SAFETY: `inner` is initialised in the call to `mutex_init` below.
274274
inner: unsafe { Mutex::new(ProcessInner::new()) },
275275
// SAFETY: `node_refs` is initialised in the call to `mutex_init` below.
@@ -904,7 +904,7 @@ impl file::Operations for Process {
904904

905905
fn mmap(this: RefBorrow<'_, Process>, _file: &File, vma: &mut mm::virt::Area) -> Result {
906906
// We don't allow mmap to be used in a different process.
907-
if !Task::current().group_leader().eq(&this.task) {
907+
if !core::ptr::eq(Task::current().group_leader(), &*this.task) {
908908
return Err(EINVAL);
909909
}
910910

rust/kernel/task.rs

+43-74
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
//!
55
//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
66
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};
99

1010
/// Wraps the kernel's `struct task_struct`.
1111
///
1212
/// # Invariants
1313
///
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`.
1516
///
1617
/// # Examples
1718
///
@@ -36,28 +37,24 @@ use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};
3637
/// incremented when creating `State` and decremented when it is dropped:
3738
///
3839
/// ```
39-
/// use kernel::task::Task;
40+
/// use kernel::{ARef, task::Task};
4041
///
4142
/// struct State {
42-
/// creator: Task,
43+
/// creator: ARef<Task>,
4344
/// index: u32,
4445
/// }
4546
///
4647
/// impl State {
4748
/// fn new() -> Self {
4849
/// Self {
49-
/// creator: Task::current().clone(),
50+
/// creator: Task::current().into(),
5051
/// index: 0,
5152
/// }
5253
/// }
5354
/// }
5455
/// ```
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>);
6158

6259
// SAFETY: It's OK to access `Task` through references from other threads because we're either
6360
// accessing properties that don't change (e.g., `pid`, `group_leader`) or that are properly
@@ -73,103 +70,75 @@ impl Task {
7370
// SAFETY: Just an FFI call.
7471
let ptr = unsafe { bindings::get_current() };
7572

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+
}
8080
}
8181

8282
/// 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() };
8686

8787
// SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
8888
// and given that a task has a reference to its group leader, we know it must be valid for
8989
// the lifetime of the returned task reference.
90-
unsafe { TaskRef::from_ptr(ptr) }
90+
unsafe { &*ptr.cast() }
9191
}
9292

9393
/// Returns the PID of the given task.
9494
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() }
9797
}
9898

9999
/// Determines whether the given task has pending signals.
100100
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 }
103103
}
104104
}
105105

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()) };
109111
}
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-
}
124112

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()) }
131116
}
132117
}
133118

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`].
139120
///
140121
/// 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.
142123
///
143124
/// # Invariants
144125
///
145126
/// The wrapped [`Task`] remains valid for the lifetime of the object.
146127
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 ()>,
163130
}
164131

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-
169132
impl Deref for TaskRef<'_> {
170133
type Target = Task;
171134

172135
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()
174143
}
175144
}

0 commit comments

Comments
 (0)