Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: pin-init: add `std` and `alloc` support from the user-space version

To synchronize the kernel's version of pin-init with the user-space
version, introduce support for `std` and `alloc`. While the kernel uses
neither, the user-space version has to support both. Thus include the
required `#[cfg]`s and additional code.

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-17-benno.lossin@proton.me
[ Undo the temporary `--extern force:alloc` since now we have contents
for `alloc` here. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Benno Lossin and committed by
Miguel Ojeda
9b2299af dbd5058b

+221 -7
+1 -1
rust/Makefile
··· 121 121 122 122 rustdoc-pin_init: private rustdoc_host = yes 123 123 rustdoc-pin_init: private rustc_target_flags = --extern pin_init_internal \ 124 - --extern macros --extern force:alloc --cfg kernel --cfg feature=\"alloc\" 124 + --extern macros --extern alloc --cfg kernel --cfg feature=\"alloc\" 125 125 rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \ 126 126 rustdoc-macros FORCE 127 127 +$(call if_changed,rustdoc)
+27
rust/pin-init/src/__internal.rs
··· 189 189 } 190 190 } 191 191 192 + #[test] 193 + fn stack_init_reuse() { 194 + use ::std::{borrow::ToOwned, println, string::String}; 195 + use core::pin::pin; 196 + 197 + #[derive(Debug)] 198 + struct Foo { 199 + a: usize, 200 + b: String, 201 + } 202 + let mut slot: Pin<&mut StackInit<Foo>> = pin!(StackInit::uninit()); 203 + let value: Result<Pin<&mut Foo>, core::convert::Infallible> = 204 + slot.as_mut().init(crate::init!(Foo { 205 + a: 42, 206 + b: "Hello".to_owned(), 207 + })); 208 + let value = value.unwrap(); 209 + println!("{value:?}"); 210 + let value: Result<Pin<&mut Foo>, core::convert::Infallible> = 211 + slot.as_mut().init(crate::init!(Foo { 212 + a: 24, 213 + b: "world!".to_owned(), 214 + })); 215 + let value = value.unwrap(); 216 + println!("{value:?}"); 217 + } 218 + 192 219 /// When a value of this type is dropped, it drops a `T`. 193 220 /// 194 221 /// Can be forgotten to prevent the drop.
+158
rust/pin-init/src/alloc.rs
··· 1 + // SPDX-License-Identifier: Apache-2.0 OR MIT 2 + 3 + #[cfg(all(feature = "alloc", not(feature = "std")))] 4 + use alloc::{boxed::Box, sync::Arc}; 5 + #[cfg(feature = "alloc")] 6 + use core::alloc::AllocError; 7 + use core::{mem::MaybeUninit, pin::Pin}; 8 + #[cfg(feature = "std")] 9 + use std::sync::Arc; 10 + 11 + #[cfg(not(feature = "alloc"))] 12 + type AllocError = core::convert::Infallible; 13 + 14 + use crate::{ 15 + init_from_closure, pin_init_from_closure, InPlaceWrite, Init, PinInit, ZeroableOption, 16 + }; 17 + 18 + pub extern crate alloc; 19 + 20 + // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee). 21 + // 22 + // In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant and there 23 + // is no problem with a VTABLE pointer being null. 24 + unsafe impl<T: ?Sized> ZeroableOption for Box<T> {} 25 + 26 + /// Smart pointer that can initialize memory in-place. 27 + pub trait InPlaceInit<T>: Sized { 28 + /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this 29 + /// type. 30 + /// 31 + /// If `T: !Unpin` it will not be able to move afterwards. 32 + fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> 33 + where 34 + E: From<AllocError>; 35 + 36 + /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this 37 + /// type. 38 + /// 39 + /// If `T: !Unpin` it will not be able to move afterwards. 40 + fn pin_init(init: impl PinInit<T>) -> Result<Pin<Self>, AllocError> { 41 + // SAFETY: We delegate to `init` and only change the error type. 42 + let init = unsafe { 43 + pin_init_from_closure(|slot| match init.__pinned_init(slot) { 44 + Ok(()) => Ok(()), 45 + Err(i) => match i {}, 46 + }) 47 + }; 48 + Self::try_pin_init(init) 49 + } 50 + 51 + /// Use the given initializer to in-place initialize a `T`. 52 + fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> 53 + where 54 + E: From<AllocError>; 55 + 56 + /// Use the given initializer to in-place initialize a `T`. 57 + fn init(init: impl Init<T>) -> Result<Self, AllocError> { 58 + // SAFETY: We delegate to `init` and only change the error type. 59 + let init = unsafe { 60 + init_from_closure(|slot| match init.__init(slot) { 61 + Ok(()) => Ok(()), 62 + Err(i) => match i {}, 63 + }) 64 + }; 65 + Self::try_init(init) 66 + } 67 + } 68 + 69 + #[cfg(feature = "alloc")] 70 + macro_rules! try_new_uninit { 71 + ($type:ident) => { 72 + $type::try_new_uninit()? 73 + }; 74 + } 75 + #[cfg(all(feature = "std", not(feature = "alloc")))] 76 + macro_rules! try_new_uninit { 77 + ($type:ident) => { 78 + $type::new_uninit() 79 + }; 80 + } 81 + 82 + impl<T> InPlaceInit<T> for Box<T> { 83 + #[inline] 84 + fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> 85 + where 86 + E: From<AllocError>, 87 + { 88 + try_new_uninit!(Box).write_pin_init(init) 89 + } 90 + 91 + #[inline] 92 + fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> 93 + where 94 + E: From<AllocError>, 95 + { 96 + try_new_uninit!(Box).write_init(init) 97 + } 98 + } 99 + 100 + impl<T> InPlaceInit<T> for Arc<T> { 101 + #[inline] 102 + fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> 103 + where 104 + E: From<AllocError>, 105 + { 106 + let mut this = try_new_uninit!(Arc); 107 + let Some(slot) = Arc::get_mut(&mut this) else { 108 + // SAFETY: the Arc has just been created and has no external references 109 + unsafe { core::hint::unreachable_unchecked() } 110 + }; 111 + let slot = slot.as_mut_ptr(); 112 + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 113 + // slot is valid and will not be moved, because we pin it later. 114 + unsafe { init.__pinned_init(slot)? }; 115 + // SAFETY: All fields have been initialized and this is the only `Arc` to that data. 116 + Ok(unsafe { Pin::new_unchecked(this.assume_init()) }) 117 + } 118 + 119 + #[inline] 120 + fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> 121 + where 122 + E: From<AllocError>, 123 + { 124 + let mut this = try_new_uninit!(Arc); 125 + let Some(slot) = Arc::get_mut(&mut this) else { 126 + // SAFETY: the Arc has just been created and has no external references 127 + unsafe { core::hint::unreachable_unchecked() } 128 + }; 129 + let slot = slot.as_mut_ptr(); 130 + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 131 + // slot is valid. 132 + unsafe { init.__init(slot)? }; 133 + // SAFETY: All fields have been initialized. 134 + Ok(unsafe { this.assume_init() }) 135 + } 136 + } 137 + 138 + impl<T> InPlaceWrite<T> for Box<MaybeUninit<T>> { 139 + type Initialized = Box<T>; 140 + 141 + fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> { 142 + let slot = self.as_mut_ptr(); 143 + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 144 + // slot is valid. 145 + unsafe { init.__init(slot)? }; 146 + // SAFETY: All fields have been initialized. 147 + Ok(unsafe { self.assume_init() }) 148 + } 149 + 150 + fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> { 151 + let slot = self.as_mut_ptr(); 152 + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 153 + // slot is valid and will not be moved, because we pin it later. 154 + unsafe { init.__pinned_init(slot)? }; 155 + // SAFETY: All fields have been initialized. 156 + Ok(unsafe { self.assume_init() }.into()) 157 + } 158 + }
+35 -6
rust/pin-init/src/lib.rs
··· 204 204 //! [structurally pinned fields]: 205 205 //! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field 206 206 //! [stack]: crate::stack_pin_init 207 - //! [`Arc<T>`]: https://rust.docs.kernel.org/kernel/sync/struct.Arc.html 208 - //! [`Box<T>`]: https://rust.docs.kernel.org/kernel/alloc/kbox/struct.Box.html 207 + #![cfg_attr( 208 + kernel, 209 + doc = "[`Arc<T>`]: https://rust.docs.kernel.org/kernel/sync/struct.Arc.html" 210 + )] 211 + #![cfg_attr( 212 + kernel, 213 + doc = "[`Box<T>`]: https://rust.docs.kernel.org/kernel/alloc/kbox/struct.Box.html" 214 + )] 215 + #![cfg_attr(not(kernel), doc = "[`Arc<T>`]: alloc::alloc::sync::Arc")] 216 + #![cfg_attr(not(kernel), doc = "[`Box<T>`]: alloc::alloc::boxed::Box")] 209 217 //! [`impl PinInit<Foo>`]: PinInit 210 218 //! [`impl PinInit<T, E>`]: PinInit 211 219 //! [`impl Init<T, E>`]: Init ··· 246 238 pub mod __internal; 247 239 #[doc(hidden)] 248 240 pub mod macros; 241 + 242 + #[cfg(any(feature = "std", feature = "alloc"))] 243 + mod alloc; 244 + #[cfg(any(feature = "std", feature = "alloc"))] 245 + pub use alloc::InPlaceInit; 249 246 250 247 /// Used to specify the pinning information of the fields of a struct. 251 248 /// ··· 927 914 /// - `slot` is not partially initialized. 928 915 /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. 929 916 /// 930 - /// [`Arc<T>`]: https://rust.docs.kernel.org/kernel/sync/struct.Arc.html 931 - /// [`Box<T>`]: https://rust.docs.kernel.org/kernel/alloc/kbox/struct.Box.html 917 + #[cfg_attr( 918 + kernel, 919 + doc = "[`Arc<T>`]: https://rust.docs.kernel.org/kernel/sync/struct.Arc.html" 920 + )] 921 + #[cfg_attr( 922 + kernel, 923 + doc = "[`Box<T>`]: https://rust.docs.kernel.org/kernel/alloc/kbox/struct.Box.html" 924 + )] 925 + #[cfg_attr(not(kernel), doc = "[`Arc<T>`]: alloc::alloc::sync::Arc")] 926 + #[cfg_attr(not(kernel), doc = "[`Box<T>`]: alloc::alloc::boxed::Box")] 932 927 #[must_use = "An initializer must be used in order to create its value."] 933 928 pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { 934 929 /// Initializes `slot`. ··· 1026 1005 /// Contrary to its supertype [`PinInit<T, E>`] the caller is allowed to 1027 1006 /// move the pointee after initialization. 1028 1007 /// 1029 - /// [`Arc<T>`]: https://rust.docs.kernel.org/kernel/sync/struct.Arc.html 1030 - /// [`Box<T>`]: https://rust.docs.kernel.org/kernel/alloc/kbox/struct.Box.html 1008 + #[cfg_attr( 1009 + kernel, 1010 + doc = "[`Arc<T>`]: https://rust.docs.kernel.org/kernel/sync/struct.Arc.html" 1011 + )] 1012 + #[cfg_attr( 1013 + kernel, 1014 + doc = "[`Box<T>`]: https://rust.docs.kernel.org/kernel/alloc/kbox/struct.Box.html" 1015 + )] 1016 + #[cfg_attr(not(kernel), doc = "[`Arc<T>`]: alloc::alloc::sync::Arc")] 1017 + #[cfg_attr(not(kernel), doc = "[`Box<T>`]: alloc::alloc::boxed::Box")] 1031 1018 #[must_use = "An initializer must be used in order to create its value."] 1032 1019 pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> { 1033 1020 /// Initializes `slot`.