Skip to content

Commit cb6f0de

Browse files
authored
Merge pull request #66 from saethlin/master
Avoid lossy ptr-int transmutes by using AtomicPtr
2 parents 30e562c + b0e5867 commit cb6f0de

File tree

2 files changed

+33
-26
lines changed

2 files changed

+33
-26
lines changed

src/native/arc_list.rs

+19-12
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
use std::marker;
44
use std::ops::Deref;
55
use std::sync::atomic::Ordering::SeqCst;
6-
use std::sync::atomic::{AtomicBool, AtomicUsize};
6+
use std::sync::atomic::{AtomicBool, AtomicPtr};
77
use std::sync::Arc;
88

99
pub struct ArcList<T> {
10-
list: AtomicUsize,
10+
list: AtomicPtr<Node<T>>,
1111
_marker: marker::PhantomData<T>,
1212
}
1313

1414
impl<T> ArcList<T> {
1515
pub fn new() -> ArcList<T> {
1616
ArcList {
17-
list: AtomicUsize::new(0),
17+
list: AtomicPtr::new(Node::EMPTY),
1818
_marker: marker::PhantomData,
1919
}
2020
}
@@ -31,10 +31,10 @@ impl<T> ArcList<T> {
3131
return Ok(());
3232
}
3333
let mut head = self.list.load(SeqCst);
34-
let node = Arc::into_raw(data.clone()) as usize;
34+
let node = Arc::into_raw(data.clone()) as *mut Node<T>;
3535
loop {
3636
// If we've been sealed off, abort and return an error
37-
if head == 1 {
37+
if head == Node::SEALED {
3838
unsafe {
3939
drop(Arc::from_raw(node as *mut Node<T>));
4040
}
@@ -55,16 +55,19 @@ impl<T> ArcList<T> {
5555
pub fn take(&self) -> ArcList<T> {
5656
let mut list = self.list.load(SeqCst);
5757
loop {
58-
if list == 1 {
58+
if list == Node::SEALED {
5959
break;
6060
}
61-
match self.list.compare_exchange(list, 0, SeqCst, SeqCst) {
61+
match self
62+
.list
63+
.compare_exchange(list, Node::EMPTY, SeqCst, SeqCst)
64+
{
6265
Ok(_) => break,
6366
Err(l) => list = l,
6467
}
6568
}
6669
ArcList {
67-
list: AtomicUsize::new(list),
70+
list: AtomicPtr::new(list),
6871
_marker: marker::PhantomData,
6972
}
7073
}
@@ -73,7 +76,7 @@ impl<T> ArcList<T> {
7376
/// `push`.
7477
pub fn take_and_seal(&self) -> ArcList<T> {
7578
ArcList {
76-
list: AtomicUsize::new(self.list.swap(1, SeqCst)),
79+
list: AtomicPtr::new(self.list.swap(Node::SEALED, SeqCst)),
7780
_marker: marker::PhantomData,
7881
}
7982
}
@@ -82,7 +85,7 @@ impl<T> ArcList<T> {
8285
/// empty list.
8386
pub fn pop(&mut self) -> Option<Arc<Node<T>>> {
8487
let head = *self.list.get_mut();
85-
if head == 0 || head == 1 {
88+
if head == Node::EMPTY || head == Node::SEALED {
8689
return None;
8790
}
8891
let head = unsafe { Arc::from_raw(head as *const Node<T>) };
@@ -103,15 +106,19 @@ impl<T> Drop for ArcList<T> {
103106
}
104107

105108
pub struct Node<T> {
106-
next: AtomicUsize,
109+
next: AtomicPtr<Node<T>>,
107110
enqueued: AtomicBool,
108111
data: T,
109112
}
110113

111114
impl<T> Node<T> {
115+
const EMPTY: *mut Node<T> = std::ptr::null_mut();
116+
117+
const SEALED: *mut Node<T> = std::ptr::null_mut::<Node<T>>().wrapping_add(1);
118+
112119
pub fn new(data: T) -> Node<T> {
113120
Node {
114-
next: AtomicUsize::new(0),
121+
next: AtomicPtr::new(Node::EMPTY),
115122
enqueued: AtomicBool::new(false),
116123
data,
117124
}

src/native/timer.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use std::fmt;
2-
use std::mem;
32
use std::pin::Pin;
4-
use std::sync::atomic::AtomicUsize;
53
use std::sync::atomic::Ordering::SeqCst;
4+
use std::sync::atomic::{AtomicPtr, AtomicUsize};
65
use std::sync::{Arc, Mutex, Weak};
76
use std::task::{Context, Poll};
87
use std::time::Instant;
@@ -216,7 +215,8 @@ impl Default for Timer {
216215
}
217216
}
218217

219-
static HANDLE_FALLBACK: AtomicUsize = AtomicUsize::new(0);
218+
static HANDLE_FALLBACK: AtomicPtr<Inner> = AtomicPtr::new(EMPTY_HANDLE);
219+
const EMPTY_HANDLE: *mut Inner = std::ptr::null_mut();
220220

221221
/// Error returned from `TimerHandle::set_fallback`.
222222
#[derive(Clone, Debug)]
@@ -247,23 +247,23 @@ impl TimerHandle {
247247
/// successful then no future calls may succeed.
248248
fn set_as_global_fallback(self) -> Result<(), SetDefaultError> {
249249
unsafe {
250-
let val = self.into_usize();
251-
match HANDLE_FALLBACK.compare_exchange(0, val, SeqCst, SeqCst) {
250+
let val = self.into_raw();
251+
match HANDLE_FALLBACK.compare_exchange(EMPTY_HANDLE, val, SeqCst, SeqCst) {
252252
Ok(_) => Ok(()),
253253
Err(_) => {
254-
drop(TimerHandle::from_usize(val));
254+
drop(TimerHandle::from_raw(val));
255255
Err(SetDefaultError(()))
256256
}
257257
}
258258
}
259259
}
260260

261-
fn into_usize(self) -> usize {
262-
unsafe { mem::transmute::<Weak<Inner>, usize>(self.inner) }
261+
fn into_raw(self) -> *mut Inner {
262+
self.inner.into_raw() as *mut Inner
263263
}
264264

265-
unsafe fn from_usize(val: usize) -> TimerHandle {
266-
let inner = mem::transmute::<usize, Weak<Inner>>(val);
265+
unsafe fn from_raw(val: *mut Inner) -> TimerHandle {
266+
let inner = Weak::from_raw(val);
267267
TimerHandle { inner }
268268
}
269269
}
@@ -277,7 +277,7 @@ impl Default for TimerHandle {
277277
// actually create a helper thread then we'll just return a "defunkt"
278278
// handle which will return errors when timer objects are attempted to
279279
// be associated.
280-
if fallback == 0 {
280+
if fallback == EMPTY_HANDLE {
281281
let helper = match global::HelperThread::new() {
282282
Ok(helper) => helper,
283283
Err(_) => return TimerHandle { inner: Weak::new() },
@@ -301,11 +301,11 @@ impl Default for TimerHandle {
301301
// At this point our fallback handle global was configured so we use
302302
// its value to reify a handle, clone it, and then forget our reified
303303
// handle as we don't actually have an owning reference to it.
304-
assert!(fallback != 0);
304+
assert!(fallback != EMPTY_HANDLE);
305305
unsafe {
306-
let handle = TimerHandle::from_usize(fallback);
306+
let handle = TimerHandle::from_raw(fallback);
307307
let ret = handle.clone();
308-
let _ = handle.into_usize();
308+
let _ = handle.into_raw();
309309
ret
310310
}
311311
}

0 commit comments

Comments
 (0)