Skip to content

Commit

Permalink
Tolerate the standard library reusing ThreadIds
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Dec 15, 2021
1 parent e23e46a commit 964cd08
Showing 1 changed file with 28 additions and 3 deletions.
31 changes: 28 additions & 3 deletions src/thread.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt::{self, Debug};
use std::thread::{self, ThreadId};
use std::num::NonZeroUsize;
use std::sync::atomic::{AtomicUsize, Ordering};

/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value
/// of type T only from the original thread on which the ThreadBound was
Expand All @@ -18,12 +19,12 @@ impl<T> ThreadBound<T> {
pub fn new(value: T) -> Self {
ThreadBound {
value,
thread_id: thread::current().id(),
thread_id: ThreadId::current(),
}
}

pub fn get(&self) -> Option<&T> {
if thread::current().id() == self.thread_id {
if ThreadId::current() == self.thread_id {
Some(&self.value)
} else {
None
Expand All @@ -39,3 +40,27 @@ impl<T: Debug> Debug for ThreadBound<T> {
}
}
}

#[derive(Copy, Clone, PartialEq)]
struct ThreadId(NonZeroUsize);

impl ThreadId {
fn current() -> Self {
static NEXT_THREAD_ID: AtomicUsize = AtomicUsize::new(1);

thread_local! {
static THIS_THREAD_ID: ThreadId = {
let mut current = NEXT_THREAD_ID.load(Ordering::Relaxed);
loop {
let next = current.checked_add(1).expect("ThreadId overflow");
match NEXT_THREAD_ID.compare_exchange_weak(current, next, Ordering::Relaxed, Ordering::Relaxed) {
Ok(current) => break ThreadId(unsafe { NonZeroUsize::new_unchecked(current) }),
Err(update) => current = update,
}
}
};
}

THIS_THREAD_ID.with(ThreadId::clone)
}
}

0 comments on commit 964cd08

Please sign in to comment.