mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-16 17:46:48 +00:00
Remove ostd::sync::AtomicBits
This commit is contained in:
parent
26c4abde58
commit
b400d287fa
@ -1,397 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use core::{
|
||||
fmt::{self},
|
||||
sync::atomic::{AtomicU64, Ordering::Relaxed},
|
||||
};
|
||||
|
||||
use align_ext::AlignExt;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// A fixed number of bits that can be safely shared between threads.
|
||||
pub struct AtomicBits {
|
||||
num_bits: usize,
|
||||
u64s: Box<[AtomicU64]>,
|
||||
}
|
||||
|
||||
impl AtomicBits {
|
||||
/// Creates a given number of bit 0s.
|
||||
pub fn new_zeroes(num_bits: usize) -> Self {
|
||||
Self::new(0, num_bits)
|
||||
}
|
||||
|
||||
/// Creates a given number of bit 1s.
|
||||
pub fn new_ones(num_bits: usize) -> Self {
|
||||
Self::new(!0, num_bits)
|
||||
}
|
||||
|
||||
fn new(u64_val: u64, num_bits: usize) -> Self {
|
||||
let num_u64s = num_bits.align_up(64) / 64;
|
||||
let u64s = {
|
||||
let mut u64s = Vec::with_capacity(num_u64s);
|
||||
for _ in 0..num_u64s {
|
||||
u64s.push(AtomicU64::new(u64_val));
|
||||
}
|
||||
u64s.into_boxed_slice()
|
||||
};
|
||||
Self { num_bits, u64s }
|
||||
}
|
||||
|
||||
/// Returns the length in bits.
|
||||
pub fn len(&self) -> usize {
|
||||
self.num_bits
|
||||
}
|
||||
|
||||
/// Gets the bit at a given position.
|
||||
pub fn get(&self, index: usize) -> bool {
|
||||
assert!(index < self.num_bits);
|
||||
let i = index / 64;
|
||||
let j = index % 64;
|
||||
// SAFETY: Variable i is in range as variable index is in range.
|
||||
let u64_atomic = unsafe { self.u64s.get_unchecked(i) };
|
||||
(u64_atomic.load(Relaxed) & 1 << j) != 0
|
||||
}
|
||||
|
||||
/// Sets the bit at a given position.
|
||||
pub fn set(&self, index: usize, new_bit: bool) {
|
||||
assert!(index < self.num_bits);
|
||||
let i = index / 64;
|
||||
let j = index % 64;
|
||||
// SAFETY: Variable i is in range as variable index is in range.
|
||||
let u64_atomic = unsafe { self.u64s.get_unchecked(i) };
|
||||
if new_bit {
|
||||
u64_atomic.fetch_or(1 << j, Relaxed);
|
||||
} else {
|
||||
u64_atomic.fetch_and(!(1 << j), Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears all the bits.
|
||||
pub fn clear(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Are all bits ones.
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.match_pattern(!0)
|
||||
}
|
||||
|
||||
/// Are all bits zeroes.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.match_pattern(0)
|
||||
}
|
||||
|
||||
fn match_pattern(&self, pattern: u64) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Gets an iterator for the bits.
|
||||
pub fn iter(&self) -> Iter<'_> {
|
||||
Iter::new(self)
|
||||
}
|
||||
|
||||
/// Gets an iterator that gives the positions of all 1s in the bits.
|
||||
pub fn iter_ones(&self) -> OnesIter<'_> {
|
||||
OnesIter::new(self)
|
||||
}
|
||||
|
||||
/// Gets an iterator that gives the positions of all 0s in the bits.
|
||||
pub fn iter_zeroes(&self) -> ZeroesIter<'_> {
|
||||
ZeroesIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that accesses the bits of an `AtomicBits`.
|
||||
pub struct Iter<'a> {
|
||||
bits: &'a AtomicBits,
|
||||
bit_i: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iter<'a> {
|
||||
fn new(bits: &'a AtomicBits) -> Self {
|
||||
Self { bits, bit_i: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Iter<'_> {
|
||||
type Item = bool;
|
||||
|
||||
fn next(&mut self) -> Option<bool> {
|
||||
if self.bit_i < self.bits.len() {
|
||||
let bit = self.bits.get(self.bit_i);
|
||||
self.bit_i += 1;
|
||||
Some(bit)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that returns the positions of 1s in an [`AtomicBits`].
|
||||
pub struct OnesIter<'a> {
|
||||
bits: &'a AtomicBits,
|
||||
u64_idx: usize,
|
||||
u64_val: u64,
|
||||
num_garbage_bits_in_last_u64: u8,
|
||||
}
|
||||
|
||||
impl<'a> OnesIter<'a> {
|
||||
fn new(bits: &'a AtomicBits) -> Self {
|
||||
let num_garbage_bits_in_last_u64 = {
|
||||
if bits.len() % 64 != 0 {
|
||||
64 - ((bits.len() % 64) as u8)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
let mut new_self = Self {
|
||||
bits,
|
||||
u64_idx: 0,
|
||||
u64_val: 0, // NOT initialized yet!
|
||||
num_garbage_bits_in_last_u64,
|
||||
};
|
||||
new_self.u64_val = new_self.get_u64_val(0);
|
||||
new_self
|
||||
}
|
||||
|
||||
/// Gets the u64 value at the given position, removing the garbage bits if any.
|
||||
fn get_u64_val(&self, idx: usize) -> u64 {
|
||||
let mut u64_val = self.bits.u64s[idx].load(Relaxed);
|
||||
// Clear the garbage bits, if any, in the last u64 so that they
|
||||
// won't affect the result of the iterator.
|
||||
if idx == self.bits.u64s.len() - 1 && self.num_garbage_bits_in_last_u64 > 0 {
|
||||
let num_valid_bits_in_last_u64 = 64 - self.num_garbage_bits_in_last_u64;
|
||||
let valid_bits_mask = (1 << num_valid_bits_in_last_u64) - 1;
|
||||
u64_val &= valid_bits_mask;
|
||||
}
|
||||
u64_val
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for OnesIter<'_> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<usize> {
|
||||
loop {
|
||||
if self.u64_idx >= self.bits.u64s.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let first_one_in_u64 = self.u64_val.trailing_zeros() as usize;
|
||||
if first_one_in_u64 < 64 {
|
||||
self.u64_val &= !(1 << first_one_in_u64);
|
||||
let one_pos = self.u64_idx * 64 + first_one_in_u64;
|
||||
return Some(one_pos);
|
||||
}
|
||||
|
||||
self.u64_idx += 1;
|
||||
if self.u64_idx < self.bits.u64s.len() {
|
||||
self.u64_val = self.get_u64_val(self.u64_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that returns the positions of 0s in an [`AtomicBits`].
|
||||
pub struct ZeroesIter<'a> {
|
||||
bits: &'a AtomicBits,
|
||||
u64_idx: usize,
|
||||
u64_val: u64,
|
||||
num_garbage_bits_in_last_u64: u8,
|
||||
}
|
||||
|
||||
impl<'a> ZeroesIter<'a> {
|
||||
fn new(bits: &'a AtomicBits) -> Self {
|
||||
let num_garbage_bits_in_last_u64 = {
|
||||
if bits.len() % 64 != 0 {
|
||||
64 - ((bits.len() % 64) as u8)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
let mut new_self = Self {
|
||||
bits,
|
||||
u64_idx: 0,
|
||||
u64_val: 0, // NOT initialized yet!
|
||||
num_garbage_bits_in_last_u64,
|
||||
};
|
||||
new_self.u64_val = new_self.get_u64_val(0);
|
||||
new_self
|
||||
}
|
||||
|
||||
/// Gets the u64 value at the given position, removing the garbage bits if any.
|
||||
fn get_u64_val(&self, idx: usize) -> u64 {
|
||||
let mut u64_val = self.bits.u64s[idx].load(Relaxed);
|
||||
// Set all garbage bits, if any, in the last u64 so that they
|
||||
// won't affect the result of the iterator.
|
||||
if idx == self.bits.u64s.len() - 1 && self.num_garbage_bits_in_last_u64 > 0 {
|
||||
let num_valid_bits_in_last_u64 = 64 - self.num_garbage_bits_in_last_u64;
|
||||
let garbage_bits_mask = !((1 << num_valid_bits_in_last_u64) - 1);
|
||||
u64_val |= garbage_bits_mask;
|
||||
}
|
||||
u64_val
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ZeroesIter<'_> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<usize> {
|
||||
loop {
|
||||
if self.u64_idx >= self.bits.u64s.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let first_zero_in_u64 = self.u64_val.trailing_ones() as usize;
|
||||
if first_zero_in_u64 < 64 {
|
||||
self.u64_val |= 1 << first_zero_in_u64;
|
||||
let one_pos = self.u64_idx * 64 + first_zero_in_u64;
|
||||
return Some(one_pos);
|
||||
}
|
||||
|
||||
self.u64_idx += 1;
|
||||
if self.u64_idx < self.bits.u64s.len() {
|
||||
self.u64_val = self.get_u64_val(self.u64_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for AtomicBits {
|
||||
fn clone(&self) -> Self {
|
||||
let num_bits = self.num_bits;
|
||||
let num_u64s = self.u64s.len();
|
||||
let u64s = {
|
||||
let mut u64s = Vec::with_capacity(num_u64s);
|
||||
for u64_i in 0..num_u64s {
|
||||
let u64_val = self.u64s[u64_i].load(Relaxed);
|
||||
u64s.push(AtomicU64::new(u64_val));
|
||||
}
|
||||
u64s.into_boxed_slice()
|
||||
};
|
||||
Self { num_bits, u64s }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AtomicBits {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "AtomicBits(")?;
|
||||
for bit in self.iter() {
|
||||
if bit {
|
||||
write!(f, "1")?;
|
||||
} else {
|
||||
write!(f, "0")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(ktest)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[ktest]
|
||||
fn new() {
|
||||
let bits = AtomicBits::new_zeroes(1);
|
||||
assert!(bits.len() == 1);
|
||||
|
||||
let bits = AtomicBits::new_zeroes(128);
|
||||
assert!(bits.len() == 128);
|
||||
|
||||
let bits = AtomicBits::new_ones(7);
|
||||
assert!(bits.len() == 7);
|
||||
|
||||
let bits = AtomicBits::new_zeroes(65);
|
||||
assert!(bits.len() == 65);
|
||||
}
|
||||
|
||||
#[ktest]
|
||||
fn set_get() {
|
||||
let bits = AtomicBits::new_zeroes(128);
|
||||
for i in 0..bits.len() {
|
||||
assert!(!bits.get(i));
|
||||
|
||||
bits.set(i, true);
|
||||
assert!(bits.get(i));
|
||||
|
||||
bits.set(i, false);
|
||||
assert!(!bits.get(i));
|
||||
}
|
||||
|
||||
let bits = AtomicBits::new_ones(128);
|
||||
for i in 0..bits.len() {
|
||||
assert!(bits.get(i));
|
||||
|
||||
bits.set(i, false);
|
||||
assert!(!bits.get(i));
|
||||
|
||||
bits.set(i, true);
|
||||
assert!(bits.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
#[ktest]
|
||||
fn iter_ones() {
|
||||
let bits = AtomicBits::new_zeroes(1);
|
||||
assert!(bits.iter_ones().count() == 0);
|
||||
let bits = AtomicBits::new_zeroes(400);
|
||||
assert!(bits.iter_ones().count() == 0);
|
||||
|
||||
let bits = AtomicBits::new_ones(1);
|
||||
assert!(bits.iter_ones().count() == 1);
|
||||
let bits = AtomicBits::new_ones(24);
|
||||
assert!(bits.iter_ones().count() == 24);
|
||||
let bits = AtomicBits::new_ones(64);
|
||||
assert!(bits.iter_ones().count() == 64);
|
||||
let bits = AtomicBits::new_ones(77);
|
||||
assert!(bits.iter_ones().count() == 77);
|
||||
let bits = AtomicBits::new_ones(128);
|
||||
assert!(bits.iter_ones().count() == 128);
|
||||
|
||||
let bits = AtomicBits::new_zeroes(8);
|
||||
bits.set(1, true);
|
||||
bits.set(3, true);
|
||||
bits.set(5, true);
|
||||
assert!(bits.iter_ones().count() == 3);
|
||||
}
|
||||
|
||||
#[ktest]
|
||||
fn iter_zeroes() {
|
||||
let bits = AtomicBits::new_ones(1);
|
||||
assert!(bits.iter_zeroes().count() == 0);
|
||||
let bits = AtomicBits::new_ones(130);
|
||||
assert!(bits.iter_zeroes().count() == 0);
|
||||
|
||||
let bits = AtomicBits::new_zeroes(1);
|
||||
assert!(bits.iter_zeroes().count() == 1);
|
||||
let bits = AtomicBits::new_zeroes(24);
|
||||
assert!(bits.iter_zeroes().count() == 24);
|
||||
let bits = AtomicBits::new_zeroes(64);
|
||||
assert!(bits.iter_zeroes().count() == 64);
|
||||
let bits = AtomicBits::new_zeroes(77);
|
||||
assert!(bits.iter_zeroes().count() == 77);
|
||||
let bits = AtomicBits::new_zeroes(128);
|
||||
assert!(bits.iter_zeroes().count() == 128);
|
||||
|
||||
let bits = AtomicBits::new_ones(96);
|
||||
bits.set(1, false);
|
||||
bits.set(3, false);
|
||||
bits.set(5, false);
|
||||
bits.set(64, false);
|
||||
bits.set(76, false);
|
||||
assert!(bits.iter_zeroes().count() == 5);
|
||||
}
|
||||
|
||||
#[ktest]
|
||||
fn iter() {
|
||||
let bits = AtomicBits::new_zeroes(7);
|
||||
assert!(bits.iter().all(|bit| !bit));
|
||||
|
||||
let bits = AtomicBits::new_ones(128);
|
||||
assert!(bits.iter().all(|bit| bit));
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
|
||||
//! Useful synchronization primitives.
|
||||
|
||||
mod atomic_bits;
|
||||
mod mutex;
|
||||
// TODO: refactor this rcu implementation
|
||||
// Comment out this module since it raises lint error
|
||||
@ -14,7 +13,6 @@ mod wait;
|
||||
|
||||
// pub use self::rcu::{pass_quiescent_state, OwnerPtr, Rcu, RcuReadGuard, RcuReclaimer};
|
||||
pub use self::{
|
||||
atomic_bits::AtomicBits,
|
||||
mutex::{ArcMutexGuard, Mutex, MutexGuard},
|
||||
rwlock::{
|
||||
ArcRwLockReadGuard, ArcRwLockUpgradeableGuard, ArcRwLockWriteGuard, RwLock,
|
||||
|
Loading…
x
Reference in New Issue
Block a user