mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 20:16:42 +00:00
Remove ostd::sync::AtomicBits
This commit is contained in:
committed by
Tate, Hongliang Tian
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.
|
//! Useful synchronization primitives.
|
||||||
|
|
||||||
mod atomic_bits;
|
|
||||||
mod mutex;
|
mod mutex;
|
||||||
// TODO: refactor this rcu implementation
|
// TODO: refactor this rcu implementation
|
||||||
// Comment out this module since it raises lint error
|
// 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::rcu::{pass_quiescent_state, OwnerPtr, Rcu, RcuReadGuard, RcuReclaimer};
|
||||||
pub use self::{
|
pub use self::{
|
||||||
atomic_bits::AtomicBits,
|
|
||||||
mutex::{ArcMutexGuard, Mutex, MutexGuard},
|
mutex::{ArcMutexGuard, Mutex, MutexGuard},
|
||||||
rwlock::{
|
rwlock::{
|
||||||
ArcRwLockReadGuard, ArcRwLockUpgradeableGuard, ArcRwLockWriteGuard, RwLock,
|
ArcRwLockReadGuard, ArcRwLockUpgradeableGuard, ArcRwLockWriteGuard, RwLock,
|
||||||
|
Reference in New Issue
Block a user