WebAssembly / WebAssembly/wasi-libc

pthread should use atomic load/store for access of contended fields

Open
#413 14 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C
Stars
1k
Forks
251
Avg merge
7h 15m
Merged PRs (30d)
3

Description

Sorry if this is the wrong repo for this issue, I guess it is more related to LLVM but I am finding it through analysis of wasi-libc and WebAssembly threads proposal specifically, and perhaps the change should be scoped to just libc.

I have been working on threads support for wazero, and for example run tests with this simple use of pthread mutex

https://github.com/tetratelabs/wazero/blob/main/experimental/testdata/pthread.c

One cool thing about wazero being a Go runtime is that the Go race detector can be applied. When trying to run that code concurrently from multiple host threads, each with an instantiated wasm module accessing an imported shared memory (the code in main does not reflect this yet, I am trying in https://github.com/tetratelabs/wazero/compare/main...anuraaga:wazero:mod-per-routine?expand=1), races are shown. It's hard to find the actual C code that causes a race, but through some pattern matching, I found for example this code during locking

https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/src/thread/pthread_mutex_timedlock.c#L77

trylock is a CAS while r = m->_m_lock is a load of a volatile field. I see the compiled Wasm uses i32.atomic.rmw.cmpxchg for the CAS, but just i32.load, not an atomic load for the volatile read. I can't say I'm an expert on this subject, but my guess is that a non-atomic load is used because on normal hardware, a 32-bit load is atomic vs other atomic instructions, there's no such thing as a non-atomic load per se. However, WebAssembly can be run in many environments, and in the case of wazero's interpreter mode (compiler mode has not been implemented yet and would likely not exhibit this race), CAS operations are not implemented with atomic instructions (Go does not provide the APIs to do so for all the instructions in the thread proposal) and uses locks instead.

cmpxchg locks
https://github.com/tetratelabs/wazero/blob/90eba1b81cacd0a5c1b4351d4d5e73c57d13c4b1/internal/engine/interpreter/interpreter.go#L4198

atomic.load locks
https://github.com/tetratelabs/wazero/blob/main/internal/engine/interpreter/interpreter.go#L3974

normal load doesn't lock and will race with any cmpxchg operation
https://github.com/tetratelabs/wazero/blob/main/internal/engine/interpreter/interpreter.go#L755

Because wasm32-wasi-threads will be executed on arbitrary machines, does it make sense to use atomic.load for volatile read instead of normal one? While I understand that C volatile is not supposed to be a guarantee of atomicity, I wonder if in practice code like in musl does expect it. Or perhaps wasi-libc's fork of musl needs to be made more precise by explicitly specifying atomic load, because it cannot assume a fixed set of supported architectures like musl does. Sorry if this is completely off the mark.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with musl/src/thread/pthread_mutex_timedlock.c at the cited load, then compare the referenced wazero interpreter implementations for cmpxchg, atomic.load, and normal load. Determine whether wasi-libc needs an explicit atomic access for this path and identify the relevant thread tests; done means the behavior and scope are agreed and covered by a reproducible test.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, wasm
Domain
operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.