Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiment: Build PHP with OPFS support #1030

Closed
wants to merge 1 commit into from
Closed

Conversation

adamziel
Copy link
Collaborator

@adamziel adamziel commented Feb 11, 2024

This is an attempt to use Emscripten to build a WASM module that uses OPFS as its filesystem.

To try it out locally, run:

python server.py

Then, go to http://localhost:8000/ and open the developer tools.

OPFS backend for WASMFS causes crashes in Chrome

No matter what I did, I couldn't get OPFS to work in the browser.

It always crashes when creating a new file in the /opfs directory. This function call:

void create_file() {
    FILE *file = fopen("/opfs/test.txt", "w");
    // ...
}

Invokes the following asynchronous JavaScript implementation:

  async function wasmfsOPFSGetOrCreateFile(parent, name, create) {
      let parentHandle = wasmfsOPFSDirectoryHandles.get(parent);
      let fileHandle;
      try {
        fileHandle = await parentHandle.getFileHandle(name, {create: create});
        // ...

However, the await is deadly and crashes the WASM process:

support.cpp:39 Uncaught RuntimeError: unreachable
    at wasmfs::handle_unreachable(char const*, char const*, unsigned int) (http://localhost:8000/opfs.wasm:wasm-function[327]:0xf3d3)
    at (anonymous namespace)::OPFSDirectory::getChild(std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>> const&) (http://localhost:8000/opfs.wasm:wasm-function[297]:0xba0e)
    at wasmfs::Directory::Handle::getChild(std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>> const&) (http://localhost:8000/opfs.wasm:wasm-function[406]:0x11c4c)
    at wasmfs::path::(anonymous namespace)::getChild(std::__2::shared_ptr<wasmfs::Directory>, std::__2::basic_string_view<char, std::__2::char_traits<char>>, wasmfs::path::LinkBehavior, unsigned long&) (http://localhost:8000/opfs.wasm:wasm-function[439]:0x17a2f)
    at wasmfs::path::(anonymous namespace)::doParseParent(std::__2::basic_string_view<char, std::__2::char_traits<char>>, std::__2::shared_ptr<wasmfs::Directory>, unsigned long&) (http://localhost:8000/opfs.wasm:wasm-function[438]:0x175f2)
    at wasmfs::path::parseParent(std::__2::basic_string_view<char, std::__2::char_traits<char>>, unsigned int) (http://localhost:8000/opfs.wasm:wasm-function[436]:0x16ef2)
    at __syscall_openat (http://localhost:8000/opfs.wasm:wasm-function[474]:0x1b10d)
    at open (http://localhost:8000/opfs.wasm:wasm-function[53]:0x15a8)
    at create_file (http://localhost:8000/opfs.wasm:wasm-function[47]:0x11e7)
    at ret.<computed> (http://localhost:8000/opfs.js:2559:35)

It's not about the getFileHandle call. It's about asynchronous code. The same function with await sleep(100); crashes in the exact same way.

Potential solutions

I tried building:

  • With -sASYNCIFY=1 and different ASYNCIFY settings and imports
  • With -sASYNCIFY=2 (after enabling JSPI at chrome://flags)
  • With -sWASM_WORKERS

Unfortunately, the final bundle always crashes in the same way.

Weirdly, it crashes on file creation but not on directory creation. The mkdir code path seems to somehow support stack switching.

I don't have any futher ideas so I'll abandon these explorations for now and leave this PR for posterity.

Implementation details

This PR explores Emscripten's new WASMFS filesystem with OPFS backend.

main.c contains the C code where the OPFS directory is created:

int main() {
    backend_t opfs = wasmfs_create_opfs_backend();
    emscripten_console_log("created OPFS backend");
    wasmfs_create_directory("/opfs", 0777, opfs);
}

void create_file() {
    FILE *file = fopen("/opfs/test.txt", "w");
    // ...
}

It's then built into a WASM module via build.sh (or build-in-docker.sh for convenience) and loaded in the browser by index.html.

Building

Run build-in-docker.sh

WASMFS Resources

There's no documentation out there, I've been learning from GitHub discussions and code in the Emscripten repo. Here's a few useful links:

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.

1 participant