#spin-lock #mutex

wasm_safe_mutex

A suite of WebAssembly-safe synchronization primitives that paper over platform-specific locking constraints

3 releases

Uses new Rust 2024

0.1.2 Nov 28, 2025
0.1.1 Nov 23, 2025
0.1.0 Aug 18, 2025

#181 in Concurrency

Download history 101/week @ 2025-08-13 27/week @ 2025-08-20 23/week @ 2025-08-27 28/week @ 2025-09-03 9/week @ 2025-09-10 11/week @ 2025-09-17 22/week @ 2025-09-24 32/week @ 2025-10-01 19/week @ 2025-10-08 83/week @ 2025-10-15 18/week @ 2025-10-22 166/week @ 2025-11-19 61/week @ 2025-11-26

227 downloads per month
Used in 21 crates (7 directly)

MIT/Apache

200KB
3K SLoC

wasm_safe_mutex

logo

A suite of WebAssembly-safe synchronization primitives that paper over platform-specific locking constraints.

The Core Problem

WebAssembly's main thread cannot use blocking locks - attempting to do so will panic with "cannot block on the main thread". This is a fundamental limitation of the browser environment where blocking the main thread would freeze the entire UI.

However, blocking locks ARE allowed in:

  • WebAssembly worker threads (where Atomics.wait is available)
  • Native platforms (both main and worker threads)
  • Most non-WASM contexts (traditional OS threads have no such restrictions)

The Solution

This crate provides synchronization primitives that automatically adapt their locking strategy based on the runtime environment:

  • Native (any thread): Uses efficient thread parking (thread::park)
  • WASM worker threads: Uses Atomics.wait when available
  • WASM main thread: Falls back to spinning (non-blocking busy-wait)

This means you can write code once and have it work correctly across all platforms, without worrying about whether you're on the main thread, a worker thread, native or WASM.

Primitives

This crate provides the following primitives, all of which support the adaptive behavior:

  • Mutex: A mutual exclusion primitive for protecting shared data.
  • RwLock: A reader-writer lock that allows multiple concurrent readers or one exclusive writer.
  • Condvar: A condition variable for blocking a thread while waiting for an event.
  • mpsc: A multi-producer, single-consumer channel for message passing.

Features

  • Transparent adaptation: Automatically detects and uses the best available locking mechanism
  • Main thread safe: Won't panic on WASM main thread (uses spinning instead)
  • Worker thread optimized: Uses proper blocking when available for efficiency
  • Native performance: Full thread parking on native platforms
  • Async support: Non-blocking async methods that work everywhere
  • Multiple strategies: Try-lock, spin-lock, blocking lock, and async lock

Installation

Add this to your Cargo.toml:

[dependencies]
wasm_safe_mutex = "0.1.0"

Examples

Mutex

use wasm_safe_mutex::Mutex;

let mutex = Mutex::new(42);
let mut guard = mutex.lock_sync();
*guard = 100;
drop(guard);

assert_eq!(*mutex.lock_sync(), 100);

RwLock

use wasm_safe_mutex::rwlock::RwLock;

let rwlock = RwLock::new(vec![1, 2, 3]);

// Multiple readers
let r1 = rwlock.lock_sync_read();
let r2 = rwlock.lock_sync_read();
assert_eq!(r1.len(), 3);
assert_eq!(r2.len(), 3);
drop(r1);
drop(r2);

// Exclusive writer
let mut w = rwlock.lock_sync_write();
w.push(4);

Async Usage

use wasm_safe_mutex::Mutex;

let mutex = Mutex::new(0);

// Async lock works everywhere, including WASM main thread
let mut guard = mutex.lock_async().await;
*guard += 1;

Platform Behavior

The primitives transparently handle platform differences:

  • Native (main or worker thread): Full blocking with thread parking
  • WASM worker threads: Blocks using Atomics.wait
  • WASM main thread: Spins to avoid "cannot block on main thread" panic

This automatic adaptation means your code works everywhere without modification.

Dependencies

~0.5–2.4MB
~43K SLoC