mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 02:38:04 +02:00
Merge branch 'atomic_mem' into 'main'
util/rust: Add atomic memory synchronization support See merge request mesa/mesa!39653
This commit is contained in:
commit
2f4434d272
10 changed files with 190 additions and 0 deletions
88
src/util/rust/atomic_memory_sentinel.rs
Normal file
88
src/util/rust/atomic_memory_sentinel.rs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2026 Red Hat, Inc.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! AtomicMemorySentinel - Cross-platform atomic memory synchronization primitive.
|
||||
//!
|
||||
//! Provides access to futex and WaitOnAddress-like APIs for atomic memory operations.
|
||||
|
||||
use std::mem::size_of;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use crate::sys::platform::atomic_memory_sentinel;
|
||||
use crate::MappedRegion;
|
||||
use crate::MemoryMapping;
|
||||
use crate::MesaError;
|
||||
use crate::MesaResult;
|
||||
|
||||
/// A sentinel that provides access to atomic memory.
|
||||
/// Safe to share across threads.
|
||||
pub struct AtomicMemorySentinel {
|
||||
_memory_mapping: MemoryMapping,
|
||||
atomic_ptr: *mut u32,
|
||||
}
|
||||
|
||||
// SAFETY: AtomicMemorySentinel can be sent across threads.
|
||||
unsafe impl Send for AtomicMemorySentinel {}
|
||||
// SAFETY: AtomicMemorySentinel can be shared across threads.
|
||||
unsafe impl Sync for AtomicMemorySentinel {}
|
||||
|
||||
impl AtomicMemorySentinel {
|
||||
/// Create a new AtomicMemorySentinel from a memory mapping.
|
||||
pub fn new(memory_mapping: MemoryMapping) -> MesaResult<Self> {
|
||||
if memory_mapping.size() < size_of::<u32>() {
|
||||
return Err(MesaError::WithContext(
|
||||
"memory mapping too small for AtomicU32",
|
||||
));
|
||||
}
|
||||
|
||||
let atomic_ptr = memory_mapping.as_ptr() as *mut u32;
|
||||
|
||||
Ok(Self {
|
||||
_memory_mapping: memory_mapping,
|
||||
atomic_ptr,
|
||||
})
|
||||
}
|
||||
|
||||
/// Signal that the atomic memory has changed.
|
||||
///
|
||||
/// This will wake up waiters on this sentinel.
|
||||
pub fn signal(&self) -> MesaResult<()> {
|
||||
// SAFETY: self.atomic_ptr is valid for the lifetime of the MemoryMapping,
|
||||
// properly aligned, and we have exclusive ownership via the MemoryMapping.
|
||||
let atomic_val = unsafe { AtomicU32::from_ptr(self.atomic_ptr) };
|
||||
atomic_memory_sentinel::wake_bitset(atomic_val, i32::MAX, 1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Load the current value from atomic memory.
|
||||
pub fn load(&self) -> u32 {
|
||||
// SAFETY: self.atomic_ptr is valid for the lifetime of the MemoryMapping,
|
||||
// properly aligned, and we have exclusive ownership via the MemoryMapping.
|
||||
let atomic_val = unsafe { AtomicU32::from_ptr(self.atomic_ptr) };
|
||||
atomic_val.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Store a value to atomic memory.
|
||||
pub fn store(&self, val: u32) {
|
||||
// SAFETY: self.atomic_ptr is valid for the lifetime of the MemoryMapping,
|
||||
// properly aligned, and we have exclusive ownership via the MemoryMapping.
|
||||
let atomic_val = unsafe { AtomicU32::from_ptr(self.atomic_ptr) };
|
||||
atomic_val.store(val, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// Wake all threads waiting on this sentinel.
|
||||
pub fn wake_all(&self) {
|
||||
// SAFETY: self.atomic_ptr is valid for the lifetime of the MemoryMapping,
|
||||
// properly aligned, and we have exclusive ownership via the MemoryMapping.
|
||||
let atomic_val = unsafe { AtomicU32::from_ptr(self.atomic_ptr) };
|
||||
atomic_memory_sentinel::wake_all(atomic_val);
|
||||
}
|
||||
|
||||
/// Blocks until the value changes from `val` or is woken up.
|
||||
pub fn wait(&self, val: u32) {
|
||||
// SAFETY: self.atomic_ptr is valid for the lifetime of the MemoryMapping,
|
||||
// properly aligned, and we have exclusive ownership via the MemoryMapping.
|
||||
let atomic_val = unsafe { AtomicU32::from_ptr(self.atomic_ptr) };
|
||||
atomic_memory_sentinel::wait_bitset(atomic_val, val, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -87,6 +87,7 @@ pub enum DescriptorType {
|
|||
Unknown,
|
||||
Memory(u32, u32), // (size, handle_type)
|
||||
WritePipe,
|
||||
Event,
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2025 Google
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
mod atomic_memory_sentinel;
|
||||
mod bytestream;
|
||||
mod defines;
|
||||
mod descriptor;
|
||||
|
|
@ -9,6 +10,7 @@ mod memory_mapping;
|
|||
mod shm;
|
||||
mod sys;
|
||||
|
||||
pub use atomic_memory_sentinel::AtomicMemorySentinel;
|
||||
pub use bytestream::Reader;
|
||||
pub use bytestream::Writer;
|
||||
pub use defines::*;
|
||||
|
|
|
|||
40
src/util/rust/sys/linux/atomic_memory_sentinel.rs
Normal file
40
src/util/rust/sys/linux/atomic_memory_sentinel.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2026 Red Hat, Inc.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Linux futex wrappers for cross-domain synchronization.
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
||||
use rustix::thread::futex;
|
||||
|
||||
/// Wait on a futex with a bitset mask.
|
||||
///
|
||||
/// Blocks until the futex is woken up or the value changes from `val`.
|
||||
pub fn wait_bitset(atomic_val: &AtomicU32, val: u32, bitset: u32) {
|
||||
let flags = futex::Flags::PRIVATE;
|
||||
let timeout = None;
|
||||
let val3 = NonZeroU32::new(bitset).unwrap_or(NonZeroU32::new(1).unwrap());
|
||||
|
||||
// Ignore errors - futex::wait_bitset returns an error if the value
|
||||
// has already changed or if interrupted, both are expected
|
||||
let _ = futex::wait_bitset(atomic_val, flags, val, timeout, val3);
|
||||
}
|
||||
|
||||
/// Wake threads waiting on a futex with a bitset mask.
|
||||
///
|
||||
/// Only wakes threads whose bitset matches the provided mask.
|
||||
pub fn wake_bitset(atomic_val: &AtomicU32, val: i32, bitset: u32) {
|
||||
let flags = futex::Flags::PRIVATE;
|
||||
let val_u32 = if val < 0 { i32::MAX as u32 } else { val as u32 };
|
||||
let val3 = NonZeroU32::new(bitset).unwrap_or(NonZeroU32::new(1).unwrap());
|
||||
|
||||
let _ = futex::wake_bitset(atomic_val, flags, val_u32, val3);
|
||||
}
|
||||
|
||||
/// Wake all threads waiting on a futex.
|
||||
pub fn wake_all(atomic_val: &AtomicU32) {
|
||||
let flags = futex::Flags::PRIVATE;
|
||||
// u32::MAX means wake all waiters
|
||||
let _ = futex::wake(atomic_val, flags, u32::MAX);
|
||||
}
|
||||
|
|
@ -47,6 +47,14 @@ impl OwnedDescriptor {
|
|||
}
|
||||
|
||||
pub fn determine_type(&self) -> Result<DescriptorType> {
|
||||
// Check for eventfd first (not seekable, special symlink)
|
||||
if let Ok(fd_path) = read_link(format!("/proc/self/fd/{}", self.as_raw_descriptor())) {
|
||||
let path_str = fd_path.to_string_lossy();
|
||||
if path_str.starts_with("anon_inode:[eventfd]") {
|
||||
return Ok(DescriptorType::Event);
|
||||
}
|
||||
}
|
||||
|
||||
match seek(&self.owned, SeekFrom::End(0)) {
|
||||
Ok(seek_size) => {
|
||||
let size: u32 = seek_size
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2025 Google
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pub mod atomic_memory_sentinel;
|
||||
pub mod descriptor;
|
||||
pub mod event;
|
||||
pub mod memory_mapping;
|
||||
|
|
|
|||
24
src/util/rust/sys/stub/atomic_memory_sentinel.rs
Normal file
24
src/util/rust/sys/stub/atomic_memory_sentinel.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2026 Red Hat, Inc.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Stub atomic memory synchronization implementation.
|
||||
//!
|
||||
//! The Linux backend uses futexes for atomic memory synchronization.
|
||||
//! This stub implementation allows compilation on platforms without native support.
|
||||
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
||||
/// Stub implementation - no-op on non-Linux platforms.
|
||||
pub fn wait_bitset(_atomic_val: &AtomicU32, _val: u32, _bitset: u32) {
|
||||
todo!("atomic memory synchronization not implemented on this platform")
|
||||
}
|
||||
|
||||
/// Stub implementation - no-op on non-Linux platforms.
|
||||
pub fn wake_bitset(_atomic_val: &AtomicU32, _val: i32, _bitset: u32) {
|
||||
todo!("atomic memory synchronization not implemented on this platform")
|
||||
}
|
||||
|
||||
/// Stub implementation - no-op on non-Linux platforms.
|
||||
pub fn wake_all(_atomic_val: &AtomicU32) {
|
||||
todo!("atomic memory synchronization not implemented on this platform")
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2025 Google
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pub mod atomic_memory_sentinel;
|
||||
pub mod descriptor;
|
||||
pub mod event;
|
||||
pub mod memory_mapping;
|
||||
|
|
|
|||
24
src/util/rust/sys/windows/atomic_memory_sentinel.rs
Normal file
24
src/util/rust/sys/windows/atomic_memory_sentinel.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2026 Red Hat, Inc.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Stub atomic memory synchronization implementation for Windows.
|
||||
//!
|
||||
//! The Linux backend uses futexes for atomic memory synchronization.
|
||||
//! This stub implementation allows compilation on Windows without native support.
|
||||
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
||||
/// Stub implementation - no-op on Windows.
|
||||
pub fn wait_bitset(_atomic_val: &AtomicU32, _val: u32, _bitset: u32) {
|
||||
todo!("atomic memory synchronization not implemented on this platform")
|
||||
}
|
||||
|
||||
/// Stub implementation - no-op on Windows.
|
||||
pub fn wake_bitset(_atomic_val: &AtomicU32, _val: i32, _bitset: u32) {
|
||||
todo!("atomic memory synchronization not implemented on this platform")
|
||||
}
|
||||
|
||||
/// Stub implementation - no-op on Windows.
|
||||
pub fn wake_all(_atomic_val: &AtomicU32) {
|
||||
todo!("atomic memory synchronization not implemented on this platform")
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2025 Google
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pub mod atomic_memory_sentinel;
|
||||
pub mod descriptor;
|
||||
pub mod event;
|
||||
pub mod memory_mapping;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue