Skip to content

Instantly share code, notes, and snippets.

@corwin-of-amber
Last active October 21, 2019 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save corwin-of-amber/8f71f66a4c8c483beb813f6eb870f65e to your computer and use it in GitHub Desktop.
Save corwin-of-amber/8f71f66a4c8c483beb813f6eb870f65e to your computer and use it in GitHub Desktop.
A utility library for coroutines in Emscripten (using Asyncify)
emcc example.c -s ASYNCIFY \
-s ASYNCIFY_IMPORTS='["emscripten_sleep","emscripten_yield","emscripten_coroutine_create","emscripten_coroutine_next"]' \
--js-library library_coroutine.js
#include <stdio.h>
#include <emscripten.h>
void cofunc(void *data) {
printf("co: 1\n");
emscripten_yield();
printf("co: 2\n");
emscripten_yield();
printf("co: 3\n");
}
int main(int argc, char **argv) {
emscripten_coroutine co = emscripten_coroutine_create(cofunc, NULL, 64 * 1024);
printf("main: 1\n");
emscripten_coroutine_next(co);
printf("main: 2\n");
emscripten_coroutine_next(co);
printf("main: 3\n");
emscripten_coroutine_next(co);
printf("-------\n");
}
mergeInto(LibraryManager.library, {
$Coroutines__deps: ["Asyncify_restoreState"],
$Coroutines: {
main: null, live: [], active: null,
allocate: function(obj) {
id = this.live.length;
this.live[id] = obj;
return id;
},
free: function(id) {
delete this.live[id];
},
resume: function(co) {
_Asyncify_restoreState(co.savedState);
co.jump();
},
return: function(id) {
this.free(id);
this.resume(this.main);
}
},
assign$: function(to, from) { for (let k in from) to[k] = from[k]; },
Asyncify_saveState: function() {
return {currData: Asyncify.currData};
},
Asyncify_restoreState__deps: ["assign$"],
Asyncify_restoreState: function(savedState) {
_assign$(Asyncify, savedState);
},
emscripten_coroutine_create__deps: ["$Coroutines"],
emscripten_coroutine_create: function(funcptr, data, size) {
return Coroutines.allocate(
{jump: () => Module.asm.dynCall_vi(funcptr, data), savedState: {}});
},
emscripten_coroutine_next__deps: ["$Coroutines", "Asyncify_saveState"],
emscripten_coroutine_next: function(id) {
co = Coroutines.live[id];
return Asyncify.handleSleep((wakeUp) => {
setTimeout(() => {
Coroutines.main = {jump: wakeUp, savedState: _Asyncify_saveState()};
Coroutines.active = co;
Coroutines.resume(co);
if (!Asyncify.currData) Coroutines.return(id);
});
});
},
emscripten_yield__deps: ["assign$", "Asyncify_saveState"],
emscripten_yield: function() {
return Asyncify.handleSleep((wakeUp) => {
setTimeout(() => {
_assign$(Coroutines.active,
{jump: wakeUp, savedState: _Asyncify_saveState()});
Coroutines.resume(Coroutines.main);
});
});
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment