-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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)