Coverage Report

Created: 2025-02-25 06:39

/rust/registry/src/index.crates.io-6f17d22bba15001f/sharded-slab-0.1.7/src/tid.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::{
2
    cfg::{self, CfgPrivate},
3
    page,
4
    sync::{
5
        atomic::{AtomicUsize, Ordering},
6
        lazy_static, thread_local, Mutex,
7
    },
8
    Pack,
9
};
10
use std::{
11
    cell::{Cell, UnsafeCell},
12
    collections::VecDeque,
13
    fmt,
14
    marker::PhantomData,
15
};
16
17
/// Uniquely identifies a thread.
18
pub(crate) struct Tid<C> {
19
    id: usize,
20
    _not_send: PhantomData<UnsafeCell<()>>,
21
    _cfg: PhantomData<fn(C)>,
22
}
23
24
#[derive(Debug)]
25
struct Registration(Cell<Option<usize>>);
26
27
struct Registry {
28
    next: AtomicUsize,
29
    free: Mutex<VecDeque<usize>>,
30
}
31
32
lazy_static! {
33
    static ref REGISTRY: Registry = Registry {
34
        next: AtomicUsize::new(0),
35
        free: Mutex::new(VecDeque::new()),
36
    };
37
}
38
39
thread_local! {
40
    static REGISTRATION: Registration = Registration::new();
41
}
42
43
// === impl Tid ===
44
45
impl<C: cfg::Config> Pack<C> for Tid<C> {
46
    const LEN: usize = C::MAX_SHARDS.trailing_zeros() as usize + 1;
47
48
    type Prev = page::Addr<C>;
49
50
    #[inline(always)]
51
0
    fn as_usize(&self) -> usize {
52
0
        self.id
53
0
    }
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig> as sharded_slab::Pack<sharded_slab::cfg::DefaultConfig>>::as_usize
Unexecuted instantiation: <sharded_slab::tid::Tid<_> as sharded_slab::Pack<_>>::as_usize
54
55
    #[inline(always)]
56
0
    fn from_usize(id: usize) -> Self {
57
0
        Self {
58
0
            id,
59
0
            _not_send: PhantomData,
60
0
            _cfg: PhantomData,
61
0
        }
62
0
    }
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig> as sharded_slab::Pack<sharded_slab::cfg::DefaultConfig>>::from_usize
Unexecuted instantiation: <sharded_slab::tid::Tid<_> as sharded_slab::Pack<_>>::from_usize
63
}
64
65
impl<C: cfg::Config> Tid<C> {
66
    #[inline]
67
0
    pub(crate) fn current() -> Self {
68
0
        REGISTRATION
69
0
            .try_with(Registration::current)
70
0
            .unwrap_or_else(|_| Self::poisoned())
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig>>::current::{closure#0}
Unexecuted instantiation: <sharded_slab::tid::Tid<_>>::current::{closure#0}
71
0
    }
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig>>::current
Unexecuted instantiation: <sharded_slab::tid::Tid<_>>::current
72
73
0
    pub(crate) fn is_current(self) -> bool {
74
0
        REGISTRATION
75
0
            .try_with(|r| self == r.current::<C>())
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig>>::is_current::{closure#0}
Unexecuted instantiation: <sharded_slab::tid::Tid<_>>::is_current::{closure#0}
76
0
            .unwrap_or(false)
77
0
    }
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig>>::is_current
Unexecuted instantiation: <sharded_slab::tid::Tid<_>>::is_current
78
79
    #[inline(always)]
80
0
    pub fn new(id: usize) -> Self {
81
0
        Self::from_usize(id)
82
0
    }
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig>>::new
Unexecuted instantiation: <sharded_slab::tid::Tid<_>>::new
83
}
84
85
impl<C> Tid<C> {
86
    #[cold]
87
0
    fn poisoned() -> Self {
88
0
        Self {
89
0
            id: std::usize::MAX,
90
0
            _not_send: PhantomData,
91
0
            _cfg: PhantomData,
92
0
        }
93
0
    }
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig>>::poisoned
Unexecuted instantiation: <sharded_slab::tid::Tid<_>>::poisoned
94
95
    /// Returns true if the local thread ID was accessed while unwinding.
96
0
    pub(crate) fn is_poisoned(&self) -> bool {
97
0
        self.id == std::usize::MAX
98
0
    }
99
}
100
101
impl<C> fmt::Debug for Tid<C> {
102
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103
0
        if self.is_poisoned() {
104
0
            f.debug_tuple("Tid")
105
0
                .field(&format_args!("<poisoned>"))
106
0
                .finish()
107
        } else {
108
0
            f.debug_tuple("Tid")
109
0
                .field(&format_args!("{}", self.id))
110
0
                .finish()
111
        }
112
0
    }
113
}
114
115
impl<C> PartialEq for Tid<C> {
116
0
    fn eq(&self, other: &Self) -> bool {
117
0
        self.id == other.id
118
0
    }
Unexecuted instantiation: <sharded_slab::tid::Tid<sharded_slab::cfg::DefaultConfig> as core::cmp::PartialEq>::eq
Unexecuted instantiation: <sharded_slab::tid::Tid<_> as core::cmp::PartialEq>::eq
119
}
120
121
impl<C> Eq for Tid<C> {}
122
123
impl<C: cfg::Config> Clone for Tid<C> {
124
0
    fn clone(&self) -> Self {
125
0
        *self
126
0
    }
127
}
128
129
impl<C: cfg::Config> Copy for Tid<C> {}
130
131
// === impl Registration ===
132
133
impl Registration {
134
0
    fn new() -> Self {
135
0
        Self(Cell::new(None))
136
0
    }
137
138
    #[inline(always)]
139
0
    fn current<C: cfg::Config>(&self) -> Tid<C> {
140
0
        if let Some(tid) = self.0.get().map(Tid::new) {
141
0
            return tid;
142
0
        }
143
0
144
0
        self.register()
145
0
    }
Unexecuted instantiation: <sharded_slab::tid::Registration>::current::<sharded_slab::cfg::DefaultConfig>
Unexecuted instantiation: <sharded_slab::tid::Registration>::current::<_>
146
147
    #[cold]
148
0
    fn register<C: cfg::Config>(&self) -> Tid<C> {
149
0
        let id = REGISTRY
150
0
            .free
151
0
            .lock()
152
0
            .ok()
153
0
            .and_then(|mut free| {
154
0
                if free.len() > 1 {
155
0
                    free.pop_front()
156
                } else {
157
0
                    None
158
                }
159
0
            })
Unexecuted instantiation: <sharded_slab::tid::Registration>::register::<sharded_slab::cfg::DefaultConfig>::{closure#0}
Unexecuted instantiation: <sharded_slab::tid::Registration>::register::<_>::{closure#0}
160
0
            .unwrap_or_else(|| {
161
0
                let id = REGISTRY.next.fetch_add(1, Ordering::AcqRel);
162
0
                if id > Tid::<C>::BITS {
163
0
                    panic_in_drop!(
164
0
                        "creating a new thread ID ({}) would exceed the \
165
0
                        maximum number of thread ID bits specified in {} \
166
0
                        ({})",
167
0
                        id,
168
0
                        std::any::type_name::<C>(),
169
                        Tid::<C>::BITS,
170
                    );
171
0
                }
172
0
                id
173
0
            });
Unexecuted instantiation: <sharded_slab::tid::Registration>::register::<sharded_slab::cfg::DefaultConfig>::{closure#1}
Unexecuted instantiation: <sharded_slab::tid::Registration>::register::<_>::{closure#1}
174
0
175
0
        self.0.set(Some(id));
176
0
        Tid::new(id)
177
0
    }
Unexecuted instantiation: <sharded_slab::tid::Registration>::register::<sharded_slab::cfg::DefaultConfig>
Unexecuted instantiation: <sharded_slab::tid::Registration>::register::<_>
178
}
179
180
// Reusing thread IDs doesn't work under loom, since this `Drop` impl results in
181
// an access to a `loom` lazy_static while the test is shutting down, which
182
// panics. T_T
183
// Just skip TID reuse and use loom's lazy_static macro to ensure we have a
184
// clean initial TID on every iteration, instead.
185
#[cfg(not(all(loom, any(feature = "loom", test))))]
186
impl Drop for Registration {
187
0
    fn drop(&mut self) {
188
        use std::sync::PoisonError;
189
190
0
        if let Some(id) = self.0.get() {
191
0
            let mut free_list = REGISTRY.free.lock().unwrap_or_else(PoisonError::into_inner);
192
0
            free_list.push_back(id);
193
0
        }
194
0
    }
195
}
196
197
#[cfg(all(test, not(loom)))]
198
pub(crate) fn with<R>(tid: usize, f: impl FnOnce() -> R) -> R {
199
    struct Guard(Option<usize>);
200
201
    impl Drop for Guard {
202
        fn drop(&mut self) {
203
            REGISTRATION.with(|r| r.0.set(self.0.take()));
204
        }
205
    }
206
207
    let prev = REGISTRATION.with(|r| r.0.replace(Some(tid)));
208
    let _guard = Guard(prev);
209
    f()
210
}