mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-14 10:19:08 +08:00
rust: pin-init: examples, tests: add conditional compilation in order to compile under any feature combination
In the CI, all examples & tests should be run under all feature
combinations. Currently several examples & tests use `std` without
conditionally enabling it. Thus make them all compile under any feature
combination by conditionally disabling the code that uses e.g. `std`.
Link: fdfb70efdd
Link: https://lore.kernel.org/all/20250523125424.192843-2-lossin@kernel.org
Signed-off-by: Benno Lossin <lossin@kernel.org>
This commit is contained in:
committed by
Benno Lossin
parent
e832374cca
commit
58cebd6888
@@ -4,6 +4,7 @@ use pin_init::*;
|
||||
|
||||
// Struct with size over 1GiB
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct BigStruct {
|
||||
buf: [u8; 1024 * 1024 * 1024],
|
||||
a: u64,
|
||||
@@ -25,15 +26,18 @@ impl ManagedBuf {
|
||||
}
|
||||
|
||||
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));
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ use core::{
|
||||
|
||||
use pin_init::*;
|
||||
|
||||
#[expect(unused_attributes)]
|
||||
#[allow(unused_attributes)]
|
||||
mod error;
|
||||
#[allow(unused_imports)]
|
||||
use error::Error;
|
||||
|
||||
#[pin_data(PinnedDrop)]
|
||||
@@ -39,6 +40,7 @@ impl ListHead {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
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)}),
|
||||
@@ -112,6 +114,7 @@ impl Link {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
fn prev(&self) -> &Link {
|
||||
unsafe { &(*self.0.get().as_ptr()).prev }
|
||||
}
|
||||
@@ -137,8 +140,13 @@ impl Link {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn main() {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg_attr(test, test)]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn main() -> Result<(), Error> {
|
||||
let a = Box::pin_init(ListHead::new())?;
|
||||
stack_pin_init!(let b = ListHead::insert_next(&a));
|
||||
|
||||
@@ -12,14 +12,15 @@ use core::{
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
use std::{
|
||||
sync::Arc,
|
||||
thread::{self, park, sleep, Builder, Thread},
|
||||
thread::{self, sleep, Builder, Thread},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use pin_init::*;
|
||||
#[expect(unused_attributes)]
|
||||
#[allow(unused_attributes)]
|
||||
#[path = "./linked_list.rs"]
|
||||
pub mod linked_list;
|
||||
use linked_list::*;
|
||||
@@ -36,6 +37,7 @@ impl SpinLock {
|
||||
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
#[cfg(feature = "std")]
|
||||
while self.inner.load(Ordering::Relaxed) {
|
||||
thread::yield_now();
|
||||
}
|
||||
@@ -94,7 +96,8 @@ impl<T> CMutex<T> {
|
||||
// println!("wait list length: {}", self.wait_list.size());
|
||||
while self.locked.get() {
|
||||
drop(sguard);
|
||||
park();
|
||||
#[cfg(feature = "std")]
|
||||
thread::park();
|
||||
sguard = self.spin_lock.acquire();
|
||||
}
|
||||
// This does have an effect, as the ListHead inside wait_entry implements Drop!
|
||||
@@ -131,8 +134,11 @@ impl<T> Drop for CMutexGuard<'_, T> {
|
||||
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() };
|
||||
let _wait_entry = list_field.as_ptr().cast::<WaitEntry>();
|
||||
#[cfg(feature = "std")]
|
||||
unsafe {
|
||||
(*_wait_entry).thread.unpark()
|
||||
};
|
||||
}
|
||||
drop(sguard);
|
||||
}
|
||||
@@ -159,52 +165,61 @@ impl<T> DerefMut for CMutexGuard<'_, T> {
|
||||
struct WaitEntry {
|
||||
#[pin]
|
||||
wait_list: ListHead,
|
||||
#[cfg(feature = "std")]
|
||||
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(feature = "std")]
|
||||
{
|
||||
pin_init!(Self {
|
||||
thread: thread::current(),
|
||||
wait_list <- ListHead::insert_prev(list),
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
pin_init!(Self {
|
||||
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"))]
|
||||
#[allow(dead_code)]
|
||||
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"),
|
||||
);
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
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);
|
||||
}
|
||||
for h in handles {
|
||||
h.join().expect("thread panicked");
|
||||
}
|
||||
println!("{:?}", &*mtx.lock());
|
||||
assert_eq!(*mtx.lock(), workload * thread_count * 2);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ mod pthread_mtx {
|
||||
pub enum Error {
|
||||
#[allow(dead_code)]
|
||||
IO(std::io::Error),
|
||||
#[allow(dead_code)]
|
||||
Alloc,
|
||||
}
|
||||
|
||||
@@ -61,6 +62,7 @@ mod pthread_mtx {
|
||||
}
|
||||
|
||||
impl<T> PThreadMutex<T> {
|
||||
#[allow(dead_code)]
|
||||
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>| {
|
||||
@@ -103,6 +105,7 @@ mod pthread_mtx {
|
||||
}? Error)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn lock(&self) -> PThreadMutexGuard<'_, T> {
|
||||
// SAFETY: raw is always initialized
|
||||
unsafe { libc::pthread_mutex_lock(self.raw.get()) };
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#![allow(clippy::undocumented_unsafe_blocks)]
|
||||
#![cfg_attr(feature = "alloc", feature(allocator_api))]
|
||||
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use core::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
@@ -12,12 +13,13 @@ use core::{
|
||||
time::Duration,
|
||||
};
|
||||
use pin_init::*;
|
||||
#[cfg(feature = "std")]
|
||||
use std::{
|
||||
sync::Arc,
|
||||
thread::{sleep, Builder},
|
||||
};
|
||||
|
||||
#[expect(unused_attributes)]
|
||||
#[allow(unused_attributes)]
|
||||
mod mutex;
|
||||
use mutex::*;
|
||||
|
||||
@@ -82,42 +84,41 @@ unsafe impl PinInit<CMutex<usize>> for CountInit {
|
||||
|
||||
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"),
|
||||
);
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
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);
|
||||
}
|
||||
for h in handles {
|
||||
h.join().expect("thread panicked");
|
||||
}
|
||||
println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock());
|
||||
assert_eq!(*mtx.lock(), workload * thread_count * 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user