mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
rust: id_pool: do not immediately acquire new ids
When Rust Binder assigns a new ID, it performs various fallible operations before it "commits" to actually using the new ID. To support this pattern, change acquire_next_id() so that it does not immediately call set_bit(), but instead returns an object that may be used to call set_bit() later. The UnusedId type holds a exclusive reference to the IdPool, so it's guaranteed that nobody else can call find_unused_id() while the UnusedId object is live. [Miguel: rust: id_pool: fix example] Reviewed-by: Burak Emir <bqe@google.com> Reviewed-by: Danilo Krummrich <dakr@kernel.org> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Yury Norov (NVIDIA) <yury.norov@gmail.com>
This commit is contained in:
committed by
Yury Norov (NVIDIA)
parent
69ec6a1bed
commit
f523d110a6
@@ -23,22 +23,22 @@ use crate::bitmap::BitmapVec;
|
|||||||
/// Basic usage
|
/// Basic usage
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use kernel::alloc::{AllocError, flags::GFP_KERNEL};
|
/// use kernel::alloc::AllocError;
|
||||||
/// use kernel::id_pool::IdPool;
|
/// use kernel::id_pool::{IdPool, UnusedId};
|
||||||
///
|
///
|
||||||
/// let mut pool = IdPool::with_capacity(64, GFP_KERNEL)?;
|
/// let mut pool = IdPool::with_capacity(64, GFP_KERNEL)?;
|
||||||
/// for i in 0..64 {
|
/// for i in 0..64 {
|
||||||
/// assert_eq!(i, pool.acquire_next_id(i).ok_or(ENOSPC)?);
|
/// assert_eq!(i, pool.find_unused_id(i).ok_or(ENOSPC)?.acquire());
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// pool.release_id(23);
|
/// pool.release_id(23);
|
||||||
/// assert_eq!(23, pool.acquire_next_id(0).ok_or(ENOSPC)?);
|
/// assert_eq!(23, pool.find_unused_id(0).ok_or(ENOSPC)?.acquire());
|
||||||
///
|
///
|
||||||
/// assert_eq!(None, pool.acquire_next_id(0)); // time to realloc.
|
/// assert!(pool.find_unused_id(0).is_none()); // time to realloc.
|
||||||
/// let resizer = pool.grow_request().ok_or(ENOSPC)?.realloc(GFP_KERNEL)?;
|
/// let resizer = pool.grow_request().ok_or(ENOSPC)?.realloc(GFP_KERNEL)?;
|
||||||
/// pool.grow(resizer);
|
/// pool.grow(resizer);
|
||||||
///
|
///
|
||||||
/// assert_eq!(pool.acquire_next_id(0), Some(64));
|
/// assert_eq!(pool.find_unused_id(0).ok_or(ENOSPC)?.acquire(), 64);
|
||||||
/// # Ok::<(), Error>(())
|
/// # Ok::<(), Error>(())
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@@ -52,8 +52,8 @@ use crate::bitmap::BitmapVec;
|
|||||||
/// fn get_id_maybe_realloc(guarded_pool: &SpinLock<IdPool>) -> Result<usize, AllocError> {
|
/// fn get_id_maybe_realloc(guarded_pool: &SpinLock<IdPool>) -> Result<usize, AllocError> {
|
||||||
/// let mut pool = guarded_pool.lock();
|
/// let mut pool = guarded_pool.lock();
|
||||||
/// loop {
|
/// loop {
|
||||||
/// match pool.acquire_next_id(0) {
|
/// match pool.find_unused_id(0) {
|
||||||
/// Some(index) => return Ok(index),
|
/// Some(index) => return Ok(index.acquire()),
|
||||||
/// None => {
|
/// None => {
|
||||||
/// let alloc_request = pool.grow_request();
|
/// let alloc_request = pool.grow_request();
|
||||||
/// drop(pool);
|
/// drop(pool);
|
||||||
@@ -221,18 +221,18 @@ impl IdPool {
|
|||||||
self.map = resizer.new;
|
self.map = resizer.new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acquires a new ID by finding and setting the next zero bit in the
|
/// Finds an unused ID in the bitmap.
|
||||||
/// bitmap.
|
|
||||||
///
|
///
|
||||||
/// Upon success, returns its index. Otherwise, returns [`None`]
|
/// Upon success, returns its index. Otherwise, returns [`None`]
|
||||||
/// to indicate that a [`Self::grow_request`] is needed.
|
/// to indicate that a [`Self::grow_request`] is needed.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn acquire_next_id(&mut self, offset: usize) -> Option<usize> {
|
#[must_use]
|
||||||
let next_zero_bit = self.map.next_zero_bit(offset);
|
pub fn find_unused_id(&mut self, offset: usize) -> Option<UnusedId<'_>> {
|
||||||
if let Some(nr) = next_zero_bit {
|
// INVARIANT: `next_zero_bit()` returns None or an integer less than `map.len()`
|
||||||
self.map.set_bit(nr);
|
Some(UnusedId {
|
||||||
}
|
id: self.map.next_zero_bit(offset)?,
|
||||||
next_zero_bit
|
pool: self,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases an ID.
|
/// Releases an ID.
|
||||||
@@ -242,6 +242,51 @@ impl IdPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents an unused id in an [`IdPool`].
|
||||||
|
///
|
||||||
|
/// # Invariants
|
||||||
|
///
|
||||||
|
/// The value of `id` is less than `pool.map.len()`.
|
||||||
|
pub struct UnusedId<'pool> {
|
||||||
|
id: usize,
|
||||||
|
pool: &'pool mut IdPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'pool> UnusedId<'pool> {
|
||||||
|
/// Get the unused id as an usize.
|
||||||
|
///
|
||||||
|
/// Be aware that the id has not yet been acquired in the pool. The
|
||||||
|
/// [`acquire`] method must be called to prevent others from taking the id.
|
||||||
|
///
|
||||||
|
/// [`acquire`]: UnusedId::acquire()
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn as_usize(&self) -> usize {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the unused id as an u32.
|
||||||
|
///
|
||||||
|
/// Be aware that the id has not yet been acquired in the pool. The
|
||||||
|
/// [`acquire`] method must be called to prevent others from taking the id.
|
||||||
|
///
|
||||||
|
/// [`acquire`]: UnusedId::acquire()
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn as_u32(&self) -> u32 {
|
||||||
|
// CAST: By the type invariants:
|
||||||
|
// `self.id < pool.map.len() <= BitmapVec::MAX_LEN = i32::MAX`.
|
||||||
|
self.id as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acquire the unused id.
|
||||||
|
#[inline]
|
||||||
|
pub fn acquire(self) -> usize {
|
||||||
|
self.pool.map.set_bit(self.id);
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for IdPool {
|
impl Default for IdPool {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|||||||
Reference in New Issue
Block a user