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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
//! 基于操作系统的线程本地存储
//!
//! 该模块提供了一个基于操作系统的线程本地存储的实现,使用了本地操作系统提供的工具 (想想 `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)] // sys 尚未导出

#[cfg(test)]
mod tests;

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

/// 静态分配的 TLS 密钥的类型。
///
/// 使用此类型是完全 `unsafe` 的,因为它不能防止在释放后使用或释放​​期间使用。
///
///
/// 第一次使用时会延迟分配实际的 OS-TLS 密钥。
/// 当 Rust 运行时退出或调用 `destroy` (以先到者为准) 时,也将释放该键。
///
/// # Examples
///
/// ```ignore (cannot-doctest-private-modules)
/// use tls::os::{StaticKey, INIT};
///
/// static KEY: StaticKey = INIT;
///
/// 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)>,
}

/// 一种安全管理的基于 OS 的 TLS 插槽的类型。
///
/// 初始化时,此类型分配 OS TLS 密钥; 当它离开离开作用域时,将释放该密钥。
/// 与 `StaticKey` 相比,此类型完全可以安全使用。
///
/// 但是,实现可能会包含不安全的代码,因为此类型仅在 `*mut u8` (裸指针) 上运行。
///
///
/// # Examples
///
/// ```ignore (cannot-doctest-private-modules)
/// use tls::os::Key;
///
/// let key = Key::new(None);
/// assert!(key.get().is_null());
/// key.set(1 as *mut u8);
/// assert!(!key.get().is_null());
///
/// drop(key); // 释放此 TLS 插槽。
/// ```
///
pub struct Key {
    key: imp::Key,
}

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

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(0), 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) {
            0 => self.lazy_init() as imp::Key,
            n => n as imp::Key,
        }
    }

    unsafe fn lazy_init(&self) -> usize {
        // 当前,TLS 的 Windows 实现非常繁琐,如果我们仅同步所有内容,它将大大简化创建过程。
        //
        //
        // 此外,在 windows 上还没有看到 tls 键的 0 索引,因此我们只是简化了整个分支。
        //
        if imp::requires_synchronized_create() {
            // 我们从不调用 `INIT_LOCK.init()`,因此尝试重新获得此互斥锁是 UB!
            //
            static INIT_LOCK: StaticMutex = StaticMutex::new();
            let _guard = INIT_LOCK.lock();
            let mut key = self.key.load(Ordering::SeqCst);
            if key == 0 {
                key = imp::create(self.dtor) as usize;
                self.key.store(key, Ordering::SeqCst);
            }
            rtassert!(key != 0);
            return key;
        }

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

impl Key {
    /// 创建一个新的托管 OS TLS 密钥。
    ///
    /// 当秘钥离开作用域时,该键将被释放。
    ///
    /// 提供的参数是此 TLS 密钥的值的可选指定的析构函数。
    /// 当线程退出并且此键的值不为 null 时,将调用析构函数。
    /// 在调用析构函数之前,TLS 值将重置为 null。
    ///
    /// 请注意,当 `Key` 离开作用域时,析构函数将不会运行。
    ///
    ///
    #[inline]
    pub fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
        Key { key: unsafe { imp::create(dtor) } }
    }

    /// 请参见 StaticKey::get
    #[inline]
    pub fn get(&self) -> *mut u8 {
        unsafe { imp::get(self.key) }
    }

    /// 请参见 StaticKey::set
    #[inline]
    pub fn set(&self, val: *mut u8) {
        unsafe { imp::set(self.key, val) }
    }
}

impl Drop for Key {
    fn drop(&mut self) {
        // 目前,Windows 不支持 TLS 密钥销毁,但是除了测试以外,其他任何地方都没有使用它,因此只需泄漏 TLS 密钥即可。
        //
        // unsafe { imp::destroy(self.key) }
    }
}