Skip to content

Commit

Permalink
Auto merge of #78965 - jryans:emscripten-threads-libc, r=kennytm
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Nov 12, 2020
2 parents 5a6a41e + bf3be09 commit 55794e4
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 20 deletions.
42 changes: 41 additions & 1 deletion library/std/src/sys/unix/futex.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
#![cfg(any(target_os = "linux", target_os = "android"))]
#![cfg(any(
target_os = "linux",
target_os = "android",
all(target_os = "emscripten", target_feature = "atomics")
))]

#[cfg(any(target_os = "linux", target_os = "android"))]
use crate::convert::TryInto;
#[cfg(any(target_os = "linux", target_os = "android"))]
use crate::ptr::null;
use crate::sync::atomic::AtomicI32;
use crate::time::Duration;

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

#[cfg(target_os = "emscripten")]
pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
extern "C" {
fn emscripten_futex_wait(
addr: *const AtomicI32,
val: libc::c_uint,
max_wait_ms: libc::c_double,
) -> libc::c_int;
}

unsafe {
emscripten_futex_wait(
futex as *const AtomicI32,
// `val` is declared unsigned to match the Emscripten headers, but since it's used as
// an opaque value, we can ignore the meaning of signed vs. unsigned and cast here.
expected as libc::c_uint,
timeout.map_or(crate::f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
);
}
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn futex_wake(futex: &AtomicI32) {
unsafe {
libc::syscall(
Expand All @@ -35,3 +64,14 @@ pub fn futex_wake(futex: &AtomicI32) {
);
}
}

#[cfg(target_os = "emscripten")]
pub fn futex_wake(futex: &AtomicI32) {
extern "C" {
fn emscripten_futex_wake(addr: *const AtomicI32, count: libc::c_int) -> libc::c_int;
}

unsafe {
emscripten_futex_wake(futex as *const AtomicI32, 1);
}
}
20 changes: 1 addition & 19 deletions library/std/src/sys/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,6 @@ pub struct Thread {
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
#[cfg(not(target_os = "emscripten"))]
unsafe fn pthread_attr_setstacksize(
attr: *mut libc::pthread_attr_t,
stack_size: libc::size_t,
) -> libc::c_int {
libc::pthread_attr_setstacksize(attr, stack_size)
}

#[cfg(target_os = "emscripten")]
unsafe fn pthread_attr_setstacksize(
_attr: *mut libc::pthread_attr_t,
_stack_size: libc::size_t,
) -> libc::c_int {
panic!()
}

impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
Expand All @@ -50,7 +32,7 @@ impl Thread {

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

match pthread_attr_setstacksize(&mut attr, stack_size) {
match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
0 => {}
n => {
assert_eq!(n, libc::EINVAL);
Expand Down

0 comments on commit 55794e4

Please sign in to comment.