about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-12 05:52:17 +0000
committerbors <bors@rust-lang.org>2020-11-12 05:52:17 +0000
commit55794e43960ad3647e78ea5b0cb5ad0c5c0596a8 (patch)
tree8f15452ce9172f3340c458c214eb9f70ff91e359 /library/std/src/sys
parent5a6a41e7847ff5f85a31b87431ce2af29c567f1d (diff)
parentbf3be09ee800de4ec98dfeea5088639e1c538813 (diff)
downloadrust-55794e43960ad3647e78ea5b0cb5ad0c5c0596a8.tar.gz
rust-55794e43960ad3647e78ea5b0cb5ad0c5c0596a8.zip
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.
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/unix/futex.rs42
-rw-r--r--library/std/src/sys/unix/thread.rs20
2 files changed, 42 insertions, 20 deletions
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
index e6f0c48c59b..42ddc1d514e 100644
--- a/library/std/src/sys/unix/futex.rs
+++ b/library/std/src/sys/unix/futex.rs
@@ -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 {
@@ -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(
@@ -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);
+    }
+}
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index f1ab302d30e..cda17eb4bd2 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -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> {
@@ -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);