Struct IdPool

Source
pub struct IdPool { /* private fields */ }
Expand description

Represents a dynamic ID pool backed by a BitmapVec.

Clients acquire and release IDs from unset bits in a bitmap.

The capacity of the ID pool may be adjusted by users as needed. The API supports the scenario where users need precise control over the time of allocation of a new backing bitmap, which may require release of spinlock. Due to concurrent updates, all operations are re-verified to determine if the grow or shrink is sill valid.

§Examples

Basic usage

use kernel::alloc::{AllocError, flags::GFP_KERNEL};
use kernel::id_pool::IdPool;

let mut pool = IdPool::new(64, GFP_KERNEL)?;
for i in 0..64 {
    assert_eq!(i, pool.acquire_next_id(i).ok_or(ENOSPC)?);
}

pool.release_id(23);
assert_eq!(23, pool.acquire_next_id(0).ok_or(ENOSPC)?);

assert_eq!(None, pool.acquire_next_id(0));  // time to realloc.
let resizer = pool.grow_request().ok_or(ENOSPC)?.realloc(GFP_KERNEL)?;
pool.grow(resizer);

assert_eq!(pool.acquire_next_id(0), Some(64));

Releasing spinlock to grow the pool

use kernel::alloc::{AllocError, flags::GFP_KERNEL};
use kernel::sync::{new_spinlock, SpinLock};
use kernel::id_pool::IdPool;

fn get_id_maybe_realloc(guarded_pool: &SpinLock<IdPool>) -> Result<usize, AllocError> {
    let mut pool = guarded_pool.lock();
    loop {
        match pool.acquire_next_id(0) {
            Some(index) => return Ok(index),
            None => {
                let alloc_request = pool.grow_request();
                drop(pool);
                let resizer = alloc_request.ok_or(AllocError)?.realloc(GFP_KERNEL)?;
                pool = guarded_pool.lock();
                pool.grow(resizer)
            }
        }
    }
}

Implementations§

Source§

impl IdPool

Source

pub fn new(num_ids: usize, flags: Flags) -> Result<Self, AllocError>

Constructs a new IdPool.

A capacity below BITS_PER_LONG is adjusted to BITS_PER_LONG.

Source

pub fn capacity(&self) -> usize

Returns how many IDs this pool can currently have.

Source

pub fn shrink_request(&self) -> Option<ReallocRequest>

Returns a ReallocRequest if the IdPool can be shrunk, None otherwise.

The capacity of an IdPool cannot be shrunk below BITS_PER_LONG.

§Examples
use kernel::alloc::{AllocError, flags::GFP_KERNEL};
use kernel::id_pool::{ReallocRequest, IdPool};

let mut pool = IdPool::new(1024, GFP_KERNEL)?;
let alloc_request = pool.shrink_request().ok_or(AllocError)?;
let resizer = alloc_request.realloc(GFP_KERNEL)?;
pool.shrink(resizer);
assert_eq!(pool.capacity(), kernel::bindings::BITS_PER_LONG as usize);
Source

pub fn shrink(&mut self, resizer: PoolResizer)

Shrinks pool by using a new BitmapVec, if still possible.

Source

pub fn grow_request(&self) -> Option<ReallocRequest>

Returns a ReallocRequest for growing this IdPool, if possible.

The capacity of an IdPool cannot be grown above i32::MAX.

Source

pub fn grow(&mut self, resizer: PoolResizer)

Grows pool by using a new BitmapVec, if still necessary.

The resizer arguments has to be obtained by calling Self::grow_request on this object and performing a ReallocRequest::realloc.

Source

pub fn acquire_next_id(&mut self, offset: usize) -> Option<usize>

Acquires a new ID by finding and setting the next zero bit in the bitmap.

Upon success, returns its index. Otherwise, returns None to indicate that a Self::grow_request is needed.

Source

pub fn release_id(&mut self, id: usize)

Releases an ID.

Auto Trait Implementations§

§

impl Freeze for IdPool

§

impl RefUnwindSafe for IdPool

§

impl Send for IdPool

§

impl Sync for IdPool

§

impl Unpin for IdPool

§

impl UnwindSafe for IdPool

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Init<T> for T

Source§

unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible>

Initializes slot. Read more
Source§

fn chain<F>(self, f: F) -> ChainInit<Self, F, T, E>
where F: FnOnce(&mut T) -> Result<(), E>,

First initializes the value using self then calls the function f with the initialized value. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PinInit<T> for T

Source§

unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible>

Initializes slot. Read more
Source§

fn pin_chain<F>(self, f: F) -> ChainPinInit<Self, F, T, E>
where F: FnOnce(Pin<&mut T>) -> Result<(), E>,

First initializes the value using self then calls the function f with the initialized value. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.