std/thread/
current.rs

1use super::{Thread, ThreadId};
2use crate::mem::ManuallyDrop;
3use crate::ptr;
4use crate::sys::thread_local::local_pointer;
5
6const NONE: *mut () = ptr::null_mut();
7const BUSY: *mut () = ptr::without_provenance_mut(1);
8const DESTROYED: *mut () = ptr::without_provenance_mut(2);
9
10local_pointer! {
11    static CURRENT;
12}
13
14/// Persistent storage for the thread ID.
15///
16/// We store the thread ID so that it never gets destroyed during the lifetime
17/// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s.
18pub(super) mod id {
19    use super::*;
20
21    cfg_if::cfg_if! {
22        if #[cfg(target_thread_local)] {
23            use crate::cell::Cell;
24
25            #[thread_local]
26            static ID: Cell<Option<ThreadId>> = Cell::new(None);
27
28            pub(super) const CHEAP: bool = true;
29
30            pub(crate) fn get() -> Option<ThreadId> {
31                ID.get()
32            }
33
34            pub(super) fn set(id: ThreadId) {
35                ID.set(Some(id))
36            }
37        } else if #[cfg(target_pointer_width = "16")] {
38            local_pointer! {
39                static ID0;
40                static ID16;
41                static ID32;
42                static ID48;
43            }
44
45            pub(super) const CHEAP: bool = false;
46
47            pub(crate) fn get() -> Option<ThreadId> {
48                let id0 = ID0.get().addr() as u64;
49                let id16 = ID16.get().addr() as u64;
50                let id32 = ID32.get().addr() as u64;
51                let id48 = ID48.get().addr() as u64;
52                ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0)
53            }
54
55            pub(super) fn set(id: ThreadId) {
56                let val = id.as_u64().get();
57                ID0.set(ptr::without_provenance_mut(val as usize));
58                ID16.set(ptr::without_provenance_mut((val >> 16) as usize));
59                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
60                ID48.set(ptr::without_provenance_mut((val >> 48) as usize));
61            }
62        } else if #[cfg(target_pointer_width = "32")] {
63            local_pointer! {
64                static ID0;
65                static ID32;
66            }
67
68            pub(super) const CHEAP: bool = false;
69
70            pub(crate) fn get() -> Option<ThreadId> {
71                let id0 = ID0.get().addr() as u64;
72                let id32 = ID32.get().addr() as u64;
73                ThreadId::from_u64((id32 << 32) + id0)
74            }
75
76            pub(super) fn set(id: ThreadId) {
77                let val = id.as_u64().get();
78                ID0.set(ptr::without_provenance_mut(val as usize));
79                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
80            }
81        } else {
82            local_pointer! {
83                static ID;
84            }
85
86            pub(super) const CHEAP: bool = true;
87
88            pub(crate) fn get() -> Option<ThreadId> {
89                let id = ID.get().addr() as u64;
90                ThreadId::from_u64(id)
91            }
92
93            pub(super) fn set(id: ThreadId) {
94                let val = id.as_u64().get();
95                ID.set(ptr::without_provenance_mut(val as usize));
96            }
97        }
98    }
99
100    #[inline]
101    pub(super) fn get_or_init() -> ThreadId {
102        get().unwrap_or_else(
103            #[cold]
104            || {
105                let id = ThreadId::new();
106                id::set(id);
107                id
108            },
109        )
110    }
111}
112
113/// Tries to set the thread handle for the current thread. Fails if a handle was
114/// already set or if the thread ID of `thread` would change an already-set ID.
115pub(super) fn set_current(thread: Thread) -> Result<(), Thread> {
116    if CURRENT.get() != NONE {
117        return Err(thread);
118    }
119
120    match id::get() {
121        Some(id) if id == thread.id() => {}
122        None => id::set(thread.id()),
123        _ => return Err(thread),
124    }
125
126    // Make sure that `crate::rt::thread_cleanup` will be run, which will
127    // call `drop_current`.
128    crate::sys::thread_local::guard::enable();
129    CURRENT.set(thread.into_raw().cast_mut());
130    Ok(())
131}
132
133/// Gets the id of the thread that invokes it.
134///
135/// This function will always succeed, will always return the same value for
136/// one thread and is guaranteed not to call the global allocator.
137#[inline]
138pub(crate) fn current_id() -> ThreadId {
139    // If accessing the persistent thread ID takes multiple TLS accesses, try
140    // to retrieve it from the current thread handle, which will only take one
141    // TLS access.
142    if !id::CHEAP {
143        if let Some(id) = try_with_current(|t| t.map(|t| t.id())) {
144            return id;
145        }
146    }
147
148    id::get_or_init()
149}
150
151/// Gets a reference to the handle of the thread that invokes it, if the handle
152/// has been initialized.
153pub(super) fn try_with_current<F, R>(f: F) -> R
154where
155    F: FnOnce(Option<&Thread>) -> R,
156{
157    let current = CURRENT.get();
158    if current > DESTROYED {
159        // SAFETY: `Arc` does not contain interior mutability, so it does not
160        // matter that the address of the handle might be different depending
161        // on where this is called.
162        unsafe {
163            let current = ManuallyDrop::new(Thread::from_raw(current));
164            f(Some(&current))
165        }
166    } else {
167        f(None)
168    }
169}
170
171/// Gets a handle to the thread that invokes it. If the handle stored in thread-
172/// local storage was already destroyed, this creates a new unnamed temporary
173/// handle to allow thread parking in nearly all situations.
174pub(crate) fn current_or_unnamed() -> Thread {
175    let current = CURRENT.get();
176    if current > DESTROYED {
177        unsafe {
178            let current = ManuallyDrop::new(Thread::from_raw(current));
179            (*current).clone()
180        }
181    } else if current == DESTROYED {
182        Thread::new(id::get_or_init(), None)
183    } else {
184        init_current(current)
185    }
186}
187
188/// Gets a handle to the thread that invokes it.
189///
190/// # Examples
191///
192/// Getting a handle to the current thread with `thread::current()`:
193///
194/// ```
195/// use std::thread;
196///
197/// let handler = thread::Builder::new()
198///     .name("named thread".into())
199///     .spawn(|| {
200///         let handle = thread::current();
201///         assert_eq!(handle.name(), Some("named thread"));
202///     })
203///     .unwrap();
204///
205/// handler.join().unwrap();
206/// ```
207#[must_use]
208#[stable(feature = "rust1", since = "1.0.0")]
209pub fn current() -> Thread {
210    let current = CURRENT.get();
211    if current > DESTROYED {
212        unsafe {
213            let current = ManuallyDrop::new(Thread::from_raw(current));
214            (*current).clone()
215        }
216    } else {
217        init_current(current)
218    }
219}
220
221#[cold]
222fn init_current(current: *mut ()) -> Thread {
223    if current == NONE {
224        CURRENT.set(BUSY);
225        // If the thread ID was initialized already, use it.
226        let id = id::get_or_init();
227        let thread = Thread::new(id, None);
228
229        // Make sure that `crate::rt::thread_cleanup` will be run, which will
230        // call `drop_current`.
231        crate::sys::thread_local::guard::enable();
232        CURRENT.set(thread.clone().into_raw().cast_mut());
233        thread
234    } else if current == BUSY {
235        // BUSY exists solely for this check, but as it is in the slow path, the
236        // extra TLS write above shouldn't matter. The alternative is nearly always
237        // a stack overflow.
238
239        // If you came across this message, contact the author of your allocator.
240        // If you are said author: A surprising amount of functions inside the
241        // standard library (e.g. `Mutex`, `thread_local!`, `File` when using long
242        // paths, even `panic!` when using unwinding), need memory allocation, so
243        // you'll get circular dependencies all over the place when using them.
244        // I (joboet) highly recommend using only APIs from core in your allocator
245        // and implementing your own system abstractions. Still, if you feel that
246        // a particular API should be entirely allocation-free, feel free to open
247        // an issue on the Rust repository, we'll see what we can do.
248        rtabort!(
249            "\n\
250            Attempted to access thread-local data while allocating said data.\n\
251            Do not access functions that allocate in the global allocator!\n\
252            This is a bug in the global allocator.\n\
253            "
254        )
255    } else {
256        debug_assert_eq!(current, DESTROYED);
257        panic!(
258            "use of std::thread::current() is not possible after the thread's \
259            local data has been destroyed"
260        )
261    }
262}
263
264/// This should be run in [`crate::rt::thread_cleanup`] to reset the thread
265/// handle.
266pub(crate) fn drop_current() {
267    let current = CURRENT.get();
268    if current > DESTROYED {
269        unsafe {
270            CURRENT.set(DESTROYED);
271            drop(Thread::from_raw(current));
272        }
273    }
274}