5
5
//! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h).
6
6
7
7
use crate :: bindings;
8
- use core:: { cell:: UnsafeCell , ptr} ;
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
14
/// Instances of this type are always ref-counted, that is, a call to `get_task_struct` ensures
15
15
/// that the allocation remains valid at least until the matching call to `put_task_struct`.
16
+ ///
17
+ /// # Examples
18
+ ///
19
+ /// The following is an example of getting the PID of the current thread with zero additional cost
20
+ /// when compared to the C version:
21
+ ///
22
+ /// ```
23
+ /// use kernel::task::Task;
24
+ ///
25
+ /// let pid = Task::current().pid();
26
+ /// ```
27
+ ///
28
+ /// Getting the PID of the current process, also zero additional cost:
29
+ ///
30
+ /// ```
31
+ /// use kernel::task::Task;
32
+ ///
33
+ /// let pid = Task::current().group_leader().pid();
34
+ /// ```
35
+ ///
36
+ /// Getting the current task and storing it in some struct. The reference count is automatically
37
+ /// incremented when creating `State` and decremented when it is dropped:
38
+ ///
39
+ /// ```
40
+ /// use kernel::{task::Task, ARef};
41
+ ///
42
+ /// struct State {
43
+ /// creator: ARef<Task>,
44
+ /// index: u32,
45
+ /// }
46
+ ///
47
+ /// impl State {
48
+ /// fn new() -> Self {
49
+ /// Self {
50
+ /// creator: Task::current().into(),
51
+ /// index: 0,
52
+ /// }
53
+ /// }
54
+ /// }
55
+ /// ```
16
56
#[ repr( transparent) ]
17
57
pub struct Task ( pub ( crate ) UnsafeCell < bindings:: task_struct > ) ;
18
58
@@ -25,6 +65,20 @@ unsafe impl Sync for Task {}
25
65
type Pid = bindings:: pid_t ;
26
66
27
67
impl Task {
68
+ /// Returns a task reference for the currently executing task/thread.
69
+ pub fn current < ' a > ( ) -> TaskRef < ' a > {
70
+ // SAFETY: Just an FFI call with no additional safety requirements.
71
+ let ptr = unsafe { bindings:: get_current ( ) } ;
72
+
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
+ }
81
+
28
82
/// Returns the group leader of the given task.
29
83
pub fn group_leader ( & self ) -> & Task {
30
84
// SAFETY: By the type invariant, we know that `self.0` is valid.
@@ -69,3 +123,30 @@ unsafe impl crate::types::AlwaysRefCounted for Task {
69
123
unsafe { bindings:: put_task_struct ( obj. cast ( ) . as_ptr ( ) ) }
70
124
}
71
125
}
126
+
127
+ /// A wrapper for a shared reference to [`Task`] that isn't [`Send`].
128
+ ///
129
+ /// We make this explicitly not [`Send`] so that we can use it to represent the current thread
130
+ /// without having to increment/decrement the task's reference count.
131
+ ///
132
+ /// # Invariants
133
+ ///
134
+ /// The wrapped [`Task`] remains valid for the lifetime of the object.
135
+ pub struct TaskRef < ' a > {
136
+ task : & ' a Task ,
137
+ _not_send : PhantomData < * mut ( ) > ,
138
+ }
139
+
140
+ impl Deref for TaskRef < ' _ > {
141
+ type Target = Task ;
142
+
143
+ fn deref ( & self ) -> & Self :: Target {
144
+ self . task
145
+ }
146
+ }
147
+
148
+ impl From < TaskRef < ' _ > > for crate :: types:: ARef < Task > {
149
+ fn from ( t : TaskRef < ' _ > ) -> Self {
150
+ t. deref ( ) . into ( )
151
+ }
152
+ }
0 commit comments