Description
The kernel has a lot of data structures that cannot be freely moved, e.g. Mutex
and CondVar
. Currently what we do is to first unsafe
ly create instance of them, pin them, and then unsafe
ly initialize them after having them pinned (currently the code does not require unsafe
to initialize Mutex
, which I believe is a bug, as it could be initialized while locked, which is definitely unsound).
For example, this snippet (related #286) from miscdev needs 3 unsafes (5 if we count both inits):
linux/samples/rust/rust_miscdev.rs
Lines 35 to 59 in 1a73789
And this is a very common pattern. In the current state, essentially any use of CondVar
, Mutex
, Spinlock
or any pinned types require a lot of unsafe
to initialize. Of course we can have these types Box
-ed internally but that's many unnecessary allocations.
So I spent the past few days designing and implementing a safe way to pin-initialized struct, pin-init
(doc, repo). This design allows safe initialization and use of pthread mutex without any boxing: https://github.com/nbdd0121/pin-init/blob/trunk/examples/pthread_mutex.rs.
Kernel CondVar
& Mutex
could be implemented in a similar way. With pin-init
, the above snippet could be written like this:
#[pin_init]
struct SharedState {
#[pin]
state_changed: CondVar,
#[pin]
inner: Mutex<SharedStateInner>,
}
impl SharedState {
fn try_new() -> Result<Pin<Arc<Self>>> {
try_new_arc(init_pin!(Self {
state_changed: |s| kernel::condvar_new!(s, "SharedState::state_changed"),
inner: |s| kernel::mutex_new!(s, "SharedState::inner", SharedStateInner { token_count: 0 }),
}))
}
}
Approaches like this make code more readable and safer; but it requires procedural macro (and parsing capability of syn
) so it might not be easy to integrate at current stage.