1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! 基于操作系统的线程本地存储
//!
//! 该模块提供了一个基于操作系统的线程本地存储的实现,使用了本地操作系统提供的工具 (想想 `TlsAlloc` 或 `pthread_setspecific`)。
//! 它的接口与此 crate 中提供的其他类型的线程本地存储不同,因为基于操作系统的 TLS 只能获取/设置指针大小的数据,可能带有关联的析构函数。
//!
//!
//! 该模块还提供了两种 TLS。其中一个用于静态初始化,不包含用于释放 OS-TLS 密钥的 `Drop` 实现。
//! 另一个是实现了 `Drop` 的类型,因此有一个安全的接口。
//!
//! # Usage
//!
//! 除非在其他原语的基础上构建,否则不应该直接使用此模块。
//! 像 `thread_local::spawn::Key` 这样的类型在实践中可能比此基于 OS 的版本有用得多,后者可能需要不安全的代码才能进行互操作。
//!
//! # Examples
//!
//! 使用动态分配的 TLS 密钥。请注意,这个键可以通过 `Arc` 在多个线程中共享。
//!
//! ```ignore (cannot-doctest-private-modules)
//! let key = Key::new(None);
//! assert!(key.get().is_null());
//! key.set(1 as *mut u8);
//! assert!(!key.get().is_null());
//!
//! drop(key); // 释放此 TLS 插槽。
//! ```
//!
//! 有时,静态分配的密钥是必需的,或者更易于使用。
//!
//! ```ignore (cannot-doctest-private-modules)
//! static KEY: StaticKey = INIT;
//!
//! unsafe {
//!     assert!(KEY.get().is_null());
//!     KEY.set(1 as *mut u8);
//! }
//! ```
//!
//!
//!
//!
//!
//!
//!
//!

#![allow(non_camel_case_types)]
#![unstable(feature = "thread_local_internals", issue = "none")]
#![allow(dead_code)]

#[cfg(test)]
mod tests;

use crate::sync::atomic::{self, AtomicUsize, Ordering};
use crate::sys::thread_local_key as imp;

/// 静态分配的 TLS 密钥的类型。
///
/// 使用此类型是完全 `unsafe` 的,因为它不能防止在释放后使用或释放​​期间使用。
///
///
/// 第一次使用时会延迟分配实际的 OS-TLS 密钥。
/// 当 Rust 运行时退出或调用 `destroy` (以先到者为准) 时,也将释放该键。
///
/// # Examples
///
/// ```ignore (cannot-doctest-private-modules)
/// use tls::os::{StaticKey, INIT};
///
/// // 使用常规静态存储密钥。
/// static KEY: StaticKey = INIT;
///
/// // 通过 `get` 和 `set` 提供的状态是线程本地的。
/// unsafe {
///     assert!(KEY.get().is_null());
///     KEY.set(1 as *mut u8);
/// }
/// ```
///
pub struct StaticKey {
    /// 内部静态 TLS 密钥 (internals)。
    key: AtomicUsize,
    /// TLS 值的析构函数。
    ///
    /// 有关析构函数何时运行以及运行方式的信息,请参见 `Key::new`。
    ///
    dtor: Option<unsafe extern "C" fn(*mut u8)>,
}

/// 静态 TLS 密钥的常量初始化值。
///
/// 默认情况下,此值不指定析构函数。
pub const INIT: StaticKey = StaticKey::new(None);

// 定义一个可能不会作为 TLS 密钥返回的标记值。
//
#[cfg(not(target_os = "nto"))]
const KEY_SENTVAL: usize = 0;
// 在 QNX Neutrino 上,当前未使用时始终返回 0。
// 使用 0 意味着总是创建两个键并在之后立即远程第一个 (值为 0)。
//
#[cfg(target_os = "nto")]
const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1;

impl StaticKey {
    #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
    pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
        StaticKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
    }

    /// 获取与此 TLS 密钥关联的值
    ///
    /// 如果尚未分配 TLS 密钥,则会从操作系统延迟分配 TLS 密钥。
    ///
    #[inline]
    pub unsafe fn get(&self) -> *mut u8 {
        imp::get(self.key())
    }

    /// 将此 TLS 密钥设置为新值。
    ///
    /// 如果尚未分配 TLS 密钥,则会从操作系统延迟分配 TLS 密钥。
    ///
    #[inline]
    pub unsafe fn set(&self, val: *mut u8) {
        imp::set(self.key(), val)
    }

    #[inline]
    unsafe fn key(&self) -> imp::Key {
        match self.key.load(Ordering::Relaxed) {
            KEY_SENTVAL => self.lazy_init() as imp::Key,
            n => n as imp::Key,
        }
    }

    unsafe fn lazy_init(&self) -> usize {
        // POSIX 允许此处创建的密钥为 KEY_SENTVAL,但下面的 compare_exchange 依赖于使用 KEY_SENTVAL 作为标记值来检查谁赢得了设置共享 TLS 密钥的竞赛。
        // 据我所知,没有保证值不能作为 posix_key_create 键返回,因此没有值可以初始化内部键以证明尚未设置。
        //
        // 因此,我们将继续使用 KEY_SENTVAL 的值,但会进行一些调整以确保我们从创建例程中返回一个非 KEY_SENTVAL 值。
        // FIXME: 这显然是一个 hack,应该对其进行清理。
        //
        //
        //
        //
        let key1 = imp::create(self.dtor);
        let key = if key1 as usize != KEY_SENTVAL {
            key1
        } else {
            let key2 = imp::create(self.dtor);
            imp::destroy(key1);
            key2
        };
        rtassert!(key as usize != KEY_SENTVAL);
        match self.key.compare_exchange(
            KEY_SENTVAL,
            key as usize,
            Ordering::SeqCst,
            Ordering::SeqCst,
        ) {
            // CAS 成功了,所以我们创建了实际的密钥
            Ok(_) => key as usize,
            // 如果有人超过了我们,请改用他们的秘钥
            Err(n) => {
                imp::destroy(key);
                n
            }
        }
    }
}