false,
global,
this._inst.exports.mem,
- () => { // resolveCallbackPromise
- if (this.exited) {
- throw new Error("bad callback: Go program has already exited");
- }
- setTimeout(this._resolveCallbackPromise, 0); // make sure it is asynchronous
- },
+ this,
];
this._refs = new Map();
+ this._callbackShutdown = false;
this.exited = false;
const mem = new DataView(this._inst.exports.mem.buffer)
while (true) {
const callbackPromise = new Promise((resolve) => {
- this._resolveCallbackPromise = resolve;
+ this._resolveCallbackPromise = () => {
+ if (this.exited) {
+ throw new Error("bad callback: Go program has already exited");
+ }
+ setTimeout(resolve, 0); // make sure it is asynchronous
+ };
});
this._inst.exports.run(argc, argv);
if (this.exited) {
go.env = process.env;
go.exit = process.exit;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
- process.on("exit", () => { // Node.js exits if no callback is pending
- if (!go.exited) {
- console.error("error: all goroutines asleep and no JavaScript callback pending - deadlock!");
- process.exit(1);
+ process.on("exit", (code) => { // Node.js exits if no callback is pending
+ if (code === 0 && !go.exited) {
+ // deadlock, make Go print error and stack traces
+ go._callbackShutdown = true;
+ go._inst.exports.run();
}
});
return go.run(result.instance);
}).catch((err) => {
- console.error(err);
- go.exited = true;
- process.exit(1);
+ throw err;
});
}
})();
var pendingCallbacks = Global().Get("Array").New()
var makeCallbackHelper = Global().Call("eval", `
- (function(id, pendingCallbacks, resolveCallbackPromise) {
+ (function(id, pendingCallbacks, go) {
return function() {
pendingCallbacks.push({ id: id, args: arguments });
- resolveCallbackPromise();
+ go._resolveCallbackPromise();
};
})
`)
callbacks[id] = fn
callbacksMu.Unlock()
return Callback{
- Value: makeCallbackHelper.Invoke(id, pendingCallbacks, resolveCallbackPromise),
+ Value: makeCallbackHelper.Invoke(id, pendingCallbacks, jsGo),
id: id,
}
}
var callbackLoopOnce sync.Once
func callbackLoop() {
- for {
+ for !jsGo.Get("_callbackShutdown").Bool() {
sleepUntilCallback()
for {
cb := pendingCallbacks.Call("shift")
}
var (
- valueNaN = predefValue(0)
- valueUndefined = predefValue(1)
- valueNull = predefValue(2)
- valueTrue = predefValue(3)
- valueFalse = predefValue(4)
- valueGlobal = predefValue(5)
- memory = predefValue(6) // WebAssembly linear memory
- resolveCallbackPromise = predefValue(7) // function that the callback helper uses to resume the execution of Go's WebAssembly code
+ valueNaN = predefValue(0)
+ valueUndefined = predefValue(1)
+ valueNull = predefValue(2)
+ valueTrue = predefValue(3)
+ valueFalse = predefValue(4)
+ valueGlobal = predefValue(5)
+ memory = predefValue(6) // WebAssembly linear memory
+ jsGo = predefValue(7) // instance of the Go class in JavaScript
)
// Undefined returns the JavaScript value "undefined".