relibc/header/pthread/
tls.rs1#![warn(warnings, unused_variables)]
4
5use super::*;
6
7use alloc::{collections::BTreeMap, vec::Vec};
9
10use core::{
11 cell::RefCell,
12 ptr,
13 sync::atomic::{AtomicUsize, Ordering},
14};
15
16use crate::{
17 header::{errno::EINVAL, limits::PTHREAD_DESTRUCTOR_ITERATIONS},
18 sync::Mutex,
19};
20
21type Dtor = Option<extern "C" fn(value: *mut c_void)>;
22
23struct Record {
24 data: *mut c_void,
25}
26
27#[thread_local]
28static VALUES: RefCell<BTreeMap<pthread_key_t, Record>> = RefCell::new(BTreeMap::new());
29static KEYS: Mutex<BTreeMap<pthread_key_t, Dtor>> = Mutex::new(BTreeMap::new());
30static NEXTKEY: AtomicUsize = AtomicUsize::new(1);
31
32#[unsafe(no_mangle)]
34pub unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
35 debug_assert!(KEYS.lock().contains_key(&key));
41 VALUES
42 .borrow_mut()
43 .get(&key)
44 .map(|record| record.data)
45 .unwrap_or(ptr::null_mut())
46}
47
48#[unsafe(no_mangle)]
50pub unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int {
51 if !KEYS.lock().contains_key(&key) {
52 return EINVAL;
55 }
56
57 let mut guard = VALUES.borrow_mut();
58
59 let record = guard.entry(key).or_insert(Record {
60 data: core::ptr::null_mut(),
61 });
62 record.data = value.cast_mut();
65 0
66}
67
68#[unsafe(no_mangle)]
70pub unsafe extern "C" fn pthread_key_create(
71 key_ptr: *mut pthread_key_t,
72 destructor: Dtor,
73) -> c_int {
74 let key = NEXTKEY.fetch_add(1, Ordering::SeqCst) as pthread_key_t;
75
76 KEYS.lock().insert(key, destructor);
81
82 unsafe { key_ptr.write(key) };
83 0
84}
85
86#[unsafe(no_mangle)]
88pub unsafe extern "C" fn pthread_key_delete(key: pthread_key_t) -> c_int {
89 if KEYS.lock().remove(&key).is_none() {
90 return EINVAL;
92 }
93
94 VALUES.borrow_mut().remove(&key);
97
98 0
99}
100
101pub(crate) unsafe fn run_all_destructors() {
102 for _ in 0..PTHREAD_DESTRUCTOR_ITERATIONS {
103 let mut any_run = false;
104 let dtors = {
105 let keys = KEYS.lock();
106 keys.iter()
107 .filter_map(|(&key, &dtor)| dtor.map(|dtor| (key, dtor)))
108 .collect::<Vec<_>>()
109 };
110
111 for (key, dtor) in dtors {
114 let mut values = VALUES.borrow_mut();
115 if let Some(record) = values.get_mut(&key) {
116 let val = record.data;
117 if val.is_null() {
118 continue;
119 }
120 record.data = ptr::null_mut();
121 drop(values);
122 dtor(val);
123 any_run = true;
124 }
125 }
126
127 if !any_run {
128 break;
129 }
130 }
131
132 }