Skip to content

Add shared linear memory as prerequisite for wasip1-threads#359

Open
MaxDesiatov wants to merge 11 commits into
mainfrom
maxd/wasi-shared-memory
Open

Add shared linear memory as prerequisite for wasip1-threads#359
MaxDesiatov wants to merge 11 commits into
mainfrom
maxd/wasi-shared-memory

Conversation

@MaxDesiatov

Copy link
Copy Markdown
Member

Added corresponding shared memory load/instructions that call reloadSharedMemorySize, updated atomic instructions to do the same.

A `shared` memory is backed by `SharedMemoryStorage`, which reserves its full address range up front so the base pointer stays stable, then commits pages on `memory.grow` under a spinlock that the SIGSEGV/SIGBUS handler also takes, so a concurrent grow cannot race an in-flight access; `memory.atomic.wait32/64` and `memory.atomic.notify` block and wake threads through `AtomicParkingLot`. Adds `SharedMemoryStorageTests` and `AtomicParkingLotTests`.

@kateinoigakukun kateinoigakukun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's split out AtomicParkingLot's pthread_cond_t change to make review easier 🙇

Comment on lines +516 to +522
// Shared memory always uses software bounds checking. A guard-page fault
// recovered by siglongjmp would unwind the interpreter past a lock held by a
// concurrent grow or atomic operation, so the multi-threaded path must stay
// free of non-local jumps. mprotect guards are reserved for non-shared memory.
let isNonSharedMemory = sp.currentInstance?.memories.first?.withValue { $0.sharedStorage == nil } ?? true
let shouldUseMprotectTrapGuards =
store.value.engine.configuration.memoryBoundsChecking == .mprotect && isNonSharedMemory

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I actually didn't get this. Is it even theoretically possible that "thread X causes Wasm OOB access while owning memory.grow or atomic.wait lock? Given that siglongjmp is a thread local stack unwinding, I guess it won't be possible to happen?

/// A type that can be interned into a unique identifier.
/// Used for efficient equality comparison.
protocol Internable {
package protocol Internable {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why do we need to expose some structures in this file to package level?


/// If this memory is shared, the mmap-backed storage is held here.
/// Multiple `MemoryEntity` instances (across threads) may reference the same `SharedMemoryStorage`.
let sharedStorage: SharedMemoryEntity?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the memory storage should be consistently represented by let storage member to avoid having many if let sharedStorage below and we can remove shared-variant of memory instructions. Also even further, I'm wondering if we really need a new SharedMemoryEntity type here, can't we add shared mode to MprotectLinearMemory?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants