summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Sørvig <morten.sorvig@qt.io>2023-07-05 14:46:13 +0200
committerMorten Sørvig <morten.sorvig@qt.io>2023-07-10 05:13:56 +0200
commita4d1c30a1b52e797cce504f90bcf20d7943dd1f9 (patch)
treebc693b85bb1db721a6d6ce3a4781cd642ba49497
parent20d17b1a3b0e3a17a0ed1214cc21d84d79d3c829 (diff)
wasm: clarify qtloader onExit behavior
onExit is called whenever the application exits, i.e. when the app canvas should no longer be displayed and the loader/embedder code should take some action. Emscripten provides two callbacks which can be used here: - onExit, called when the app exits (but see EXIT_RUNTIME) - onAbort, called on abort errors. These map to the two cases Qt's onExit supports. onExit is not called when EXIT_RUNTIME is disabled, which means we don't need the special case for exit code 0. In addition call onExit on any exception. The second call to showUi() in html_shell.html is then not needed any more and we avoid duplicating the UI state handling in user code. Update the qtloader_integration test to handle changes in behavior (we no longer set the error text on exit). Use emscripten_force_exit() to simulate application exit - using this function makes Emscripten call onExit even when EXIT_RUNTIME is disabled. Pick-to: 6.6 Change-Id: I72b5463c1836e8d5054e594abbd304fbc67032b7 Reviewed-by: Piotr Wierciński <piotr.wiercinski@qt.io> Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
-rw-r--r--src/plugins/platforms/wasm/qtloader.js54
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html2
-rw-r--r--tests/manual/wasm/qtloader_integration/main.cpp4
-rw-r--r--tests/manual/wasm/qtloader_integration/test_body.js8
4 files changed, 32 insertions, 36 deletions
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
index 233e801e26..1b76d4ecc1 100644
--- a/src/plugins/platforms/wasm/qtloader.js
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -9,9 +9,14 @@
* - environment: { [name:string] : string }
* environment variables set on the instance
* - onExit: (exitStatus: { text: string, code?: number, crashed: bool }) => void
- * called when the application has exited for any reason. exitStatus.code is defined in
- * case of a normal application exit. This is not called on exit with return code 0, as
- * the program does not shutdown its runtime and technically keeps running async.
+ * called when the application has exited for any reason. There are two cases:
+ * aborted: crashed is true, text contains an error message.
+ * exited: crashed is false, code contians the exit code.
+ *
+ * Note that by default Emscripten does not exit when main() returns. This behavior
+ * is controlled by the EXIT_RUNTIME linker flag; set "-s EXIT_RUNTIME=1" to make
+ * Emscripten tear down the runtime and exit when main() returns.
+ *
* - containerElements: HTMLDivElement[]
* Array of host elements for Qt screens. Each of these elements is mapped to a QScreen on
* launch.
@@ -156,26 +161,14 @@ async function qtLoad(config)
return originalLocatedFilename;
}
- // This is needed for errors which occur right after resolving the instance promise but
- // before exiting the function (i.e. on call to main before stack unwinding).
- let loadTimeException = undefined;
- // We don't want to issue onExit when aborted
- let aborted = false;
- const originalQuit = config.quit;
- config.quit = (code, exception) =>
- {
- originalQuit?.(code, exception);
-
- if (exception)
- loadTimeException = exception;
- if (!aborted && code !== 0) {
- config.qt.onExit?.({
- text: exception.message,
- code,
- crashed: false
- });
- }
- };
+ const originalOnExit = config.onExit;
+ config.onExit = code => {
+ originalOnExit?.();
+ config.qt.onExit?.({
+ code,
+ crashed: false
+ });
+ }
const originalOnAbort = config.onAbort;
config.onAbort = text =>
@@ -207,10 +200,17 @@ async function qtLoad(config)
// Call app/emscripten module entry function. It may either come from the emscripten
// runtime script or be customized as needed.
- const instance = await Promise.race(
- [circuitBreaker, config.qt.entryFunction(config)]);
- if (loadTimeException && loadTimeException.name !== 'ExitStatus')
- throw loadTimeException;
+ let instance;
+ try {
+ instance = await Promise.race(
+ [circuitBreaker, config.qt.entryFunction(config)]);
+ } catch (e) {
+ config.qt.onExit?.({
+ text: e.message,
+ crashed: true
+ });
+ throw e;
+ }
return instance;
}
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
index 6be7956a3c..702ea1f59d 100644
--- a/src/plugins/platforms/wasm/wasm_shell.html
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -65,8 +65,6 @@
} catch (e) {
console.error(e);
console.error(e.stack);
- status.innerHTML = e.message;
- showUi(spinner);
}
}
</script>
diff --git a/tests/manual/wasm/qtloader_integration/main.cpp b/tests/manual/wasm/qtloader_integration/main.cpp
index b9bed0d49b..ee032e9952 100644
--- a/tests/manual/wasm/qtloader_integration/main.cpp
+++ b/tests/manual/wasm/qtloader_integration/main.cpp
@@ -71,7 +71,7 @@ void crash()
void exitApp()
{
- exit(ExitValueFromExitApp);
+ emscripten_force_exit(ExitValueFromExitApp);
}
void produceOutput()
@@ -135,7 +135,7 @@ int main(int argc, char **argv)
std::find(arguments.begin(), arguments.end(), QStringLiteral("--exit-immediately"))
!= arguments.end();
if (exitImmediately)
- return ExitValueImmediateReturn;
+ emscripten_force_exit(ExitValueImmediateReturn);
const bool crashImmediately =
std::find(arguments.begin(), arguments.end(), QStringLiteral("--crash-immediately"))
diff --git a/tests/manual/wasm/qtloader_integration/test_body.js b/tests/manual/wasm/qtloader_integration/test_body.js
index 233c64f2f6..f1285d617a 100644
--- a/tests/manual/wasm/qtloader_integration/test_body.js
+++ b/tests/manual/wasm/qtloader_integration/test_body.js
@@ -345,9 +345,7 @@ export class QtLoaderIntegrationTests
caughtException = e;
}
- // An exception should have been thrown from load()
- assert.equal('RuntimeError', caughtException.name);
-
+ assert.isUndefined(caughtException);
assert.equal(1, onExitMock.calls.length);
const exitStatus = onExitMock.calls[0][0];
assert.isTrue(exitStatus.crashed);
@@ -395,7 +393,7 @@ export class QtLoaderIntegrationTests
const exitStatus = onExitMock.calls[0][0];
assert.isFalse(exitStatus.crashed);
assert.equal(instance.EXIT_VALUE_FROM_EXIT_APP, exitStatus.code);
- assert.isNotUndefined(exitStatus.text);
+ assert.isUndefined(exitStatus.text);
}
async exitImmediately()
@@ -414,7 +412,7 @@ export class QtLoaderIntegrationTests
assert.isFalse(exitStatusFromOnExit.crashed);
assert.equal(instance.EXIT_VALUE_IMMEDIATE_RETURN, exitStatusFromOnExit.code);
- assert.isNotUndefined(exitStatusFromOnExit.text);
+ assert.isUndefined(exitStatusFromOnExit.text);
}
async userQuitCallbackCalled()