Skip to content

Commit f76a8bd

Browse files
authored
Merge pull request #233 from japaric/x86-pool
Sync Pool support for (32-bit) x86
2 parents 1a7c8e8 + dffc125 commit f76a8bd

File tree

5 files changed

+58
-30
lines changed

5 files changed

+58
-30
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ jobs:
4141
matrix:
4242
target:
4343
- x86_64-unknown-linux-gnu
44+
- i686-unknown-linux-musl
4445
- riscv32imc-unknown-none-elf
45-
- x86_64-unknown-linux-gnu
4646
- armv7r-none-eabi
4747
- thumbv6m-none-eabi
4848
- thumbv7m-none-eabi
@@ -102,6 +102,7 @@ jobs:
102102
matrix:
103103
target:
104104
- x86_64-unknown-linux-gnu
105+
- i686-unknown-linux-musl
105106
toolchain:
106107
- stable
107108
- nightly

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ __trybuild = []
2626
mpmc_large = []
2727
defmt-impl = ["defmt"]
2828

29-
[target.x86_64-unknown-linux-gnu.dev-dependencies]
29+
[target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dev-dependencies]
3030
scoped_threadpool = "0.1.8"
3131

3232
[target.thumbv6m-none-eabi.dependencies]
@@ -58,4 +58,3 @@ optional = true
5858
[dev-dependencies.defmt]
5959
version = "0.2.1"
6060
features = ["unstable-test"]
61-

src/pool/cas.rs

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
66
use core::{
77
cell::UnsafeCell,
8-
convert::TryFrom,
98
marker::PhantomData,
10-
mem,
11-
num::NonZeroUsize,
9+
num::NonZeroU64,
1210
ptr::NonNull,
13-
sync::atomic::{AtomicUsize, Ordering},
11+
sync::atomic::{AtomicU64, Ordering},
1412
};
1513

1614
/// Unfortunate implementation detail required to use the
@@ -88,14 +86,16 @@ impl<T> Stack<T> {
8886
}
8987
}
9088

89+
#[cfg(target_arch = "x86_64")]
9190
fn anchor<T>() -> *mut T {
9291
static mut ANCHOR: u8 = 0;
93-
(unsafe { &mut ANCHOR } as *mut u8 as usize & !(mem::align_of::<T>() - 1)) as *mut T
92+
(unsafe { &mut ANCHOR } as *mut u8 as usize & !(core::mem::align_of::<T>() - 1)) as *mut T
9493
}
9594

96-
/// Anchored pointer. This is a (signed) 32-bit offset from `anchor` plus a 32-bit tag
95+
/// On x86_64, anchored pointer. This is a (signed) 32-bit offset from `anchor` plus a 32-bit tag
96+
/// On x86, this is a pointer plus a 32-bit tag
9797
pub struct Ptr<T> {
98-
inner: NonZeroUsize,
98+
inner: NonZeroU64,
9999
_marker: PhantomData<*mut T>,
100100
}
101101

@@ -108,27 +108,35 @@ impl<T> Clone for Ptr<T> {
108108
impl<T> Copy for Ptr<T> {}
109109

110110
impl<T> Ptr<T> {
111+
#[cfg(target_arch = "x86_64")]
111112
pub fn new(p: *mut T) -> Option<Self> {
113+
use core::convert::TryFrom;
114+
112115
i32::try_from((p as isize).wrapping_sub(anchor::<T>() as isize))
113116
.ok()
114117
.map(|offset| unsafe { Ptr::from_parts(0, offset) })
115118
}
116119

120+
#[cfg(target_arch = "x86")]
121+
pub fn new(p: *mut T) -> Option<Self> {
122+
Some(unsafe { Ptr::from_parts(0, p as i32) })
123+
}
124+
117125
unsafe fn from_parts(tag: u32, offset: i32) -> Self {
118126
Self {
119-
inner: NonZeroUsize::new_unchecked((tag as usize) << 32 | (offset as u32 as usize)),
127+
inner: NonZeroU64::new_unchecked((tag as u64) << 32 | (offset as u32 as u64)),
120128
_marker: PhantomData,
121129
}
122130
}
123131

124-
fn from_usize(p: usize) -> Option<Self> {
125-
NonZeroUsize::new(p).map(|inner| Self {
132+
fn from_u64(p: u64) -> Option<Self> {
133+
NonZeroU64::new(p).map(|inner| Self {
126134
inner,
127135
_marker: PhantomData,
128136
})
129137
}
130138

131-
fn into_usize(&self) -> usize {
139+
fn into_u64(&self) -> u64 {
132140
self.inner.get()
133141
}
134142

@@ -147,6 +155,7 @@ impl<T> Ptr<T> {
147155
self.inner.get() as i32
148156
}
149157

158+
#[cfg(target_arch = "x86_64")]
150159
fn as_raw(&self) -> NonNull<T> {
151160
unsafe {
152161
NonNull::new_unchecked(
@@ -155,6 +164,11 @@ impl<T> Ptr<T> {
155164
}
156165
}
157166

167+
#[cfg(target_arch = "x86")]
168+
fn as_raw(&self) -> NonNull<T> {
169+
unsafe { NonNull::new_unchecked(self.offset() as *mut T) }
170+
}
171+
158172
pub fn dangling() -> Self {
159173
unsafe { Self::from_parts(0, 1) }
160174
}
@@ -165,14 +179,14 @@ impl<T> Ptr<T> {
165179
}
166180

167181
struct Atomic<T> {
168-
inner: AtomicUsize,
182+
inner: AtomicU64,
169183
_marker: PhantomData<*mut T>,
170184
}
171185

172186
impl<T> Atomic<T> {
173187
const fn null() -> Self {
174188
Self {
175-
inner: AtomicUsize::new(0),
189+
inner: AtomicU64::new(0),
176190
_marker: PhantomData,
177191
}
178192
}
@@ -186,24 +200,24 @@ impl<T> Atomic<T> {
186200
) -> Result<(), Option<Ptr<T>>> {
187201
self.inner
188202
.compare_exchange_weak(
189-
current.map(|p| p.into_usize()).unwrap_or(0),
190-
new.map(|p| p.into_usize()).unwrap_or(0),
203+
current.map(|p| p.into_u64()).unwrap_or(0),
204+
new.map(|p| p.into_u64()).unwrap_or(0),
191205
succ,
192206
fail,
193207
)
194208
.map(drop)
195-
.map_err(Ptr::from_usize)
209+
.map_err(Ptr::from_u64)
196210
}
197211

198212
fn load(&self, ord: Ordering) -> Option<Ptr<T>> {
199-
NonZeroUsize::new(self.inner.load(ord)).map(|inner| Ptr {
213+
NonZeroU64::new(self.inner.load(ord)).map(|inner| Ptr {
200214
inner,
201215
_marker: PhantomData,
202216
})
203217
}
204218

205219
fn store(&self, val: Option<Ptr<T>>, ord: Ordering) {
206220
self.inner
207-
.store(val.map(|p| p.into_usize()).unwrap_or(0), ord)
221+
.store(val.map(|p| p.into_u64()).unwrap_or(0), ord)
208222
}
209223
}

src/pool/mod.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@
153153
//!
154154
//! # x86_64 support / limitations
155155
//!
156-
//! *NOTE* `Pool` is only `Sync` on `x86_64` if the Cargo feature "x86-sync-pool" is enabled
156+
//! *NOTE* `Pool` is only `Sync` on `x86_64` and `x86` (`i686`) if the Cargo feature "x86-sync-pool"
157+
//! is enabled
157158
//!
158159
//! x86_64 support is a gamble. Yes, a gamble. Do you feel lucky enough to use `Pool` on x86_64?
159160
//!
@@ -203,6 +204,10 @@
203204
//!
204205
//! ## x86_64 Limitations
205206
//!
207+
//! *NOTE* this limitation does not apply to `x86` (32-bit address space). If you run into this
208+
//! issue, on an x86_64 processor try running your code compiled for `x86`, e.g. `cargo run --target
209+
//! i686-unknown-linux-musl`
210+
//!
206211
//! Because stack nodes must be located within +- 2 GB of the hidden `ANCHOR` variable, which
207212
//! lives in the `.bss` section, `Pool` may not be able to manage static references created using
208213
//! `Box::leak` -- these heap allocated chunks of memory may live in a very different address space.
@@ -240,8 +245,11 @@ pub use stack::Node;
240245
use stack::{Ptr, Stack};
241246

242247
pub mod singleton;
243-
#[cfg_attr(target_arch = "x86_64", path = "cas.rs")]
244-
#[cfg_attr(not(target_arch = "x86_64"), path = "llsc.rs")]
248+
#[cfg_attr(any(target_arch = "x86_64", target_arch = "x86"), path = "cas.rs")]
249+
#[cfg_attr(
250+
not(any(target_arch = "x86_64", target_arch = "x86")),
251+
path = "llsc.rs"
252+
)]
245253
mod stack;
246254

247255
/// A lock-free memory pool
@@ -259,7 +267,10 @@ pub struct Pool<T> {
259267
armv7r,
260268
armv7m,
261269
armv8m_main,
262-
all(target_arch = "x86_64", feature = "x86-sync-pool"),
270+
all(
271+
any(target_arch = "x86_64", target_arch = "x86"),
272+
feature = "x86-sync-pool"
273+
),
263274
test
264275
))]
265276
unsafe impl<T> Sync for Pool<T> {}
@@ -355,15 +366,15 @@ impl<T> Pool<T> {
355366
let mut n = 0;
356367
while len >= sz {
357368
match () {
358-
#[cfg(target_arch = "x86_64")]
369+
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
359370
() => {
360371
if let Some(p) = Ptr::new(p as *mut _) {
361372
self.stack.push(p);
362373
n += 1;
363374
}
364375
}
365376

366-
#[cfg(not(target_arch = "x86_64"))]
377+
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
367378
() => {
368379
self.stack.push(unsafe { Ptr::new_unchecked(p as *mut _) });
369380
n += 1;
@@ -393,14 +404,14 @@ impl<T> Pool<T> {
393404
let cap = nodes.len();
394405
for p in nodes {
395406
match () {
396-
#[cfg(target_arch = "x86_64")]
407+
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
397408
() => {
398409
if let Some(p) = Ptr::new(p) {
399410
self.stack.push(p);
400411
}
401412
}
402413

403-
#[cfg(not(target_arch = "x86_64"))]
414+
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
404415
() => self.stack.push(core::ptr::NonNull::from(p)),
405416
}
406417
}

src/pool/singleton.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ use super::{Init, Node, Uninit};
1919
armv7r,
2020
armv7m,
2121
armv8m_main,
22-
all(target_arch = "x86_64", feature = "x86-sync-pool"),
22+
all(
23+
any(target_arch = "x86_64", target_arch = "x86"),
24+
feature = "x86-sync-pool"
25+
),
2326
test
2427
))]
2528
#[macro_export]

0 commit comments

Comments
 (0)