Skip to content

Commit 55794e4

Browse files
committed
Auto merge of #78965 - jryans:emscripten-threads-libc, r=kennytm
Update thread and futex APIs to work with Emscripten This updates the thread and futex APIs in `std` to match the APIs exposed by Emscripten. This allows threads to run on `wasm32-unknown-emscripten` and the thread parker to compile without errors related to the missing `futex` module. To make use of this, Rust code must be compiled with `-C target-feature=atomics` and Emscripten must link with `-pthread`. I have confirmed this works well locally when building multithreaded crates. Attempting to enable `std` thread tests currently fails for seemingly obscure reasons and Emscripten is currently disabled in CI, so further work is needed to have proper test coverage here.
2 parents 5a6a41e + bf3be09 commit 55794e4

File tree

2 files changed

+42
-20
lines changed

2 files changed

+42
-20
lines changed

library/std/src/sys/unix/futex.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
#![cfg(any(target_os = "linux", target_os = "android"))]
1+
#![cfg(any(
2+
target_os = "linux",
3+
target_os = "android",
4+
all(target_os = "emscripten", target_feature = "atomics")
5+
))]
26

7+
#[cfg(any(target_os = "linux", target_os = "android"))]
38
use crate::convert::TryInto;
9+
#[cfg(any(target_os = "linux", target_os = "android"))]
410
use crate::ptr::null;
511
use crate::sync::atomic::AtomicI32;
612
use crate::time::Duration;
713

14+
#[cfg(any(target_os = "linux", target_os = "android"))]
815
pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
916
let timespec = timeout.and_then(|d| {
1017
Some(libc::timespec {
@@ -25,6 +32,28 @@ pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
2532
}
2633
}
2734

35+
#[cfg(target_os = "emscripten")]
36+
pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
37+
extern "C" {
38+
fn emscripten_futex_wait(
39+
addr: *const AtomicI32,
40+
val: libc::c_uint,
41+
max_wait_ms: libc::c_double,
42+
) -> libc::c_int;
43+
}
44+
45+
unsafe {
46+
emscripten_futex_wait(
47+
futex as *const AtomicI32,
48+
// `val` is declared unsigned to match the Emscripten headers, but since it's used as
49+
// an opaque value, we can ignore the meaning of signed vs. unsigned and cast here.
50+
expected as libc::c_uint,
51+
timeout.map_or(crate::f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
52+
);
53+
}
54+
}
55+
56+
#[cfg(any(target_os = "linux", target_os = "android"))]
2857
pub fn futex_wake(futex: &AtomicI32) {
2958
unsafe {
3059
libc::syscall(
@@ -35,3 +64,14 @@ pub fn futex_wake(futex: &AtomicI32) {
3564
);
3665
}
3766
}
67+
68+
#[cfg(target_os = "emscripten")]
69+
pub fn futex_wake(futex: &AtomicI32) {
70+
extern "C" {
71+
fn emscripten_futex_wake(addr: *const AtomicI32, count: libc::c_int) -> libc::c_int;
72+
}
73+
74+
unsafe {
75+
emscripten_futex_wake(futex as *const AtomicI32, 1);
76+
}
77+
}

library/std/src/sys/unix/thread.rs

+1-19
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,6 @@ pub struct Thread {
2222
unsafe impl Send for Thread {}
2323
unsafe impl Sync for Thread {}
2424

25-
// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
26-
// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
27-
#[cfg(not(target_os = "emscripten"))]
28-
unsafe fn pthread_attr_setstacksize(
29-
attr: *mut libc::pthread_attr_t,
30-
stack_size: libc::size_t,
31-
) -> libc::c_int {
32-
libc::pthread_attr_setstacksize(attr, stack_size)
33-
}
34-
35-
#[cfg(target_os = "emscripten")]
36-
unsafe fn pthread_attr_setstacksize(
37-
_attr: *mut libc::pthread_attr_t,
38-
_stack_size: libc::size_t,
39-
) -> libc::c_int {
40-
panic!()
41-
}
42-
4325
impl Thread {
4426
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
4527
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
@@ -50,7 +32,7 @@ impl Thread {
5032

5133
let stack_size = cmp::max(stack, min_stack_size(&attr));
5234

53-
match pthread_attr_setstacksize(&mut attr, stack_size) {
35+
match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
5436
0 => {}
5537
n => {
5638
assert_eq!(n, libc::EINVAL);

0 commit comments

Comments
 (0)