Skip to content

Commit 7e9b161

Browse files
committed
rust: introduce current
This allows Rust code to get a reference to the current task without having to increment the refcount, but still guaranteeing memory safety. Cc: Ingo Molnar <[email protected]> Cc: Peter Zijlstra <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent b952b78 commit 7e9b161

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

rust/helpers.c

+6
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ bool rust_helper_refcount_dec_and_test(refcount_t *r)
100100
}
101101
EXPORT_SYMBOL_GPL(rust_helper_refcount_dec_and_test);
102102

103+
struct task_struct *rust_helper_get_current(void)
104+
{
105+
return current;
106+
}
107+
EXPORT_SYMBOL_GPL(rust_helper_get_current);
108+
103109
void rust_helper_get_task_struct(struct task_struct *t)
104110
{
105111
get_task_struct(t);

rust/kernel/prelude.rs

+2
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ pub use super::error::{code::*, Error, Result};
3636
pub use super::{str::CStr, ThisModule};
3737

3838
pub use super::init::{InPlaceInit, Init, PinInit};
39+
40+
pub use super::current;

rust/kernel/task.rs

+87-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@
55
//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
66
77
use crate::{bindings, types::Opaque};
8-
use core::ptr;
8+
use core::{marker::PhantomData, ops::Deref, ptr};
9+
10+
/// Returns the currently running task.
11+
#[macro_export]
12+
macro_rules! current {
13+
() => {
14+
// SAFETY: Deref + addr-of below create a temporary `TaskRef` that cannot outlive the
15+
// caller.
16+
unsafe { &*$crate::task::Task::current() }
17+
};
18+
}
919

1020
/// Wraps the kernel's `struct task_struct`.
1121
///
@@ -15,6 +25,42 @@ use core::ptr;
1525
///
1626
/// Instances of this type are always ref-counted, that is, a call to `get_task_struct` ensures
1727
/// that the allocation remains valid at least until the matching call to `put_task_struct`.
28+
///
29+
/// # Examples
30+
///
31+
/// The following is an example of getting the PID of the current thread with zero additional cost
32+
/// when compared to the C version:
33+
///
34+
/// ```
35+
/// let pid = current!().pid();
36+
/// ```
37+
///
38+
/// Getting the PID of the current process, also zero additional cost:
39+
///
40+
/// ```
41+
/// let pid = current!().group_leader().pid();
42+
/// ```
43+
///
44+
/// Getting the current task and storing it in some struct. The reference count is automatically
45+
/// incremented when creating `State` and decremented when it is dropped:
46+
///
47+
/// ```
48+
/// use kernel::{task::Task, types::ARef};
49+
///
50+
/// struct State {
51+
/// creator: ARef<Task>,
52+
/// index: u32,
53+
/// }
54+
///
55+
/// impl State {
56+
/// fn new() -> Self {
57+
/// Self {
58+
/// creator: current!().into(),
59+
/// index: 0,
60+
/// }
61+
/// }
62+
/// }
63+
/// ```
1864
#[repr(transparent)]
1965
pub struct Task(pub(crate) Opaque<bindings::task_struct>);
2066

@@ -27,6 +73,46 @@ unsafe impl Sync for Task {}
2773
type Pid = bindings::pid_t;
2874

2975
impl Task {
76+
/// Returns a task reference for the currently executing task/thread.
77+
///
78+
/// The recommended way to get the current task/thread is to use the
79+
/// [`current`](crate::current) macro because it is safe.
80+
///
81+
/// # Safety
82+
///
83+
/// Callers must ensure that the returned object doesn't outlive the current task/thread.
84+
pub unsafe fn current() -> impl Deref<Target = Task> {
85+
pub struct TaskRef<'a> {
86+
task: &'a Task,
87+
_not_send: PhantomData<*mut ()>,
88+
}
89+
90+
impl Deref for TaskRef<'_> {
91+
type Target = Task;
92+
93+
fn deref(&self) -> &Self::Target {
94+
self.task
95+
}
96+
}
97+
98+
impl From<TaskRef<'_>> for crate::types::ARef<Task> {
99+
fn from(t: TaskRef<'_>) -> Self {
100+
t.deref().into()
101+
}
102+
}
103+
104+
// SAFETY: Just an FFI call with no additional safety requirements.
105+
let ptr = unsafe { bindings::get_current() };
106+
107+
TaskRef {
108+
// SAFETY: If the current thread is still running, the current task is valid. Given
109+
// that `TaskRef` is not `Send`, we know it cannot be transferred to another thread
110+
// (where it could potentially outlive the caller).
111+
task: unsafe { &*ptr.cast() },
112+
_not_send: PhantomData,
113+
}
114+
}
115+
30116
/// Returns the group leader of the given task.
31117
pub fn group_leader(&self) -> &Task {
32118
// SAFETY: By the type invariant, we know that `self.0` is a valid task. Valid tasks always

0 commit comments

Comments
 (0)