-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WasmFS] Async proxied JS backend (#16229)
The key file src/library_wasmfs_fetch.js here shows a simple async JS backend that depends on pthreads proxying. That is, the main code looks sync as usual, and we proxy to a dedicated thread which does the async operation, here, a network fetch(). This is a "hello world" backend, the minimal one I can think of that is async. But it may still be useful - we used to have a LazyFile option in the old FS, which this is very close to, that is, on the first read of the data we fetch it from the network, and then it is cached like a normal JS file. To implement this, add a new ProxiedAsyncJSImplFile in C++. This combines the matters of proxying and the target being async. In theory we could add two layers, here, first a C++ File that is async (perhaps using C++ futures?), but I think that might be over-engineering, since we don't really want the async aspect for C++ - it's very specific to JS. However, those are internal details, and we could refactor the code later to add such laying if we wanted. The JS side is the important part here. Basically each JS backend would define a bunch of JS hooks that return Promises, and everything else is taken care of automatically.
- Loading branch information
Showing
18 changed files
with
514 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
mergeInto(LibraryManager.library, { | ||
// Fetch backend: On first access of the file (either a read or a getSize), it | ||
// will fetch() the data from the network asynchronously. Otherwise, after | ||
// that fetch it behaves just like JSFile (and it reuses the code from there). | ||
|
||
_wasmfs_create_fetch_backend_js__deps: [ | ||
'$wasmFS$backends', | ||
'$wasmFS$JSMemoryFiles', | ||
'_wasmfs_create_js_file_backend_js', | ||
], | ||
_wasmfs_create_fetch_backend_js: async function(backend) { | ||
// Get a promise that fetches the data and stores it in JS memory (if it has | ||
// not already been fetched). | ||
async function getFile(file) { | ||
if (wasmFS$JSMemoryFiles[file]) { | ||
// The data is already here, so nothing to do before we continue on to | ||
// the actual read below. | ||
return Promise.resolve(); | ||
} | ||
|
||
// This is the first time we want the file's data. | ||
// TODO: real URL! | ||
var url = 'data.dat'; | ||
var response = await fetch(url); | ||
var buffer = await response['arrayBuffer'](); | ||
wasmFS$JSMemoryFiles[file] = new Uint8Array(buffer); | ||
} | ||
|
||
// Start with the normal JSFile operations. This sets | ||
// wasmFS$backends[backend] | ||
// which we will then augment. | ||
__wasmfs_create_js_file_backend_js(backend); | ||
|
||
// Add the async operations on top. | ||
var jsFileOps = wasmFS$backends[backend]; | ||
wasmFS$backends[backend] = { | ||
// alloc/free operations are not actually async. Just forward to the | ||
// parent class, but we must return a Promise as the caller expects. | ||
allocFile: async (file) => { | ||
jsFileOps.allocFile(file); | ||
return Promise.resolve(); | ||
}, | ||
freeFile: async (file) => { | ||
jsFileOps.freeFile(file); | ||
return Promise.resolve(); | ||
}, | ||
|
||
write: async (file, buffer, length, offset) => { | ||
abort("TODO: file writing in fetch backend? read-only for now"); | ||
}, | ||
|
||
// read/getSize fetch the data, then forward to the parent class. | ||
read: async (file, buffer, length, offset) => { | ||
await getFile(file); | ||
return jsFileOps.read(file, buffer, length, offset); | ||
}, | ||
getSize: async(file) => { | ||
await getFile(file); | ||
return jsFileOps.getSize(file); | ||
}, | ||
}; | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,5 +47,14 @@ | |
"name" | ||
] | ||
} | ||
}, | ||
{ | ||
"file": "async_callback.h", | ||
"structs": { | ||
"CallbackState": [ | ||
"result", | ||
"offset" | ||
] | ||
} | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2022 The Emscripten Authors. All rights reserved. | ||
// Emscripten is available under two separate licenses, the MIT license and the | ||
// University of Illinois/NCSA Open Source License. Both these licenses can be | ||
// found in the LICENSE file. | ||
|
||
// This file defines the JS file backend and JS file of the new file system. | ||
// Current Status: Work in Progress. | ||
// See https://github.com/emscripten-core/emscripten/issues/15041. | ||
|
||
#pragma once | ||
|
||
#include "sys/types.h" | ||
#include "wasi/api.h" | ||
|
||
// Callbacks for the async API between C and JS. This is declared in a small | ||
// separate header for convenience of gen_struct_info. | ||
|
||
// Callbacks take a pointer to a CallbackState structure, which contains both | ||
// the function to call to resume execution, and storage for any out params. | ||
// Basically this stores the state during an async call. | ||
struct CallbackState { | ||
// The result of the operation, either success or an error code. | ||
__wasi_errno_t result; | ||
|
||
// Some syscalls return an offset. | ||
off_t offset; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2021 The Emscripten Authors. All rights reserved. | ||
// Emscripten is available under two separate licenses, the MIT license and the | ||
// University of Illinois/NCSA Open Source License. Both these licenses can be | ||
// found in the LICENSE file. | ||
|
||
// This file defines the JS file backend and JS file of the new file system. | ||
// See https://github.com/emscripten-core/emscripten/issues/15041. | ||
|
||
#include "backend.h" | ||
#include "proxied_async_js_impl_backend.h" | ||
#include "wasmfs.h" | ||
|
||
// See library_wasmfs_fetch.js | ||
|
||
extern "C" { | ||
void _wasmfs_create_fetch_backend_js(wasmfs::backend_t); | ||
} | ||
|
||
namespace wasmfs { | ||
|
||
extern "C" backend_t wasmfs_create_fetch_backend(char* base_url) { | ||
// TODO: use base url, cache on JS side | ||
return wasmFS.addBackend(std::make_unique<ProxiedAsyncJSBackend>( | ||
[](backend_t backend) { _wasmfs_create_fetch_backend_js(backend); })); | ||
} | ||
|
||
} // namespace wasmfs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.