about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-10-09 20:18:10 -0700
committerAlex Crichton <alex@alexcrichton.com>2018-10-09 23:35:45 -0700
commitc1f7e922e6e082d3f58db4a69fdf821e93ffa665 (patch)
treeea9d965a6caf7b5afb25118ebf16b901695b2715
parenteae47a40484a085f699c3175d51e74901c607e65 (diff)
downloadrust-c1f7e922e6e082d3f58db4a69fdf821e93ffa665.tar.gz
rust-c1f7e922e6e082d3f58db4a69fdf821e93ffa665.zip
std: Synchronize global allocator on wasm32
We originally didn't have threads, and now we're starting to add them!
Make sure we properly synchronize access to dlmalloc when the `atomics`
feature is enabled for `wasm32-unknown-unknown`.
-rw-r--r--src/liballoc_system/lib.rs53
1 files changed, 52 insertions, 1 deletions
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 3ef03ec6d58..15283036bb4 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -20,6 +20,10 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
+#![cfg_attr(
+    all(target_arch = "wasm32", not(target_os = "emscripten")),
+    feature(integer_atomics, stdsimd)
+)]
 #![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
 #![rustc_alloc_kind = "lib"]
 
@@ -331,29 +335,76 @@ mod platform {
     use core::alloc::{GlobalAlloc, Layout};
     use System;
 
-    // No need for synchronization here as wasm is currently single-threaded
     static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
 
     #[stable(feature = "alloc_system_type", since = "1.28.0")]
     unsafe impl GlobalAlloc for System {
         #[inline]
         unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            let _lock = lock::lock();
             DLMALLOC.malloc(layout.size(), layout.align())
         }
 
         #[inline]
         unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            let _lock = lock::lock();
             DLMALLOC.calloc(layout.size(), layout.align())
         }
 
         #[inline]
         unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+            let _lock = lock::lock();
             DLMALLOC.free(ptr, layout.size(), layout.align())
         }
 
         #[inline]
         unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+            let _lock = lock::lock();
             DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
         }
     }
+
+    #[cfg(target_feature = "atomics")]
+    mod lock {
+        use core::arch::wasm32;
+        use core::sync::atomic::{AtomicI32, Ordering::SeqCst};
+
+        static LOCKED: AtomicI32 = AtomicI32::new(0);
+
+        pub struct DropLock;
+
+        pub fn lock() -> DropLock {
+            loop {
+                if LOCKED.swap(1, SeqCst) == 0 {
+                    return DropLock
+                }
+                unsafe {
+                    let r = wasm32::atomic::wait_i32(
+                        &LOCKED as *const AtomicI32 as *mut i32,
+                        1,  // expected value
+                        -1, // timeout
+                    );
+                    debug_assert!(r == 0 || r == 1);
+                }
+            }
+        }
+
+        impl Drop for DropLock {
+            fn drop(&mut self) {
+                let r = LOCKED.swap(0, SeqCst);
+                debug_assert_eq!(r, 1);
+                unsafe {
+                    wasm32::atomic::wake(
+                        &LOCKED as *const AtomicI32 as *mut i32,
+                        1, // only one thread
+                    );
+                }
+            }
+        }
+    }
+
+    #[cfg(not(target_feature = "atomics"))]
+    mod lock {
+        pub fn lock() {} // no atomics, no threads, that's easy!
+    }
 }