Skip to content

Add a threadsafe feature for SQLite across workers sharing one memory - #205

Open
LucaCappelletti94 wants to merge 1 commit into
Spxg:masterfrom
LucaCappelletti94:feat/threadsafe
Open

LucaCappelletti94 wants to merge 1 commit into
Spxg:masterfrom
LucaCappelletti94:feat/threadsafe

Conversation

@LucaCappelletti94

@LucaCappelletti94 LucaCappelletti94 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Part of #202. Adds a threadsafe feature that compiles SQLite with SQLITE_THREADSAFE=1 and gives it a mutex that works across workers sharing one memory. The memory VFS stays single-threaded until #204.

SQLITE_OS_OTHER builds otherwise get no-op mutexes, so shim/threadsafe.h redirects SQLite's sqlite3DefaultMutex() to the mutex in src/mutex.rs. It spins on Wasm atomics, then sleeps in memory.atomic.wait32 where the thread may block. It is hand-written because std and parking_lot sleep in memory.atomic.wait32 under contention without checking the thread, which traps on Chrome's main thread, and SQLite needs a recursive mutex that it enters and leaves in separate C calls.

Whether a thread may block depends on the running module, since --shared-memory needs +atomics and +atomics alone still links an unshared memory. A sixth host hook, rust_sqlite_wasm_host_can_block, answers it, and the wasm-bindgen adapter tries a zero-timeout Atomics.wait on the module's own memory, which throws on unshared memory and on threads that may not block.

@Spxg

Spxg commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Thanks for your PR! I think the mutex implementation could be split into a separate PR, then VFS.

Also, we should take a closer look at the relationship between threadsafe, atomics, and --shared-memory. That's actually why I submitted #207, since it relies on --shared-memory rather than atomics.

@LucaCappelletti94

Copy link
Copy Markdown
Contributor Author

I split #205 as suggested. It now holds only the threadsafe feature and the mutex, rebased on #207, and #204 sits on top with the memvfs changes and the worker tests that share memvfs files. The worker tests here use :memory:, which never touches memvfs's files.

My understanding is that wasm-ld refuses --shared-memory unless the Rust objects are built with +atomics, and +atomics without --shared-memory links an unshared memory. So atomics is a precondition for threads, and whether memory is shared is known only to the running module.

can_block used to wait on a private SharedArrayBuffer, so a worker in an +atomics build without --shared-memory was told it could wait and would trap in memory.atomic.wait32 under contention. It now waits on the module's own memory, threadsafe_can_block checks that a worker may block exactly when memory is shared, and CI also runs it on an +atomics build without --shared-memory.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants