-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Asyncify
ASYNCIFY allows you to use some asynchronous function in C, through several transformation of LLVM IR.
Note: this feature has not landed yet
If you call sleep() in C/C++, what kind of JavaScript code would you expect emscripten to produce?
// test.c
#include <stdio.h>
#include <unistd.h>
int main() {
int i = 100;
printf("Hello\n");
sleep(1);
printf("World %d!\n");
return 0;
}
Note that we cannot implement sleep like this:
function sleep(ms) {
var t = Date.now() + ms;
while(Date.now() < t) ;
}
because this would block the JavaScript engine, such that pending events cannot be processed.
A hand written counterpart in JavaScript would be
function main() {
var i = 100;
console.log('Hello');
setTimeout(function() {
console.log('World ' + i + '!');
async_return_value = 0;
}, 1000);
}
Specifically, a number of aspects should be taken into consideration:
- Split the function when an async function is called, and the second function should be registered as the callback for the async function
- Any function that calls an async function also becomes an async function.
- Keep all local variables available to the callback
- Closure cannot be used in order to make asm.js validated code.
- Take care of loops and branches
- Make the return value available to the callee
- Some functions could be both sync or async, depending on the input.
And the ASYNCIFY option does all above automatically, through a number of transformations on LLVM IR.
Call emscripten_sleep() whenever you need to pause the program, and add -s ASYNCIFY=1 to emscripten.
Sometimes it's a good replacement of emscripten_set_main_loop, you may replace all sleep-alike functions with emscripten_sleep, instead of refactoring the whole main loop.
Code size increase should be expected, depending on the specific input.
-Os (or -Oz for linking) is recommended when ASYNCIFY is turned on.
E.g. usually the following loop is expanded to speed up:
for(int i = 0; i < 3; ++i) {
// do something
emscripten_sleep(1000);
// do something else
}
However by expanding the loop, two more async calls are introduced, such that more callback functions will be produced during the asyncify transformation.
setjmp/longjmp and C++ exception are not working well when there are async function calls in the scope, but they still work when there's no async calls. E.g.
try {
// do something
if(error) throw 0; // works
emscripten_sleep(1000);
// do something else
if(error) throw 0; // does not work
}
- Closures (breaking asm.js)
- Generators (too slow currently)
- Blocking message (in workers)
class MyGroup(ExceptionGroup): def derive(self, excs): return MyGroup(self.message, excs)
e = MyGroup("eg", [ValueError(1), TypeError(2)]) e.add_note("a note") e.context = Exception("context") e.cause = Exception("cause") try: raise e except Exception as e: exc = e
match, rest = exc.split(ValueError) exc, exc.context, exc.cause, exc.notes
match, match.context, match.cause, match.notes
rest, rest.context, rest.cause, rest.notes
exc.traceback is match.traceback is rest.traceback