Skip to content

Commit a2d67ef

Browse files
committed
Implement thread-local storage without pthread.
1 parent 161eda1 commit a2d67ef

File tree

4 files changed

+112
-11
lines changed

4 files changed

+112
-11
lines changed

src/libstd/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@
280280
#![feature(libc)]
281281
#![feature(link_args)]
282282
#![feature(linkage)]
283+
#![feature(linked_list_remove)]
283284
#![feature(llvm_asm)]
284285
#![feature(log_syntax)]
285286
#![feature(maybe_uninit_ref)]

src/libstd/sys/unix/freertos/ffi.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub type TaskHandle_t = *mut libc::c_void;
77
pub type QueueHandle_t = *mut libc::c_void;
88
pub type SemaphoreHandle_t = QueueHandle_t;
99
pub type TaskFunction_t = extern "C" fn(*mut libc::c_void) -> *mut libc::c_void;
10+
pub type TlsDeleteCallbackFunction_t = unsafe extern "C" fn(libc::c_int, *mut libc::c_void);
1011

1112
pub const queueQUEUE_TYPE_MUTEX: u8 = 1;
1213
pub const queueQUEUE_TYPE_RECURSIVE_MUTEX: u8 = 4;
@@ -63,6 +64,9 @@ extern "C" {
6364
pxCreatedTask: *mut TaskHandle_t,
6465
xCoreID: BaseType_t,
6566
) -> BaseType_t;
67+
pub fn pvTaskGetThreadLocalStoragePointer(xTaskToQuery: TaskHandle_t, xIndex: BaseType_t) -> *mut libc::c_void;
68+
pub fn vTaskSetThreadLocalStoragePointer(xTaskToQuery: TaskHandle_t, xIndex: BaseType_t, pvValue: *mut libc::c_void);
69+
pub fn vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskToQuery: TaskHandle_t, xIndex: BaseType_t, pvValue: *mut libc::c_void, xDelCallback: TlsDeleteCallbackFunction_t);
6670
}
6771

6872
#[cfg(target_device = "esp32")]

src/libstd/sys/unix/freertos/thread.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::sys_common::thread::*;
99
use crate::pin::Pin;
1010

1111
use crate::sys::ffi::*;
12+
use crate::sys::thread_local;
1213

1314
const RUNNING: usize = 0;
1415
const DETACHED: usize = 1;
@@ -66,6 +67,7 @@ impl Thread {
6667
join_mutex.lock();
6768

6869
main();
70+
thread_local::cleanup();
6971

7072
let previous_state = state.swap(EXITED, SeqCst);
7173

src/libstd/sys/unix/freertos/thread_local.rs

Lines changed: 105 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,125 @@
1-
#![allow(dead_code)] // not used on all platforms
1+
use crate::collections::{LinkedList, BTreeMap};
2+
use crate::ptr;
3+
use crate::sys::ffi::*;
4+
use crate::sys_common::rwlock::RWLock;
25

3-
use crate::mem;
6+
pub type Key = usize;
7+
type Tls = BTreeMap<Key, *mut u8>;
48

5-
pub type Key = libc::pthread_key_t;
9+
const TLS_INDEX: BaseType_t = 1;
10+
11+
static LOCK: RWLock = RWLock::new();
12+
static mut KEYS: LinkedList<(Key, Option<unsafe extern "C" fn(*mut u8)>)> = LinkedList::new();
13+
14+
#[inline]
15+
unsafe fn get_tls() -> *mut Tls {
16+
pvTaskGetThreadLocalStoragePointer(ptr::null_mut(), TLS_INDEX) as *mut Tls
17+
}
618

719
#[inline]
8-
pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
9-
let mut key = 0;
10-
assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
20+
unsafe fn set_tls(tls: *mut Tls) {
21+
vTaskSetThreadLocalStoragePointer(ptr::null_mut(), TLS_INDEX, tls as *mut _);
22+
}
23+
24+
#[inline]
25+
pub unsafe fn cleanup() {
26+
if let Some(mut tls) = get_tls().as_mut() {
27+
let tls = Box::from_raw(tls);
28+
29+
LOCK.read();
30+
31+
for (k, dtor) in KEYS.iter() {
32+
if let (Some(v), Some(dtor)) = (tls.get(k), dtor) {
33+
dtor(*v)
34+
}
35+
}
36+
37+
LOCK.read_unlock();
38+
39+
set_tls(ptr::null_mut());
40+
}
41+
}
42+
43+
#[inline]
44+
pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
45+
LOCK.write();
46+
47+
let key = KEYS.back().map(|&(i, _)| i + 1).unwrap_or(1);
48+
KEYS.push_back((key, dtor));
49+
50+
LOCK.write_unlock();
51+
1152
key
1253
}
1354

1455
#[inline]
1556
pub unsafe fn set(key: Key, value: *mut u8) {
16-
let r = libc::pthread_setspecific(key, value as *mut _);
17-
debug_assert_eq!(r, 0);
57+
#[cfg(debug)]
58+
{
59+
LOCK.read();
60+
61+
let mut found = false;
62+
63+
for (k, _) in KEYS.iter() {
64+
if k == key {
65+
found = true;
66+
break;
67+
}
68+
}
69+
70+
assert!(found);
71+
72+
LOCK.read_unlock();
73+
}
74+
75+
76+
let mut tls = if let Some(mut tls) = get_tls().as_mut() {
77+
tls
78+
} else {
79+
let mut tls = Box::into_raw(box Tls::new());
80+
set_tls(tls);
81+
&mut *tls
82+
};
83+
84+
if value.is_null() {
85+
tls.remove(&key);
86+
} else {
87+
tls.insert(key, value);
88+
}
1889
}
1990

2091
#[inline]
2192
pub unsafe fn get(key: Key) -> *mut u8 {
22-
libc::pthread_getspecific(key) as *mut u8
93+
if let Some(tls) = get_tls().as_mut() {
94+
tls.get(&key).cloned().unwrap_or_else(ptr::null_mut)
95+
} else {
96+
ptr::null_mut()
97+
}
2398
}
2499

25100
#[inline]
26101
pub unsafe fn destroy(key: Key) {
27-
let r = libc::pthread_key_delete(key);
28-
debug_assert_eq!(r, 0);
102+
LOCK.write();
103+
104+
let mut i = 0;
105+
let mut found = false;
106+
107+
for &(k, _) in KEYS.iter() {
108+
if k == key {
109+
found = true;
110+
break;
111+
}
112+
113+
i += 1;
114+
}
115+
116+
debug_assert!(found);
117+
118+
if found {
119+
KEYS.remove(i);
120+
}
121+
122+
LOCK.write_unlock();
29123
}
30124

31125
#[inline]

0 commit comments

Comments
 (0)