@@ -18,10 +18,6 @@ extern "C" {
18
18
fn rust_helper_put_task_struct ( task : * mut bindings:: task_struct ) ;
19
19
}
20
20
21
- fn call_as_closure ( closure : Box < Box < dyn FnOnce ( ) -> KernelResult < ( ) > > > ) -> KernelResult < ( ) > {
22
- closure ( )
23
- }
24
-
25
21
/// Generates a bridge function from Rust to C ABI.
26
22
///
27
23
/// `func` should be a `fn(arg: arg_type) -> KernelResult<()>` where arg_type
@@ -117,7 +113,7 @@ macro_rules! thread_try_new {
117
113
}
118
114
119
115
// Uses an unused closure to check whether `$arg` is `Send`.
120
- let _ = move || { _arg } ;
116
+ let _ = move || _arg;
121
117
122
118
Err ( e)
123
119
} else {
@@ -126,26 +122,122 @@ macro_rules! thread_try_new {
126
122
} } ;
127
123
}
128
124
129
- /*
125
+ /// Helper trait for thread arguments handling.
126
+ ///
127
+ /// Basically, we just handle object "sending" manually, for a [`Send`] object,
128
+ /// [`ThreadArg::from_arg`] is used to convert it into a pointer that kernel's
129
+ /// thread creation function will accept (e.g. `kthread_create_on_node`). And
130
+ /// later in the thread function, [`ThreadArg::from_raw`] is used to convert it
131
+ /// back.
132
+ ///
133
+ /// # Safety
134
+ ///
135
+ /// Both [`ThreadArg::from_arg`] and [`ThreadArg::from_raw`] are marked as
136
+ /// `unsafe` because they are only allowed to use in pair.
130
137
pub trait ThreadArg < A : Send > {
131
- fn from_raw(ptr: *mut c_types::c_void) -> A;
132
- fn into_raw(arg: A) -> *mut c_types::c_void;
138
+ /// Converts a raw pointer to a thread argument.
139
+ ///
140
+ /// # Safety
141
+ ///
142
+ /// This function is marked as unsafe because a) the caller need to make
143
+ /// sure `ptr` is a valid pointer and b) it should be used in pair with
144
+ /// ['ThreadArg::from_arg`].
145
+ unsafe fn from_raw ( ptr : * mut c_types:: c_void ) -> A ;
146
+
147
+ /// Converts a thread argument to a raw poitner.
148
+ ///
149
+ /// # Safety
150
+ ///
151
+ /// This function is marked as unsafe because it should be used in pair with
152
+ /// ['ThreadArg::into_raw`], otherwise memory leak or other UBs may happen.
153
+ unsafe fn from_arg ( arg : A ) -> * mut c_types:: c_void ;
133
154
}
155
+
156
+ /// Helper trait for generate a C ABI bridge function.
157
+ ///
158
+ /// Pass an `impl` of this trait as the second type parameter to
159
+ /// [`Thread::try_new_thread_func`], the new thread call [`ThreadFunc::func`]
160
+ /// if the creation succeeds.
134
161
pub trait ThreadFunc < A : Send > {
162
+ type Arg : ThreadArg < A > ;
135
163
fn func ( arg : A ) -> KernelResult < ( ) > ;
136
164
}
137
165
138
- extern "C" fn bridge<A, T: ThreadFunc<A>>(data: *mut c_types::c_void) -> i32
139
- where A : Send
166
+ /// Predefined argument handling structs.
167
+ ///
168
+ /// FIXME: Maybe put them into a sub mod?
169
+
170
+
171
+ /// Helper struct for Box<A: Send> thread argument handling.
172
+ ///
173
+ /// A helper [`ThreadFunc`] whose `func` is: `fn(Box<A>) -> KernelResult<()>`,
174
+ /// can use it as the [`ThreadFunc::Arg`] type.
175
+ pub struct BoxArg ;
176
+
177
+ impl < T > ThreadArg < Box < T > > for BoxArg
178
+ where
179
+ T : Send ,
180
+ {
181
+ unsafe fn from_raw ( ptr : * mut c_types:: c_void ) -> Box < T > {
182
+ Box :: from_raw ( ptr as * mut T )
183
+ }
184
+ unsafe fn from_arg ( arg : Box < T > ) -> * mut c_types:: c_void {
185
+ Box :: into_raw ( arg) as * mut _
186
+ }
187
+ }
188
+
189
+ pub struct PrimitiveArg ;
190
+
191
+ macro_rules! primitive_arg_struct {
192
+ ( $t: ty) => {
193
+ impl ThreadArg <$t> for PrimitiveArg {
194
+ unsafe fn from_raw( ptr: * mut c_types:: c_void) -> $t {
195
+ ptr as usize as $t
196
+ }
197
+ unsafe fn from_arg( arg: $t) -> * mut c_types:: c_void {
198
+ arg as usize as * mut _
199
+ }
200
+ }
201
+ } ;
202
+ }
203
+ primitive_arg_struct ! { i8 }
204
+ primitive_arg_struct ! { i16 }
205
+ primitive_arg_struct ! { i32 }
206
+ primitive_arg_struct ! { i64 }
207
+ primitive_arg_struct ! { isize }
208
+ primitive_arg_struct ! { u8 }
209
+ primitive_arg_struct ! { u16 }
210
+ primitive_arg_struct ! { u32 }
211
+ primitive_arg_struct ! { u64 }
212
+ primitive_arg_struct ! { usize }
213
+
214
+ /// Bridge function from Rust ABI to C.
215
+ extern "C" fn bridge < A , F : ThreadFunc < A > > ( data : * mut c_types:: c_void ) -> i32
216
+ where
217
+ A : Send ,
140
218
{
141
- let arg = unsafe { core::intrinsics::transmute (data) };
142
-
143
- match T ::func(arg) {
219
+ let arg = unsafe { F :: Arg :: from_raw ( data) } ;
220
+
221
+ match F :: func ( arg) {
144
222
Ok ( _) => 0 ,
145
223
Err ( e) => e. to_kernel_errno ( ) ,
146
224
}
147
225
}
148
- */
226
+
227
+ /// Helper struct for thread that just call its argument as a closure.
228
+ ///
229
+ /// We use double boxing in the implementation, because 1) we need to make sure
230
+ /// the thread argument live longer enough for the new thread to use (box #1),
231
+ /// and `FnOnce()` is a fat pointer that doesn't fit in `*mut c_void` (box #2).
232
+ struct ClosureCallFunc ;
233
+
234
+ impl ThreadFunc < Box < Box < dyn FnOnce ( ) -> KernelResult < ( ) > + Send > > > for ClosureCallFunc {
235
+ type Arg = BoxArg ;
236
+ fn func ( arg : Box < Box < dyn FnOnce ( ) -> KernelResult < ( ) > + Send > > ) -> KernelResult < ( ) > {
237
+ // Just calls it.
238
+ arg ( )
239
+ }
240
+ }
149
241
150
242
/// Function passed to `kthread_create_on_node` as the thread function pointer.
151
243
#[ no_mangle]
@@ -221,32 +313,69 @@ impl Thread {
221
313
Ok ( Thread { task } )
222
314
}
223
315
224
- /*
225
- pub fn try_new_thread_func<A, T: ThreadFunc<A>>(name: CStr, arg: A) -> KernelResult<Self>
226
- where A: Send
316
+ /// Creates a new thread without extra dynamic memory allocaiton
317
+ ///
318
+ /// # Examples
319
+ ///
320
+ /// ```
321
+ /// use kernel::thread::{Thread, ThreadFunc, BoxArg};
322
+ /// use alloc::boxed::Box;
323
+ /// use core::fmt::Debug;
324
+ ///
325
+ /// struct SimpleBoxFunc;
326
+ ///
327
+ /// impl<T> ThreadFunc<Box<T>> for SimpleBoxFunc
328
+ /// where T: Send + Debug
329
+ /// {
330
+ /// type Arg = BoxArg;
331
+ /// fn func(b: Box<T>) -> KernelResult<()> {
332
+ /// println!("I got {:?}", b);
333
+ /// }
334
+ /// }
335
+ ///
336
+ /// let t = Thread::try_new_thread_func::<_, SimpleBoxFunc>(
337
+ /// cstr!("rust-thread"),
338
+ /// Box::try_new(42)?
339
+ /// )?;
340
+ ///
341
+ /// t.wake_up();
342
+ /// ```
343
+ ///
344
+ /// # Context
345
+ ///
346
+ /// This function might sleep due to the memory allocation and waiting for
347
+ /// the completion in `kthread_create_on_node`. Therefore do not call this
348
+ /// in atomic contexts (i.e. preemption-off contexts).
349
+ pub fn try_new_thread_func < A , F : ThreadFunc < A > > ( name : CStr , arg : A ) -> KernelResult < Self >
350
+ where
351
+ A : Send ,
227
352
{
228
- let data = unsafe { core::intrinsics::transmute(arg) };
353
+ // SAFETY: We don't dereference the pointer we get from `from_arg`, and
354
+ // we will consume the pointer with 'from_raw` either in the new thread
355
+ // or the error handling below.
356
+ let data = unsafe { F :: Arg :: from_arg ( arg) } ;
229
357
230
- let result = unsafe { Self::try_new_c_style(name, bridge::<A,T>, data) };
358
+ // SAFETY: `bridge::<A,F>` is a proper function pointer to a C
359
+ // function, and [`ThreadArg::from_raw`] will be used in it to consume
360
+ // the raw pointer in the new thread.
361
+ let result = unsafe { Self :: try_new_c_style ( name, bridge :: < A , F > , data) } ;
231
362
232
363
if let Err ( e) = result {
233
- // Creation fails, we need to `transmute` back the `arg ` because
234
- // there is no new thread to own it , we should let the current
235
- // thread own it.
364
+ // Creation fails, we need to consume the raw pointer `data ` because
365
+ // there is no new thread to own the underlying object , we should
366
+ // let the current thread own it.
236
367
//
237
- // SAFETY: We `transmute ` back waht we just `transmute `, and since
368
+ // SAFETY: We `from_raw ` back what we just `from_arg `, and since
238
369
// the new thread is not created, so no one touches `data`.
239
370
unsafe {
240
- core::intrinsics::transmute::<_, A> (data);
371
+ F :: Arg :: from_raw ( data) ;
241
372
}
242
373
243
374
Err ( e)
244
375
} else {
245
376
result
246
377
}
247
-
248
378
}
249
- */
250
379
251
380
/// Creates a new thread.
252
381
///
@@ -286,13 +415,13 @@ impl Thread {
286
415
{
287
416
// Allocate closure here, because this function maybe returns before
288
417
// `rust_thread_func` (the function that uses the closure) get executed.
289
- let boxed_fn: Box < dyn FnOnce ( ) -> KernelResult < ( ) > + ' static > = Box :: try_new ( f) ?;
418
+ let boxed_fn: Box < dyn FnOnce ( ) -> KernelResult < ( ) > + ' static + Send > = Box :: try_new ( f) ?;
290
419
291
420
// Double boxing here because `dyn FnOnce` is a fat pointer, and we cannot
292
421
// `transmute` it to `*mut c_void`.
293
422
let double_box = Box :: try_new ( boxed_fn) ?;
294
423
295
- thread_try_new ! ( name , call_as_closure , double_box)
424
+ Self :: try_new_thread_func :: < _ , ClosureCallFunc > ( name , double_box)
296
425
}
297
426
298
427
/// Wakes up the thread.
0 commit comments