rust: pin-init: change examples to the user-space version

Replace the examples in the documentation by the ones from the
user-space version and introduce the standalone examples from the
user-space version such as the `CMutex<T>` type.

The `CMutex<T>` example from the pinned-init repository [1] is used in
several documentation examples in the user-space version instead of the
kernel `Mutex<T>` type (as it's not available). In order to split off
the pin-init crate, all examples need to be free of kernel-specific
types.

Link: https://github.com/rust-for-Linux/pinned-init [1]
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Link: https://lore.kernel.org/r/20250308110339.2997091-6-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
Benno Lossin 2025-03-08 11:04:18 +00:00 committed by Miguel Ojeda
parent 4b11798e82
commit 84837cf6fa
7 changed files with 915 additions and 186 deletions

View file

@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
use pin_init::*;
// Struct with size over 1GiB
#[derive(Debug)]
pub struct BigStruct {
buf: [u8; 1024 * 1024 * 1024],
a: u64,
b: u64,
c: u64,
d: u64,
managed_buf: ManagedBuf,
}
#[derive(Debug)]
pub struct ManagedBuf {
buf: [u8; 1024 * 1024],
}
impl ManagedBuf {
pub fn new() -> impl Init<Self> {
init!(ManagedBuf { buf <- zeroed() })
}
}
fn main() {
// we want to initialize the struct in-place, otherwise we would get a stackoverflow
let buf: Box<BigStruct> = Box::init(init!(BigStruct {
buf <- zeroed(),
a: 7,
b: 186,
c: 7789,
d: 34,
managed_buf <- ManagedBuf::new(),
}))
.unwrap();
println!("{}", core::mem::size_of_val(&*buf));
}

View file

@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![cfg_attr(feature = "alloc", feature(allocator_api))]
use core::convert::Infallible;
#[cfg(feature = "alloc")]
use std::alloc::AllocError;
#[derive(Debug)]
pub struct Error;
impl From<Infallible> for Error {
fn from(e: Infallible) -> Self {
match e {}
}
}
#[cfg(feature = "alloc")]
impl From<AllocError> for Error {
fn from(_: AllocError) -> Self {
Self
}
}
#[allow(dead_code)]
fn main() {}

View file

@ -0,0 +1,161 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
use core::{
cell::Cell,
convert::Infallible,
marker::PhantomPinned,
pin::Pin,
ptr::{self, NonNull},
};
use pin_init::*;
#[expect(unused_attributes)]
mod error;
use error::Error;
#[pin_data(PinnedDrop)]
#[repr(C)]
#[derive(Debug)]
pub struct ListHead {
next: Link,
prev: Link,
#[pin]
pin: PhantomPinned,
}
impl ListHead {
#[inline]
pub fn new() -> impl PinInit<Self, Infallible> {
try_pin_init!(&this in Self {
next: unsafe { Link::new_unchecked(this) },
prev: unsafe { Link::new_unchecked(this) },
pin: PhantomPinned,
}? Infallible)
}
#[inline]
pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
try_pin_init!(&this in Self {
prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}),
next: list.next.replace(unsafe { Link::new_unchecked(this)}),
pin: PhantomPinned,
}? Infallible)
}
#[inline]
pub fn insert_prev(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
try_pin_init!(&this in Self {
next: list.prev.next().replace(unsafe { Link::new_unchecked(this)}),
prev: list.prev.replace(unsafe { Link::new_unchecked(this)}),
pin: PhantomPinned,
}? Infallible)
}
#[inline]
pub fn next(&self) -> Option<NonNull<Self>> {
if ptr::eq(self.next.as_ptr(), self) {
None
} else {
Some(unsafe { NonNull::new_unchecked(self.next.as_ptr() as *mut Self) })
}
}
#[allow(dead_code)]
pub fn size(&self) -> usize {
let mut size = 1;
let mut cur = self.next.clone();
while !ptr::eq(self, cur.cur()) {
cur = cur.next().clone();
size += 1;
}
size
}
}
#[pinned_drop]
impl PinnedDrop for ListHead {
//#[inline]
fn drop(self: Pin<&mut Self>) {
if !ptr::eq(self.next.as_ptr(), &*self) {
let next = unsafe { &*self.next.as_ptr() };
let prev = unsafe { &*self.prev.as_ptr() };
next.prev.set(&self.prev);
prev.next.set(&self.next);
}
}
}
#[repr(transparent)]
#[derive(Clone, Debug)]
struct Link(Cell<NonNull<ListHead>>);
impl Link {
/// # Safety
///
/// The contents of the pointer should form a consistent circular
/// linked list; for example, a "next" link should be pointed back
/// by the target `ListHead`'s "prev" link and a "prev" link should be
/// pointed back by the target `ListHead`'s "next" link.
#[inline]
unsafe fn new_unchecked(ptr: NonNull<ListHead>) -> Self {
Self(Cell::new(ptr))
}
#[inline]
fn next(&self) -> &Link {
unsafe { &(*self.0.get().as_ptr()).next }
}
#[inline]
fn prev(&self) -> &Link {
unsafe { &(*self.0.get().as_ptr()).prev }
}
#[allow(dead_code)]
fn cur(&self) -> &ListHead {
unsafe { &*self.0.get().as_ptr() }
}
#[inline]
fn replace(&self, other: Link) -> Link {
unsafe { Link::new_unchecked(self.0.replace(other.0.get())) }
}
#[inline]
fn as_ptr(&self) -> *const ListHead {
self.0.get().as_ptr()
}
#[inline]
fn set(&self, val: &Link) {
self.0.set(val.0.get());
}
}
#[allow(dead_code)]
#[cfg_attr(test, test)]
fn main() -> Result<(), Error> {
let a = Box::pin_init(ListHead::new())?;
stack_pin_init!(let b = ListHead::insert_next(&a));
stack_pin_init!(let c = ListHead::insert_next(&a));
stack_pin_init!(let d = ListHead::insert_next(&b));
let e = Box::pin_init(ListHead::insert_next(&b))?;
println!("a ({a:p}): {a:?}");
println!("b ({b:p}): {b:?}");
println!("c ({c:p}): {c:?}");
println!("d ({d:p}): {d:?}");
println!("e ({e:p}): {e:?}");
let mut inspect = &*a;
while let Some(next) = inspect.next() {
println!("({inspect:p}): {inspect:?}");
inspect = unsafe { &*next.as_ptr() };
if core::ptr::eq(inspect, &*a) {
break;
}
}
Ok(())
}

View file

@ -0,0 +1,209 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#![allow(clippy::missing_safety_doc)]
use core::{
cell::{Cell, UnsafeCell},
marker::PhantomPinned,
ops::{Deref, DerefMut},
pin::Pin,
sync::atomic::{AtomicBool, Ordering},
};
use std::{
sync::Arc,
thread::{self, park, sleep, Builder, Thread},
time::Duration,
};
use pin_init::*;
#[expect(unused_attributes)]
#[path = "./linked_list.rs"]
pub mod linked_list;
use linked_list::*;
pub struct SpinLock {
inner: AtomicBool,
}
impl SpinLock {
#[inline]
pub fn acquire(&self) -> SpinLockGuard<'_> {
while self
.inner
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
while self.inner.load(Ordering::Relaxed) {
thread::yield_now();
}
}
SpinLockGuard(self)
}
#[inline]
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self {
inner: AtomicBool::new(false),
}
}
}
pub struct SpinLockGuard<'a>(&'a SpinLock);
impl Drop for SpinLockGuard<'_> {
#[inline]
fn drop(&mut self) {
self.0.inner.store(false, Ordering::Release);
}
}
#[pin_data]
pub struct CMutex<T> {
#[pin]
wait_list: ListHead,
spin_lock: SpinLock,
locked: Cell<bool>,
#[pin]
data: UnsafeCell<T>,
}
impl<T> CMutex<T> {
#[inline]
pub fn new(val: impl PinInit<T>) -> impl PinInit<Self> {
pin_init!(CMutex {
wait_list <- ListHead::new(),
spin_lock: SpinLock::new(),
locked: Cell::new(false),
data <- unsafe {
pin_init_from_closure(|slot: *mut UnsafeCell<T>| {
val.__pinned_init(slot.cast::<T>())
})
},
})
}
#[inline]
pub fn lock(&self) -> Pin<CMutexGuard<'_, T>> {
let mut sguard = self.spin_lock.acquire();
if self.locked.get() {
stack_pin_init!(let wait_entry = WaitEntry::insert_new(&self.wait_list));
// println!("wait list length: {}", self.wait_list.size());
while self.locked.get() {
drop(sguard);
park();
sguard = self.spin_lock.acquire();
}
// This does have an effect, as the ListHead inside wait_entry implements Drop!
#[expect(clippy::drop_non_drop)]
drop(wait_entry);
}
self.locked.set(true);
unsafe {
Pin::new_unchecked(CMutexGuard {
mtx: self,
_pin: PhantomPinned,
})
}
}
#[allow(dead_code)]
pub fn get_data_mut(self: Pin<&mut Self>) -> &mut T {
// SAFETY: we have an exclusive reference and thus nobody has access to data.
unsafe { &mut *self.data.get() }
}
}
unsafe impl<T: Send> Send for CMutex<T> {}
unsafe impl<T: Send> Sync for CMutex<T> {}
pub struct CMutexGuard<'a, T> {
mtx: &'a CMutex<T>,
_pin: PhantomPinned,
}
impl<T> Drop for CMutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
let sguard = self.mtx.spin_lock.acquire();
self.mtx.locked.set(false);
if let Some(list_field) = self.mtx.wait_list.next() {
let wait_entry = list_field.as_ptr().cast::<WaitEntry>();
unsafe { (*wait_entry).thread.unpark() };
}
drop(sguard);
}
}
impl<T> Deref for CMutexGuard<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*self.mtx.data.get() }
}
}
impl<T> DerefMut for CMutexGuard<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.mtx.data.get() }
}
}
#[pin_data]
#[repr(C)]
struct WaitEntry {
#[pin]
wait_list: ListHead,
thread: Thread,
}
impl WaitEntry {
#[inline]
fn insert_new(list: &ListHead) -> impl PinInit<Self> + '_ {
pin_init!(Self {
thread: thread::current(),
wait_list <- ListHead::insert_prev(list),
})
}
}
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn main() {}
#[allow(dead_code)]
#[cfg_attr(test, test)]
#[cfg(any(feature = "std", feature = "alloc"))]
fn main() {
let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
let mut handles = vec![];
let thread_count = 20;
let workload = if cfg!(miri) { 100 } else { 1_000 };
for i in 0..thread_count {
let mtx = mtx.clone();
handles.push(
Builder::new()
.name(format!("worker #{i}"))
.spawn(move || {
for _ in 0..workload {
*mtx.lock() += 1;
}
println!("{i} halfway");
sleep(Duration::from_millis((i as u64) * 10));
for _ in 0..workload {
*mtx.lock() += 1;
}
println!("{i} finished");
})
.expect("should not fail"),
);
}
for h in handles {
h.join().expect("thread panicked");
}
println!("{:?}", &*mtx.lock());
assert_eq!(*mtx.lock(), workload * thread_count * 2);
}

View file

@ -0,0 +1,178 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
// inspired by https://github.com/nbdd0121/pin-init/blob/trunk/examples/pthread_mutex.rs
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#[cfg(not(windows))]
mod pthread_mtx {
#[cfg(feature = "alloc")]
use core::alloc::AllocError;
use core::{
cell::UnsafeCell,
marker::PhantomPinned,
mem::MaybeUninit,
ops::{Deref, DerefMut},
pin::Pin,
};
use pin_init::*;
use std::convert::Infallible;
#[pin_data(PinnedDrop)]
pub struct PThreadMutex<T> {
#[pin]
raw: UnsafeCell<libc::pthread_mutex_t>,
data: UnsafeCell<T>,
#[pin]
pin: PhantomPinned,
}
unsafe impl<T: Send> Send for PThreadMutex<T> {}
unsafe impl<T: Send> Sync for PThreadMutex<T> {}
#[pinned_drop]
impl<T> PinnedDrop for PThreadMutex<T> {
fn drop(self: Pin<&mut Self>) {
unsafe {
libc::pthread_mutex_destroy(self.raw.get());
}
}
}
#[derive(Debug)]
pub enum Error {
#[expect(dead_code)]
IO(std::io::Error),
Alloc,
}
impl From<Infallible> for Error {
fn from(e: Infallible) -> Self {
match e {}
}
}
#[cfg(feature = "alloc")]
impl From<AllocError> for Error {
fn from(_: AllocError) -> Self {
Self::Alloc
}
}
impl<T> PThreadMutex<T> {
pub fn new(data: T) -> impl PinInit<Self, Error> {
fn init_raw() -> impl PinInit<UnsafeCell<libc::pthread_mutex_t>, Error> {
let init = |slot: *mut UnsafeCell<libc::pthread_mutex_t>| {
// we can cast, because `UnsafeCell` has the same layout as T.
let slot: *mut libc::pthread_mutex_t = slot.cast();
let mut attr = MaybeUninit::uninit();
let attr = attr.as_mut_ptr();
// SAFETY: ptr is valid
let ret = unsafe { libc::pthread_mutexattr_init(attr) };
if ret != 0 {
return Err(Error::IO(std::io::Error::from_raw_os_error(ret)));
}
// SAFETY: attr is initialized
let ret = unsafe {
libc::pthread_mutexattr_settype(attr, libc::PTHREAD_MUTEX_NORMAL)
};
if ret != 0 {
// SAFETY: attr is initialized
unsafe { libc::pthread_mutexattr_destroy(attr) };
return Err(Error::IO(std::io::Error::from_raw_os_error(ret)));
}
// SAFETY: slot is valid
unsafe { slot.write(libc::PTHREAD_MUTEX_INITIALIZER) };
// SAFETY: attr and slot are valid ptrs and attr is initialized
let ret = unsafe { libc::pthread_mutex_init(slot, attr) };
// SAFETY: attr was initialized
unsafe { libc::pthread_mutexattr_destroy(attr) };
if ret != 0 {
return Err(Error::IO(std::io::Error::from_raw_os_error(ret)));
}
Ok(())
};
// SAFETY: mutex has been initialized
unsafe { pin_init_from_closure(init) }
}
try_pin_init!(Self {
data: UnsafeCell::new(data),
raw <- init_raw(),
pin: PhantomPinned,
}? Error)
}
pub fn lock(&self) -> PThreadMutexGuard<'_, T> {
// SAFETY: raw is always initialized
unsafe { libc::pthread_mutex_lock(self.raw.get()) };
PThreadMutexGuard { mtx: self }
}
}
pub struct PThreadMutexGuard<'a, T> {
mtx: &'a PThreadMutex<T>,
}
impl<T> Drop for PThreadMutexGuard<'_, T> {
fn drop(&mut self) {
// SAFETY: raw is always initialized
unsafe { libc::pthread_mutex_unlock(self.mtx.raw.get()) };
}
}
impl<T> Deref for PThreadMutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.mtx.data.get() }
}
}
impl<T> DerefMut for PThreadMutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.mtx.data.get() }
}
}
}
#[cfg_attr(test, test)]
fn main() {
#[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))]
{
use core::pin::Pin;
use pin_init::*;
use pthread_mtx::*;
use std::{
sync::Arc,
thread::{sleep, Builder},
time::Duration,
};
let mtx: Pin<Arc<PThreadMutex<usize>>> = Arc::try_pin_init(PThreadMutex::new(0)).unwrap();
let mut handles = vec![];
let thread_count = 20;
let workload = 1_000_000;
for i in 0..thread_count {
let mtx = mtx.clone();
handles.push(
Builder::new()
.name(format!("worker #{i}"))
.spawn(move || {
for _ in 0..workload {
*mtx.lock() += 1;
}
println!("{i} halfway");
sleep(Duration::from_millis((i as u64) * 10));
for _ in 0..workload {
*mtx.lock() += 1;
}
println!("{i} finished");
})
.expect("should not fail"),
);
}
for h in handles {
h.join().expect("thread panicked");
}
println!("{:?}", &*mtx.lock());
assert_eq!(*mtx.lock(), workload * thread_count * 2);
}
}

View file

@ -0,0 +1,122 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
use core::{
cell::{Cell, UnsafeCell},
mem::MaybeUninit,
ops,
pin::Pin,
time::Duration,
};
use pin_init::*;
use std::{
sync::Arc,
thread::{sleep, Builder},
};
#[expect(unused_attributes)]
mod mutex;
use mutex::*;
pub struct StaticInit<T, I> {
cell: UnsafeCell<MaybeUninit<T>>,
init: Cell<Option<I>>,
lock: SpinLock,
present: Cell<bool>,
}
unsafe impl<T: Sync, I> Sync for StaticInit<T, I> {}
unsafe impl<T: Send, I> Send for StaticInit<T, I> {}
impl<T, I: PinInit<T>> StaticInit<T, I> {
pub const fn new(init: I) -> Self {
Self {
cell: UnsafeCell::new(MaybeUninit::uninit()),
init: Cell::new(Some(init)),
lock: SpinLock::new(),
present: Cell::new(false),
}
}
}
impl<T, I: PinInit<T>> ops::Deref for StaticInit<T, I> {
type Target = T;
fn deref(&self) -> &Self::Target {
if self.present.get() {
unsafe { (*self.cell.get()).assume_init_ref() }
} else {
println!("acquire spinlock on static init");
let _guard = self.lock.acquire();
println!("rechecking present...");
std::thread::sleep(std::time::Duration::from_millis(200));
if self.present.get() {
return unsafe { (*self.cell.get()).assume_init_ref() };
}
println!("doing init");
let ptr = self.cell.get().cast::<T>();
match self.init.take() {
Some(f) => unsafe { f.__pinned_init(ptr).unwrap() },
None => unsafe { core::hint::unreachable_unchecked() },
}
self.present.set(true);
unsafe { (*self.cell.get()).assume_init_ref() }
}
}
}
pub struct CountInit;
unsafe impl PinInit<CMutex<usize>> for CountInit {
unsafe fn __pinned_init(
self,
slot: *mut CMutex<usize>,
) -> Result<(), core::convert::Infallible> {
let init = CMutex::new(0);
std::thread::sleep(std::time::Duration::from_millis(1000));
unsafe { init.__pinned_init(slot) }
}
}
pub static COUNT: StaticInit<CMutex<usize>, CountInit> = StaticInit::new(CountInit);
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn main() {}
#[cfg(any(feature = "std", feature = "alloc"))]
fn main() {
let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
let mut handles = vec![];
let thread_count = 20;
let workload = 1_000;
for i in 0..thread_count {
let mtx = mtx.clone();
handles.push(
Builder::new()
.name(format!("worker #{i}"))
.spawn(move || {
for _ in 0..workload {
*COUNT.lock() += 1;
std::thread::sleep(std::time::Duration::from_millis(10));
*mtx.lock() += 1;
std::thread::sleep(std::time::Duration::from_millis(10));
*COUNT.lock() += 1;
}
println!("{i} halfway");
sleep(Duration::from_millis((i as u64) * 10));
for _ in 0..workload {
std::thread::sleep(std::time::Duration::from_millis(10));
*mtx.lock() += 1;
}
println!("{i} finished");
})
.expect("should not fail"),
);
}
for h in handles {
h.join().expect("thread panicked");
}
println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock());
assert_eq!(*mtx.lock(), workload * thread_count * 2);
}

View file

@ -33,19 +33,23 @@
//! //!
//! ```rust,ignore //! ```rust,ignore
//! # #![expect(clippy::disallowed_names)] //! # #![expect(clippy::disallowed_names)]
//! use kernel::sync::{new_mutex, Mutex}; //! # #![feature(allocator_api)]
//! # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
//! # use core::pin::Pin; //! # use core::pin::Pin;
//! use pin_init::*;
//!
//! #[pin_data] //! #[pin_data]
//! struct Foo { //! struct Foo {
//! #[pin] //! #[pin]
//! a: Mutex<usize>, //! a: CMutex<usize>,
//! b: u32, //! b: u32,
//! } //! }
//! //!
//! let foo = pin_init!(Foo { //! let foo = pin_init!(Foo {
//! a <- new_mutex!(42, "Foo::a"), //! a <- CMutex::new(42),
//! b: 24, //! b: 24,
//! }); //! });
//! # let _ = Box::pin_init(foo);
//! ``` //! ```
//! //!
//! `foo` now is of the type [`impl PinInit<Foo>`]. We can now use any smart pointer that we like //! `foo` now is of the type [`impl PinInit<Foo>`]. We can now use any smart pointer that we like
@ -53,19 +57,23 @@
//! //!
//! ```rust,ignore //! ```rust,ignore
//! # #![expect(clippy::disallowed_names)] //! # #![expect(clippy::disallowed_names)]
//! # use kernel::sync::{new_mutex, Mutex}; //! # #![feature(allocator_api)]
//! # use core::pin::Pin; //! # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
//! # use core::{alloc::AllocError, pin::Pin};
//! # use pin_init::*;
//! #
//! # #[pin_data] //! # #[pin_data]
//! # struct Foo { //! # struct Foo {
//! # #[pin] //! # #[pin]
//! # a: Mutex<usize>, //! # a: CMutex<usize>,
//! # b: u32, //! # b: u32,
//! # } //! # }
//! #
//! # let foo = pin_init!(Foo { //! # let foo = pin_init!(Foo {
//! # a <- new_mutex!(42, "Foo::a"), //! # a <- CMutex::new(42),
//! # b: 24, //! # b: 24,
//! # }); //! # });
//! let foo: Result<Pin<KBox<Foo>>> = KBox::pin_init(foo, GFP_KERNEL); //! let foo: Result<Pin<Box<Foo>>, AllocError> = Box::pin_init(foo);
//! ``` //! ```
//! //!
//! For more information see the [`pin_init!`] macro. //! For more information see the [`pin_init!`] macro.
@ -76,28 +84,34 @@
//! above method only works for types where you can access the fields. //! above method only works for types where you can access the fields.
//! //!
//! ```rust,ignore //! ```rust,ignore
//! # use kernel::sync::{new_mutex, Arc, Mutex}; //! # #![feature(allocator_api)]
//! let mtx: Result<Arc<Mutex<usize>>> = //! # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
//! Arc::pin_init(new_mutex!(42, "example::mtx"), GFP_KERNEL); //! # use pin_init::*;
//! # use std::sync::Arc;
//! # use core::pin::Pin;
//! let mtx: Result<Pin<Arc<CMutex<usize>>>, _> = Arc::pin_init(CMutex::new(42));
//! ``` //! ```
//! //!
//! To declare an init macro/function you just return an [`impl PinInit<T, E>`]: //! To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
//! //!
//! ```rust,ignore //! ```rust,ignore
//! # use kernel::{sync::Mutex, new_mutex, init::PinInit, try_pin_init}; //! # #![feature(allocator_api)]
//! # use pin_init::*;
//! # #[path = "../examples/error.rs"] mod error; use error::Error;
//! # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
//! #[pin_data] //! #[pin_data]
//! struct DriverData { //! struct DriverData {
//! #[pin] //! #[pin]
//! status: Mutex<i32>, //! status: CMutex<i32>,
//! buffer: KBox<[u8; 1_000_000]>, //! buffer: Box<[u8; 1_000_000]>,
//! } //! }
//! //!
//! impl DriverData { //! impl DriverData {
//! fn new() -> impl PinInit<Self, Error> { //! fn new() -> impl PinInit<Self, Error> {
//! try_pin_init!(Self { //! try_pin_init!(Self {
//! status <- new_mutex!(0, "DriverData::status"), //! status <- CMutex::new(0),
//! buffer: KBox::init(kernel::init::zeroed(), GFP_KERNEL)?, //! buffer: Box::init(pin_init::zeroed())?,
//! }) //! }? Error)
//! } //! }
//! } //! }
//! ``` //! ```
@ -117,60 +131,61 @@
//! `slot` gets called. //! `slot` gets called.
//! //!
//! ```rust,ignore //! ```rust,ignore
//! # #![expect(unreachable_pub, clippy::disallowed_names)] //! # #![feature(extern_types)]
//! use kernel::{init, types::Opaque}; //! use pin_init::*;
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; //! use core::{
//! # mod bindings { //! ptr::addr_of_mut,
//! # #![expect(non_camel_case_types)] //! marker::PhantomPinned,
//! # #![expect(clippy::missing_safety_doc)] //! cell::UnsafeCell,
//! # pub struct foo; //! pin::Pin,
//! # pub unsafe fn init_foo(_ptr: *mut foo) {} //! mem::MaybeUninit,
//! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} //! };
//! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 } //! mod bindings {
//! # } //! extern "C" {
//! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround. //! pub type foo;
//! # trait FromErrno { //! pub fn init_foo(ptr: *mut foo);
//! # fn from_errno(errno: kernel::ffi::c_int) -> Error { //! pub fn destroy_foo(ptr: *mut foo);
//! # // Dummy error that can be constructed outside the `kernel` crate. //! #[must_use = "you must check the error return code"]
//! # Error::from(core::fmt::Error) //! pub fn enable_foo(ptr: *mut foo, flags: u32) -> i32;
//! # } //! }
//! # } //! }
//! # impl FromErrno for Error {} //!
//! /// # Invariants //! /// # Invariants
//! /// //! ///
//! /// `foo` is always initialized //! /// `foo` is always initialized
//! #[pin_data(PinnedDrop)] //! #[pin_data(PinnedDrop)]
//! pub struct RawFoo { //! pub struct RawFoo {
//! #[pin] //! #[pin]
//! foo: Opaque<bindings::foo>,
//! #[pin]
//! _p: PhantomPinned, //! _p: PhantomPinned,
//! #[pin]
//! foo: UnsafeCell<MaybeUninit<bindings::foo>>,
//! } //! }
//! //!
//! impl RawFoo { //! impl RawFoo {
//! pub fn new(flags: u32) -> impl PinInit<Self, Error> { //! pub fn new(flags: u32) -> impl PinInit<Self, i32> {
//! // SAFETY: //! // SAFETY:
//! // - when the closure returns `Ok(())`, then it has successfully initialized and //! // - when the closure returns `Ok(())`, then it has successfully initialized and
//! // enabled `foo`, //! // enabled `foo`,
//! // - when it returns `Err(e)`, then it has cleaned up before //! // - when it returns `Err(e)`, then it has cleaned up before
//! unsafe { //! unsafe {
//! init::pin_init_from_closure(move |slot: *mut Self| { //! pin_init_from_closure(move |slot: *mut Self| {
//! // `slot` contains uninit memory, avoid creating a reference. //! // `slot` contains uninit memory, avoid creating a reference.
//! let foo = addr_of_mut!((*slot).foo); //! let foo = addr_of_mut!((*slot).foo);
//! let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
//! //!
//! // Initialize the `foo` //! // Initialize the `foo`
//! bindings::init_foo(Opaque::raw_get(foo)); //! bindings::init_foo(foo);
//! //!
//! // Try to enable it. //! // Try to enable it.
//! let err = bindings::enable_foo(Opaque::raw_get(foo), flags); //! let err = bindings::enable_foo(foo, flags);
//! if err != 0 { //! if err != 0 {
//! // Enabling has failed, first clean up the foo and then return the error. //! // Enabling has failed, first clean up the foo and then return the error.
//! bindings::destroy_foo(Opaque::raw_get(foo)); //! bindings::destroy_foo(foo);
//! return Err(Error::from_errno(err)); //! Err(err)
//! } else {
//! // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
//! Ok(())
//! } //! }
//!
//! // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
//! Ok(())
//! }) //! })
//! } //! }
//! } //! }
@ -180,7 +195,7 @@
//! impl PinnedDrop for RawFoo { //! impl PinnedDrop for RawFoo {
//! fn drop(self: Pin<&mut Self>) { //! fn drop(self: Pin<&mut Self>) {
//! // SAFETY: Since `foo` is initialized, destroying is safe. //! // SAFETY: Since `foo` is initialized, destroying is safe.
//! unsafe { bindings::destroy_foo(self.foo.get()) }; //! unsafe { bindings::destroy_foo(self.foo.get().cast::<bindings::foo>()) };
//! } //! }
//! } //! }
//! ``` //! ```
@ -235,35 +250,39 @@ pub mod macros;
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// # #![feature(lint_reasons)] /// # #![feature(allocator_api)]
/// # use kernel::prelude::*; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # use std::{sync::Mutex, process::Command}; /// use pin_init::pin_data;
/// # use kernel::macros::pin_data; ///
/// enum Command {
/// /* ... */
/// }
///
/// #[pin_data] /// #[pin_data]
/// struct DriverData { /// struct DriverData {
/// #[pin] /// #[pin]
/// queue: Mutex<KVec<Command>>, /// queue: CMutex<Vec<Command>>,
/// buf: KBox<[u8; 1024 * 1024]>, /// buf: Box<[u8; 1024 * 1024]>,
/// } /// }
/// ``` /// ```
/// ///
/// ```ignore /// ```ignore
/// # #![feature(lint_reasons)] /// # #![feature(allocator_api)]
/// # use kernel::prelude::*; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # use std::{sync::Mutex, process::Command}; /// # mod bindings { pub struct info; pub unsafe fn destroy_info(_: *mut info) {} }
/// # use core::pin::Pin; /// use core::pin::Pin;
/// # pub struct Info; /// use pin_init::{pin_data, pinned_drop, PinnedDrop};
/// # mod bindings { ///
/// # pub unsafe fn destroy_info(_ptr: *mut super::Info) {} /// enum Command {
/// # } /// /* ... */
/// use kernel::macros::{pin_data, pinned_drop}; /// }
/// ///
/// #[pin_data(PinnedDrop)] /// #[pin_data(PinnedDrop)]
/// struct DriverData { /// struct DriverData {
/// #[pin] /// #[pin]
/// queue: Mutex<KVec<Command>>, /// queue: CMutex<Vec<Command>>,
/// buf: KBox<[u8; 1024 * 1024]>, /// buf: Box<[u8; 1024 * 1024]>,
/// raw_info: *mut Info, /// raw_info: *mut bindings::info,
/// } /// }
/// ///
/// #[pinned_drop] /// #[pinned_drop]
@ -272,7 +291,6 @@ pub mod macros;
/// unsafe { bindings::destroy_info(self.raw_info) }; /// unsafe { bindings::destroy_info(self.raw_info) };
/// } /// }
/// } /// }
/// # fn main() {}
/// ``` /// ```
/// ///
/// [`pin_init!`]: crate::pin_init /// [`pin_init!`]: crate::pin_init
@ -285,21 +303,22 @@ pub use ::macros::pin_data;
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// # #![feature(lint_reasons)] /// # #![feature(allocator_api)]
/// # use kernel::prelude::*; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # use macros::{pin_data, pinned_drop}; /// # mod bindings { pub struct info; pub unsafe fn destroy_info(_: *mut info) {} }
/// # use std::{sync::Mutex, process::Command}; /// use core::pin::Pin;
/// # use core::pin::Pin; /// use pin_init::{pin_data, pinned_drop, PinnedDrop};
/// # mod bindings { ///
/// # pub struct Info; /// enum Command {
/// # pub unsafe fn destroy_info(_ptr: *mut Info) {} /// /* ... */
/// # } /// }
///
/// #[pin_data(PinnedDrop)] /// #[pin_data(PinnedDrop)]
/// struct DriverData { /// struct DriverData {
/// #[pin] /// #[pin]
/// queue: Mutex<KVec<Command>>, /// queue: CMutex<Vec<Command>>,
/// buf: KBox<[u8; 1024 * 1024]>, /// buf: Box<[u8; 1024 * 1024]>,
/// raw_info: *mut bindings::Info, /// raw_info: *mut bindings::info,
/// } /// }
/// ///
/// #[pinned_drop] /// #[pinned_drop]
@ -318,7 +337,7 @@ pub use ::macros::pinned_drop;
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// use kernel::macros::Zeroable; /// use pin_init::Zeroable;
/// ///
/// #[derive(Zeroable)] /// #[derive(Zeroable)]
/// pub struct DriverData { /// pub struct DriverData {
@ -335,12 +354,14 @@ pub use ::macros::Zeroable;
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)] /// # #![expect(clippy::disallowed_names)]
/// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex}; /// # #![feature(allocator_api)]
/// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # use pin_init::*;
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// #[pin_data] /// #[pin_data]
/// struct Foo { /// struct Foo {
/// #[pin] /// #[pin]
/// a: Mutex<usize>, /// a: CMutex<usize>,
/// b: Bar, /// b: Bar,
/// } /// }
/// ///
@ -350,13 +371,13 @@ pub use ::macros::Zeroable;
/// } /// }
/// ///
/// stack_pin_init!(let foo = pin_init!(Foo { /// stack_pin_init!(let foo = pin_init!(Foo {
/// a <- new_mutex!(42), /// a <- CMutex::new(42),
/// b: Bar { /// b: Bar {
/// x: 64, /// x: 64,
/// }, /// },
/// })); /// }));
/// let foo: Pin<&mut Foo> = foo; /// let foo: Pin<&mut Foo> = foo;
/// pr_info!("a: {}", &*foo.a.lock()); /// println!("a: {}", &*foo.a.lock());
/// ``` /// ```
/// ///
/// # Syntax /// # Syntax
@ -387,70 +408,56 @@ macro_rules! stack_pin_init {
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)] /// # #![expect(clippy::disallowed_names)]
/// # use kernel::{ /// # #![feature(allocator_api)]
/// # init, /// # #[path = "../examples/error.rs"] mod error; use error::Error;
/// # pin_init, /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # stack_try_pin_init, /// # use pin_init::*;
/// # init::*,
/// # sync::Mutex,
/// # new_mutex,
/// # alloc::AllocError,
/// # };
/// # use macros::pin_data;
/// # use core::pin::Pin;
/// #[pin_data] /// #[pin_data]
/// struct Foo { /// struct Foo {
/// #[pin] /// #[pin]
/// a: Mutex<usize>, /// a: CMutex<usize>,
/// b: KBox<Bar>, /// b: Box<Bar>,
/// } /// }
/// ///
/// struct Bar { /// struct Bar {
/// x: u32, /// x: u32,
/// } /// }
/// ///
/// stack_try_pin_init!(let foo: Result<Pin<&mut Foo>, AllocError> = pin_init!(Foo { /// stack_try_pin_init!(let foo: Foo = try_pin_init!(Foo {
/// a <- new_mutex!(42), /// a <- CMutex::new(42),
/// b: KBox::new(Bar { /// b: Box::try_new(Bar {
/// x: 64, /// x: 64,
/// }, GFP_KERNEL)?, /// })?,
/// })); /// }? Error));
/// let foo = foo.unwrap(); /// let foo = foo.unwrap();
/// pr_info!("a: {}", &*foo.a.lock()); /// println!("a: {}", &*foo.a.lock());
/// ``` /// ```
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)] /// # #![expect(clippy::disallowed_names)]
/// # use kernel::{ /// # #![feature(allocator_api)]
/// # init, /// # #[path = "../examples/error.rs"] mod error; use error::Error;
/// # pin_init, /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # stack_try_pin_init, /// # use pin_init::*;
/// # init::*,
/// # sync::Mutex,
/// # new_mutex,
/// # alloc::AllocError,
/// # };
/// # use macros::pin_data;
/// # use core::pin::Pin;
/// #[pin_data] /// #[pin_data]
/// struct Foo { /// struct Foo {
/// #[pin] /// #[pin]
/// a: Mutex<usize>, /// a: CMutex<usize>,
/// b: KBox<Bar>, /// b: Box<Bar>,
/// } /// }
/// ///
/// struct Bar { /// struct Bar {
/// x: u32, /// x: u32,
/// } /// }
/// ///
/// stack_try_pin_init!(let foo: Pin<&mut Foo> =? pin_init!(Foo { /// stack_try_pin_init!(let foo: Foo =? try_pin_init!(Foo {
/// a <- new_mutex!(42), /// a <- CMutex::new(42),
/// b: KBox::new(Bar { /// b: Box::try_new(Bar {
/// x: 64, /// x: 64,
/// }, GFP_KERNEL)?, /// })?,
/// })); /// }? Error));
/// pr_info!("a: {}", &*foo.a.lock()); /// println!("a: {}", &*foo.a.lock());
/// # Ok::<_, AllocError>(()) /// # Ok::<_, Error>(())
/// ``` /// ```
/// ///
/// # Syntax /// # Syntax
@ -480,7 +487,7 @@ macro_rules! stack_try_pin_init {
/// The syntax is almost identical to that of a normal `struct` initializer: /// The syntax is almost identical to that of a normal `struct` initializer:
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use pin_init::*;
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// #[pin_data] /// #[pin_data]
/// struct Foo { /// struct Foo {
@ -503,7 +510,7 @@ macro_rules! stack_try_pin_init {
/// }, /// },
/// }); /// });
/// # initializer } /// # initializer }
/// # KBox::pin_init(demo(), GFP_KERNEL).unwrap(); /// # Box::pin_init(demo()).unwrap();
/// ``` /// ```
/// ///
/// Arbitrary Rust expressions can be used to set the value of a variable. /// Arbitrary Rust expressions can be used to set the value of a variable.
@ -524,7 +531,7 @@ macro_rules! stack_try_pin_init {
/// To create an initializer function, simply declare it like this: /// To create an initializer function, simply declare it like this:
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # use kernel::{init, pin_init, init::*}; /// # use pin_init::*;
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// # #[pin_data] /// # #[pin_data]
/// # struct Foo { /// # struct Foo {
@ -551,7 +558,7 @@ macro_rules! stack_try_pin_init {
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)] /// # #![expect(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use pin_init::*;
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// # #[pin_data] /// # #[pin_data]
/// # struct Foo { /// # struct Foo {
@ -572,13 +579,13 @@ macro_rules! stack_try_pin_init {
/// # }) /// # })
/// # } /// # }
/// # } /// # }
/// let foo = KBox::pin_init(Foo::new(), GFP_KERNEL); /// let foo = Box::pin_init(Foo::new());
/// ``` /// ```
/// ///
/// They can also easily embed it into their own `struct`s: /// They can also easily embed it into their own `struct`s:
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use pin_init::*;
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// # #[pin_data] /// # #[pin_data]
/// # struct Foo { /// # struct Foo {
@ -637,7 +644,7 @@ macro_rules! stack_try_pin_init {
/// For instance: /// For instance:
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # use kernel::{macros::{Zeroable, pin_data}, pin_init}; /// # use pin_init::*;
/// # use core::{ptr::addr_of_mut, marker::PhantomPinned}; /// # use core::{ptr::addr_of_mut, marker::PhantomPinned};
/// #[pin_data] /// #[pin_data]
/// #[derive(Zeroable)] /// #[derive(Zeroable)]
@ -700,10 +707,12 @@ macro_rules! pin_init {
/// # Examples /// # Examples
/// ///
/// ```rust,ignore /// ```rust,ignore
/// use kernel::{init::{self, PinInit}, error::Error}; /// # #![feature(allocator_api)]
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
/// use pin_init::*;
/// #[pin_data] /// #[pin_data]
/// struct BigBuf { /// struct BigBuf {
/// big: KBox<[u8; 1024 * 1024 * 1024]>, /// big: Box<[u8; 1024 * 1024 * 1024]>,
/// small: [u8; 1024 * 1024], /// small: [u8; 1024 * 1024],
/// ptr: *mut u8, /// ptr: *mut u8,
/// } /// }
@ -711,12 +720,13 @@ macro_rules! pin_init {
/// impl BigBuf { /// impl BigBuf {
/// fn new() -> impl PinInit<Self, Error> { /// fn new() -> impl PinInit<Self, Error> {
/// try_pin_init!(Self { /// try_pin_init!(Self {
/// big: KBox::init(init::zeroed(), GFP_KERNEL)?, /// big: Box::init(init::zeroed())?,
/// small: [0; 1024 * 1024], /// small: [0; 1024 * 1024],
/// ptr: core::ptr::null_mut(), /// ptr: core::ptr::null_mut(),
/// }? Error) /// }? Error)
/// } /// }
/// } /// }
/// # let _ = Box::pin_init(BigBuf::new());
/// ``` /// ```
// For a detailed example of how this macro works, see the module documentation of the hidden // For a detailed example of how this macro works, see the module documentation of the hidden
// module `__internal` inside of `init/__internal.rs`. // module `__internal` inside of `init/__internal.rs`.
@ -803,18 +813,20 @@ macro_rules! init {
/// # Examples /// # Examples
/// ///
/// ```rust,ignore /// ```rust,ignore
/// use kernel::{alloc::KBox, init::{PinInit, zeroed}, error::Error}; /// # #![feature(allocator_api)]
/// # use core::alloc::AllocError;
/// use pin_init::*;
/// struct BigBuf { /// struct BigBuf {
/// big: KBox<[u8; 1024 * 1024 * 1024]>, /// big: Box<[u8; 1024 * 1024 * 1024]>,
/// small: [u8; 1024 * 1024], /// small: [u8; 1024 * 1024],
/// } /// }
/// ///
/// impl BigBuf { /// impl BigBuf {
/// fn new() -> impl Init<Self, Error> { /// fn new() -> impl Init<Self, AllocError> {
/// try_init!(Self { /// try_init!(Self {
/// big: KBox::init(zeroed(), GFP_KERNEL)?, /// big: Box::init(zeroed())?,
/// small: [0; 1024 * 1024], /// small: [0; 1024 * 1024],
/// }? Error) /// }? AllocError)
/// } /// }
/// } /// }
/// ``` /// ```
@ -859,7 +871,7 @@ macro_rules! try_init {
/// ///
/// This will succeed: /// This will succeed:
/// ```ignore /// ```ignore
/// use kernel::assert_pinned; /// use pin_init::assert_pinned;
/// #[pin_data] /// #[pin_data]
/// struct MyStruct { /// struct MyStruct {
/// #[pin] /// #[pin]
@ -870,9 +882,8 @@ macro_rules! try_init {
/// ``` /// ```
/// ///
/// This will fail: /// This will fail:
// TODO: replace with `compile_fail` when supported. /// ```compile_fail,ignore
/// ```ignore /// use pin_init::assert_pinned;
/// use kernel::assert_pinned;
/// #[pin_data] /// #[pin_data]
/// struct MyStruct { /// struct MyStruct {
/// some_field: u64, /// some_field: u64,
@ -885,7 +896,7 @@ macro_rules! try_init {
/// work around this, you may pass the `inline` parameter to the macro. The `inline` parameter can /// work around this, you may pass the `inline` parameter to the macro. The `inline` parameter can
/// only be used when the macro is invoked from a function body. /// only be used when the macro is invoked from a function body.
/// ```ignore /// ```ignore
/// use kernel::assert_pinned; /// use pin_init::assert_pinned;
/// #[pin_data] /// #[pin_data]
/// struct Foo<T> { /// struct Foo<T> {
/// #[pin] /// #[pin]
@ -963,35 +974,13 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
/// # Examples /// # Examples
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)] /// # #![feature(allocator_api)]
/// use kernel::{types::Opaque, init::pin_init_from_closure}; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// #[repr(C)] /// # use pin_init::*;
/// struct RawFoo([u8; 16]); /// let mtx_init = CMutex::new(42);
/// extern "C" { /// // Make the initializer print the value.
/// fn init_foo(_: *mut RawFoo); /// let mtx_init = mtx_init.pin_chain(|mtx| {
/// } /// println!("{:?}", mtx.get_data_mut());
///
/// #[pin_data]
/// struct Foo {
/// #[pin]
/// raw: Opaque<RawFoo>,
/// }
///
/// impl Foo {
/// fn setup(self: Pin<&mut Self>) {
/// pr_info!("Setting up foo");
/// }
/// }
///
/// let foo = pin_init!(Foo {
/// // SAFETY: TODO.
/// raw <- unsafe {
/// Opaque::ffi_init(|s| {
/// init_foo(s);
/// })
/// },
/// }).pin_chain(|foo| {
/// foo.setup();
/// Ok(()) /// Ok(())
/// }); /// });
/// ``` /// ```
@ -1076,7 +1065,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)] /// # #![expect(clippy::disallowed_names)]
/// use kernel::{types::Opaque, init::{self, init_from_closure}}; /// use pin_init::{init_from_closure, zeroed};
/// struct Foo { /// struct Foo {
/// buf: [u8; 1_000_000], /// buf: [u8; 1_000_000],
/// } /// }
@ -1088,7 +1077,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
/// } /// }
/// ///
/// let foo = init!(Foo { /// let foo = init!(Foo {
/// buf <- init::zeroed() /// buf <- zeroed()
/// }).chain(|foo| { /// }).chain(|foo| {
/// foo.setup(); /// foo.setup();
/// Ok(()) /// Ok(())
@ -1187,11 +1176,10 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
/// # Examples /// # Examples
/// ///
/// ```rust,ignore /// ```rust,ignore
/// use kernel::{alloc::KBox, error::Error, init::init_array_from_fn}; /// # use pin_init::*;
/// let array: KBox<[usize; 1_000]> = /// use pin_init::init_array_from_fn;
/// KBox::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL)?; /// let array: Box<[usize; 1_000]> = Box::init(init_array_from_fn(|i| i)).unwrap();
/// assert_eq!(array.len(), 1_000); /// assert_eq!(array.len(), 1_000);
/// # Ok::<(), Error>(())
/// ``` /// ```
pub fn init_array_from_fn<I, const N: usize, T, E>( pub fn init_array_from_fn<I, const N: usize, T, E>(
mut make_init: impl FnMut(usize) -> I, mut make_init: impl FnMut(usize) -> I,
@ -1232,11 +1220,15 @@ where
/// # Examples /// # Examples
/// ///
/// ```rust,ignore /// ```rust,ignore
/// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex}; /// # #![feature(allocator_api)]
/// let array: Arc<[Mutex<usize>; 1_000]> = /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i)), GFP_KERNEL)?; /// # use pin_init::*;
/// # use core::pin::Pin;
/// use pin_init::pin_init_array_from_fn;
/// use std::sync::Arc;
/// let array: Pin<Arc<[CMutex<usize>; 1_000]>> =
/// Arc::pin_init(pin_init_array_from_fn(|i| CMutex::new(i))).unwrap();
/// assert_eq!(array.len(), 1_000); /// assert_eq!(array.len(), 1_000);
/// # Ok::<(), Error>(())
/// ``` /// ```
pub fn pin_init_array_from_fn<I, const N: usize, T, E>( pub fn pin_init_array_from_fn<I, const N: usize, T, E>(
mut make_init: impl FnMut(usize) -> I, mut make_init: impl FnMut(usize) -> I,
@ -1421,19 +1413,20 @@ impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> {
/// Use [`pinned_drop`] to implement this trait safely: /// Use [`pinned_drop`] to implement this trait safely:
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # use kernel::sync::Mutex; /// # #![feature(allocator_api)]
/// use kernel::macros::pinned_drop; /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # use pin_init::*;
/// use core::pin::Pin; /// use core::pin::Pin;
/// #[pin_data(PinnedDrop)] /// #[pin_data(PinnedDrop)]
/// struct Foo { /// struct Foo {
/// #[pin] /// #[pin]
/// mtx: Mutex<usize>, /// mtx: CMutex<usize>,
/// } /// }
/// ///
/// #[pinned_drop] /// #[pinned_drop]
/// impl PinnedDrop for Foo { /// impl PinnedDrop for Foo {
/// fn drop(self: Pin<&mut Self>) { /// fn drop(self: Pin<&mut Self>) {
/// pr_info!("Foo is being dropped!"); /// println!("Foo is being dropped!");
/// } /// }
/// } /// }
/// ``` /// ```