Skip to content

Commit c1f7e92

Browse files
committed
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`.
1 parent eae47a4 commit c1f7e92

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

src/liballoc_system/lib.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
#![feature(nll)]
2121
#![feature(staged_api)]
2222
#![feature(rustc_attrs)]
23+
#![cfg_attr(
24+
all(target_arch = "wasm32", not(target_os = "emscripten")),
25+
feature(integer_atomics, stdsimd)
26+
)]
2327
#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
2428
#![rustc_alloc_kind = "lib"]
2529

@@ -331,29 +335,76 @@ mod platform {
331335
use core::alloc::{GlobalAlloc, Layout};
332336
use System;
333337

334-
// No need for synchronization here as wasm is currently single-threaded
335338
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
336339

337340
#[stable(feature = "alloc_system_type", since = "1.28.0")]
338341
unsafe impl GlobalAlloc for System {
339342
#[inline]
340343
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
344+
let _lock = lock::lock();
341345
DLMALLOC.malloc(layout.size(), layout.align())
342346
}
343347

344348
#[inline]
345349
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
350+
let _lock = lock::lock();
346351
DLMALLOC.calloc(layout.size(), layout.align())
347352
}
348353

349354
#[inline]
350355
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
356+
let _lock = lock::lock();
351357
DLMALLOC.free(ptr, layout.size(), layout.align())
352358
}
353359

354360
#[inline]
355361
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
362+
let _lock = lock::lock();
356363
DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
357364
}
358365
}
366+
367+
#[cfg(target_feature = "atomics")]
368+
mod lock {
369+
use core::arch::wasm32;
370+
use core::sync::atomic::{AtomicI32, Ordering::SeqCst};
371+
372+
static LOCKED: AtomicI32 = AtomicI32::new(0);
373+
374+
pub struct DropLock;
375+
376+
pub fn lock() -> DropLock {
377+
loop {
378+
if LOCKED.swap(1, SeqCst) == 0 {
379+
return DropLock
380+
}
381+
unsafe {
382+
let r = wasm32::atomic::wait_i32(
383+
&LOCKED as *const AtomicI32 as *mut i32,
384+
1, // expected value
385+
-1, // timeout
386+
);
387+
debug_assert!(r == 0 || r == 1);
388+
}
389+
}
390+
}
391+
392+
impl Drop for DropLock {
393+
fn drop(&mut self) {
394+
let r = LOCKED.swap(0, SeqCst);
395+
debug_assert_eq!(r, 1);
396+
unsafe {
397+
wasm32::atomic::wake(
398+
&LOCKED as *const AtomicI32 as *mut i32,
399+
1, // only one thread
400+
);
401+
}
402+
}
403+
}
404+
}
405+
406+
#[cfg(not(target_feature = "atomics"))]
407+
mod lock {
408+
pub fn lock() {} // no atomics, no threads, that's easy!
409+
}
359410
}

0 commit comments

Comments
 (0)