diff options
author | Morten Sørvig <morten.sorvig@qt.io> | 2023-07-05 14:46:13 +0200 |
---|---|---|
committer | Morten Sørvig <morten.sorvig@qt.io> | 2023-07-10 05:13:56 +0200 |
commit | a4d1c30a1b52e797cce504f90bcf20d7943dd1f9 (patch) | |
tree | bc693b85bb1db721a6d6ce3a4781cd642ba49497 | |
parent | 20d17b1a3b0e3a17a0ed1214cc21d84d79d3c829 (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.js | 54 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/wasm_shell.html | 2 | ||||
-rw-r--r-- | tests/manual/wasm/qtloader_integration/main.cpp | 4 | ||||
-rw-r--r-- | tests/manual/wasm/qtloader_integration/test_body.js | 8 |
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() |