Skip to content

Commit b26099a

Browse files
committed
Implement pool for any 32/64-bit architecture that supports the corresponding atomics.
1 parent 483862b commit b26099a

File tree

5 files changed

+99
-47
lines changed

5 files changed

+99
-47
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ defmt-03 = ["dep:defmt"]
3939
# Enable larger MPMC sizes.
4040
mpmc_large = []
4141

42+
nightly = []
43+
4244
[dependencies]
4345
portable-atomic = { version = "1.0", optional = true }
4446
hash32 = "0.3.0"
@@ -47,7 +49,7 @@ ufmt-write = { version = "0.1", optional = true }
4749
defmt = { version = ">=0.2.0,<0.4", optional = true }
4850

4951
# for the pool module
50-
[target.'cfg(any(target_arch = "arm", target_arch = "x86"))'.dependencies]
52+
[target.'cfg(any(target_arch = "arm", target_pointer_width = "32", target_pointer_width = "64"))'.dependencies]
5153
stable_deref_trait = { version = "1", default-features = false }
5254

5355
[dev-dependencies]

src/lib.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@
4343
//!
4444
//! List of currently implemented data structures:
4545
#![cfg_attr(
46-
any(arm_llsc, target_arch = "x86"),
46+
any(arm_llsc, target_pointer_width = "32", target_pointer_width = "64"),
4747
doc = "- [`Arc`](pool::arc::Arc) -- like `std::sync::Arc` but backed by a lock-free memory pool rather than `#[global_allocator]`"
4848
)]
4949
#![cfg_attr(
50-
any(arm_llsc, target_arch = "x86"),
50+
any(arm_llsc, target_pointer_width = "32", target_pointer_width = "64"),
5151
doc = "- [`Box`](pool::boxed::Box) -- like `std::boxed::Box` but backed by a lock-free memory pool rather than `#[global_allocator]`"
5252
)]
5353
//! - [`BinaryHeap`] -- priority queue
@@ -57,7 +57,7 @@
5757
//! - [`IndexSet`] -- hash set
5858
//! - [`LinearMap`]
5959
#![cfg_attr(
60-
any(arm_llsc, target_arch = "x86"),
60+
any(arm_llsc, target_pointer_width = "32", target_pointer_width = "64"),
6161
doc = "- [`Object`](pool::object::Object) -- objects managed by an object pool"
6262
)]
6363
//! - [`sorted_linked_list::SortedLinkedList`]
@@ -76,6 +76,14 @@
7676
#![cfg_attr(docsrs, feature(doc_cfg), feature(doc_auto_cfg))]
7777
#![cfg_attr(not(test), no_std)]
7878
#![deny(missing_docs)]
79+
#![cfg_attr(
80+
all(
81+
feature = "nightly",
82+
target_pointer_width = "64",
83+
target_has_atomic = "128"
84+
),
85+
feature(integer_atomics)
86+
)]
7987

8088
pub use binary_heap::BinaryHeap;
8189
pub use deque::Deque;
@@ -125,7 +133,20 @@ mod defmt;
125133
all(not(feature = "mpmc_large"), target_has_atomic = "8")
126134
))]
127135
pub mod mpmc;
128-
#[cfg(any(arm_llsc, target_arch = "x86"))]
136+
#[cfg(any(
137+
arm_llsc,
138+
all(
139+
target_pointer_width = "32",
140+
any(target_has_atomic = "64", feature = "portable-atomic")
141+
),
142+
all(
143+
target_pointer_width = "64",
144+
any(
145+
all(target_has_atomic = "128", feature = "nightly"),
146+
feature = "portable-atomic"
147+
)
148+
)
149+
))]
129150
pub mod pool;
130151
pub mod sorted_linked_list;
131152
#[cfg(any(

src/pool/treiber.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::mem::ManuallyDrop;
22

3-
#[cfg_attr(target_arch = "x86", path = "treiber/cas.rs")]
3+
#[cfg_attr(not(arm_llsc), path = "treiber/cas.rs")]
44
#[cfg_attr(arm_llsc, path = "treiber/llsc.rs")]
55
mod impl_;
66

src/pool/treiber/cas.rs

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,54 @@
1-
use core::{
2-
marker::PhantomData,
3-
num::{NonZeroU32, NonZeroU64},
4-
ptr::NonNull,
5-
sync::atomic::{AtomicU64, Ordering},
6-
};
1+
use core::{marker::PhantomData, ptr::NonNull, sync::atomic::Ordering};
2+
3+
#[cfg(not(feature = "portable-atomic"))]
4+
use core::sync::atomic;
5+
#[cfg(feature = "portable-atomic")]
6+
use portable_atomic as atomic;
77

88
use super::{Node, Stack};
99

10+
#[cfg(target_pointer_width = "32")]
11+
mod types {
12+
use super::atomic;
13+
14+
pub type Inner = u64;
15+
pub type InnerAtomic = atomic::AtomicU64;
16+
pub type InnerNonZero = core::num::NonZeroU64;
17+
18+
pub type Tag = core::num::NonZeroU32;
19+
pub type Address = u32;
20+
}
21+
22+
#[cfg(target_pointer_width = "64")]
23+
mod types {
24+
use super::atomic;
25+
26+
pub type Inner = u128;
27+
pub type InnerAtomic = atomic::AtomicU128;
28+
pub type InnerNonZero = core::num::NonZeroU128;
29+
30+
pub type Tag = core::num::NonZeroU64;
31+
pub type Address = u64;
32+
}
33+
34+
use types::*;
35+
1036
pub struct AtomicPtr<N>
1137
where
1238
N: Node,
1339
{
14-
inner: AtomicU64,
40+
inner: InnerAtomic,
1541
_marker: PhantomData<*mut N>,
1642
}
1743

1844
impl<N> AtomicPtr<N>
1945
where
2046
N: Node,
2147
{
48+
#[inline]
2249
pub const fn null() -> Self {
2350
Self {
24-
inner: AtomicU64::new(0),
51+
inner: InnerAtomic::new(0),
2552
_marker: PhantomData,
2653
}
2754
}
@@ -35,37 +62,35 @@ where
3562
) -> Result<(), Option<NonNullPtr<N>>> {
3663
self.inner
3764
.compare_exchange_weak(
38-
current
39-
.map(|pointer| pointer.into_u64())
40-
.unwrap_or_default(),
41-
new.map(|pointer| pointer.into_u64()).unwrap_or_default(),
65+
current.map(NonNullPtr::into_inner).unwrap_or_default(),
66+
new.map(NonNullPtr::into_inner).unwrap_or_default(),
4267
success,
4368
failure,
4469
)
4570
.map(drop)
46-
.map_err(NonNullPtr::from_u64)
71+
.map_err(NonNullPtr::from_inner)
4772
}
4873

74+
#[inline]
4975
fn load(&self, order: Ordering) -> Option<NonNullPtr<N>> {
50-
NonZeroU64::new(self.inner.load(order)).map(|inner| NonNullPtr {
76+
InnerNonZero::new(self.inner.load(order)).map(|inner| NonNullPtr {
5177
inner,
5278
_marker: PhantomData,
5379
})
5480
}
5581

82+
#[inline]
5683
fn store(&self, value: Option<NonNullPtr<N>>, order: Ordering) {
57-
self.inner.store(
58-
value.map(|pointer| pointer.into_u64()).unwrap_or_default(),
59-
order,
60-
)
84+
self.inner
85+
.store(value.map(NonNullPtr::into_inner).unwrap_or_default(), order)
6186
}
6287
}
6388

6489
pub struct NonNullPtr<N>
6590
where
6691
N: Node,
6792
{
68-
inner: NonZeroU64,
93+
inner: InnerNonZero,
6994
_marker: PhantomData<*mut N>,
7095
}
7196

@@ -84,65 +109,66 @@ impl<N> NonNullPtr<N>
84109
where
85110
N: Node,
86111
{
112+
#[inline]
87113
pub fn as_ptr(&self) -> *mut N {
88114
self.inner.get() as *mut N
89115
}
90116

117+
#[inline]
91118
pub fn from_static_mut_ref(ref_: &'static mut N) -> NonNullPtr<N> {
92119
let non_null = NonNull::from(ref_);
93120
Self::from_non_null(non_null)
94121
}
95122

96123
fn from_non_null(ptr: NonNull<N>) -> Self {
97-
let address = ptr.as_ptr() as u32;
124+
let address = ptr.as_ptr() as Address;
98125
let tag = initial_tag().get();
99126

100-
let value = (u64::from(tag) << 32) | u64::from(address);
127+
let value = (Inner::from(tag) << Address::BITS) | Inner::from(address);
101128

102129
Self {
103-
inner: unsafe { NonZeroU64::new_unchecked(value) },
130+
inner: unsafe { InnerNonZero::new_unchecked(value) },
104131
_marker: PhantomData,
105132
}
106133
}
107134

108-
fn from_u64(value: u64) -> Option<Self> {
109-
NonZeroU64::new(value).map(|inner| Self {
135+
#[inline]
136+
fn from_inner(value: Inner) -> Option<Self> {
137+
InnerNonZero::new(value).map(|inner| Self {
110138
inner,
111139
_marker: PhantomData,
112140
})
113141
}
114142

143+
#[inline]
115144
fn non_null(&self) -> NonNull<N> {
116-
unsafe { NonNull::new_unchecked(self.inner.get() as *mut N) }
145+
unsafe { NonNull::new_unchecked(self.as_ptr()) }
117146
}
118147

119-
fn tag(&self) -> NonZeroU32 {
120-
unsafe { NonZeroU32::new_unchecked((self.inner.get() >> 32) as u32) }
148+
#[inline]
149+
fn into_inner(self) -> Inner {
150+
self.inner.get()
121151
}
122152

123-
fn into_u64(self) -> u64 {
124-
self.inner.get()
153+
#[inline]
154+
fn tag(&self) -> Tag {
155+
unsafe { Tag::new_unchecked((self.inner.get() >> Address::BITS) as Address) }
125156
}
126157

127158
fn increase_tag(&mut self) {
128-
let address = self.as_ptr() as u32;
159+
let address = self.as_ptr() as Address;
129160

130-
let new_tag = self
131-
.tag()
132-
.get()
133-
.checked_add(1)
134-
.map(|val| unsafe { NonZeroU32::new_unchecked(val) })
135-
.unwrap_or_else(initial_tag)
136-
.get();
161+
let new_tag = self.tag().checked_add(1).unwrap_or_else(initial_tag).get();
137162

138-
let value = (u64::from(new_tag) << 32) | u64::from(address);
163+
let value = (Inner::from(new_tag) << Address::BITS) | Inner::from(address);
139164

140-
self.inner = unsafe { NonZeroU64::new_unchecked(value) };
165+
self.inner = unsafe { InnerNonZero::new_unchecked(value) };
141166
}
142167
}
143168

144-
fn initial_tag() -> NonZeroU32 {
145-
unsafe { NonZeroU32::new_unchecked(1) }
169+
#[inline]
170+
const fn initial_tag() -> Tag {
171+
Tag::MIN
146172
}
147173

148174
pub unsafe fn push<N>(stack: &Stack<N>, new_top: NonNullPtr<N>)

src/pool/treiber/llsc.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ impl<N> AtomicPtr<N>
1616
where
1717
N: Node,
1818
{
19+
#[inline]
1920
pub const fn null() -> Self {
2021
Self {
2122
inner: UnsafeCell::new(None),
@@ -34,10 +35,12 @@ impl<N> NonNullPtr<N>
3435
where
3536
N: Node,
3637
{
38+
#[inline]
3739
pub fn as_ptr(&self) -> *mut N {
3840
self.inner.as_ptr().cast()
3941
}
4042

43+
#[inline]
4144
pub fn from_static_mut_ref(ref_: &'static mut N) -> Self {
4245
Self {
4346
inner: NonNull::from(ref_),

0 commit comments

Comments
 (0)