thread_id/
lib.rs

1// Thread-ID -- Get a unique thread ID
2// Copyright 2016 Ruud van Asseldonk
3//
4// Licensed under either the Apache License, Version 2.0, or the MIT license, at
5// your option. A copy of both licenses has been included in the root of the
6// repository.
7
8//! Thread-ID: get a unique ID for the current thread.
9//!
10//! For diagnostics and debugging it can often be useful to get an ID that is
11//! different for every thread. This crate provides that functionality.
12//!
13//! # Example
14//!
15//! ```
16//! use std::thread;
17//! use thread_id;
18//!
19//! let handle = thread::spawn(move || {
20//!     println!("spawned thread has id {}", thread_id::get());
21//! });
22//!
23//! println!("main thread has id {}", thread_id::get());
24//!
25//! handle.join().unwrap();
26//! ```
27
28#![warn(missing_docs)]
29
30#[cfg(unix)]
31extern crate libc;
32
33#[cfg(windows)]
34extern crate windows_sys;
35
36/// Returns a number that is unique to the calling thread.
37///
38/// Calling this function twice from the same thread will return the same
39/// number. Calling this function from a different thread will return a
40/// different number.
41#[inline]
42pub fn get() -> usize {
43    get_internal()
44}
45
46#[cfg(all(
47    unix,
48    not(any(
49        target_os = "macos",
50        target_os = "ios",
51        target_os = "tvos",
52        target_os = "watchos"
53    ))
54))]
55#[inline]
56fn get_internal() -> usize {
57    unsafe { libc::pthread_self() as usize }
58}
59
60#[cfg(all(
61    unix,
62    any(
63        target_os = "macos",
64        target_os = "ios",
65        target_os = "tvos",
66        target_os = "watchos"
67    )
68))]
69#[inline]
70fn get_internal() -> usize {
71    let mut tid: u64 = 0;
72    unsafe {
73        libc::pthread_threadid_np(libc::pthread_self(), &mut tid as *mut u64);
74    };
75    tid as usize
76}
77
78#[cfg(windows)]
79#[inline]
80fn get_internal() -> usize {
81    unsafe { windows_sys::Win32::System::Threading::GetCurrentThreadId() as usize }
82}
83
84#[cfg(all(
85    target_arch = "wasm32",
86    target_vendor = "unknown",
87    target_os = "unknown",
88    not(target_feature = "atomics"),
89))]
90#[inline]
91fn get_internal() -> usize {
92    0
93}
94
95#[cfg(any(
96    target_env = "sgx",
97    all(
98        target_arch = "wasm32",
99        target_vendor = "unknown",
100        target_os = "unknown",
101        target_feature = "atomics",
102    )
103))]
104#[inline]
105fn get_internal() -> usize {
106    use std::sync::atomic::{AtomicUsize, Ordering};
107
108    static COUNTER: AtomicUsize = AtomicUsize::new(0);
109
110    thread_local! {
111        static ID: usize = COUNTER.fetch_add(1, Ordering::Relaxed);
112    }
113
114    ID.with(|id| *id)
115}
116
117#[test]
118fn distinct_threads_have_distinct_ids() {
119    use std::sync::mpsc;
120    use std::thread;
121
122    let (tx, rx) = mpsc::channel();
123    thread::spawn(move || tx.send(crate::get()).unwrap()).join().unwrap();
124
125    let main_tid = crate::get();
126    let other_tid = rx.recv().unwrap();
127    assert!(main_tid != other_tid);
128}