mirror of
https://github.com/logos-co/logos-view-module-runtime.git
synced 2026-08-27 11:01:13 +00:00
* feat(ui-host): give a view its chance to finish before teardown
ui-host deleted the plugin the instant app.exec() returned. Core modules
have had a grace period since the teardown hook shipped; views did not.
Calls the shared logos::runPluginAboutToUnload() (logos-plugin-qt#23)
between exec() returning and `delete pluginObject`. Safe to run a nested
event loop there: the application loop has already returned, so this is the
same shape as logos_host's call site rather than a re-entrant exec(). It
must come BEFORE the delete — it is the plugin it asks, and the plugin has
to still be alive to answer.
THE GRACE PERIOD IS 2000ms, NOT logos_host's 3000. That difference is the
reason the helper takes it as a parameter instead of owning a constant.
ViewModuleHost::stop() gives this process terminate() plus
waitForFinished(3000) before it resorts to kill(), and everything after the
signal has to fit inside that 3s: unwinding exec() through the self-pipe
notifier, this grace period, `delete pluginObject`, the QRemoteObjectHost
destructor unlinking the QtRO socket, and process exit. Porting 3000 would
have consumed the entire budget and left every async view hard-killed
mid-teardown — the precise failure the hook exists to prevent.
Measured, through the real ViewModuleHost driving the real ui-host binary:
no hook 0.001s dtor
async finishes 1.003s about-to-unload, tick x10, work-done, signalled, dtor
async hangs 1.903s about-to-unload, tick x19, dtor
All exit 0 — none hard-killed. The hang case costs 1.9s rather than 2.0
because the deadline is a default coarse QTimer, which Qt may fire up to 5%
early; that errs toward giving up sooner, the safe direction for a budget
carved out of someone else's kill timer.
The assertions are on ENTRY ORDER and relative tick counts, never elapsed
time: `work-done` before `dtor` proves the wait happened, the ticks prove a
nested loop actually ran, and hangTicks > finishTicks proves the deadline
outlasts a completion — i.e. that deadline.isActive() really does
distinguish "finished" from "gave up". Wall clock is asserted only where a
bound IS the contract (stopMs < 3000).
Negative control: removing the call fails 3 of the 4 tests, and correctly
leaves the no-hook one passing.
Two pins move forward, both required rather than incidental:
* logos-plugin-qt -> #23, which adds the helper. TODO: re-point at master
once it merges.
* logos-protocol f4407ff -> 7989472. plugin-qt follows THIS repo's
protocol, and its logos_qt_host_shared refuses to configure against one
that does not export logos_protocol_shared (protocol#65) — a deliberate
FATAL_ERROR, because the alternative is falling back to the archive and
reintroducing the duplicate singleton at runtime.
10/10 tests pass, UiHostUnloadTests included.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore(deps): track logos-plugin-qt master now that the helper has landed
logos-plugin-qt#23 merged as ef11c21, so the temporary rev pin goes. The
relocked narHash is identical to the branch tip this was pinned to, so
nothing about the build changes — only the pin.
The logos-protocol bump stays: plugin-qt follows THIS repo's protocol, and
its logos_qt_host_shared refuses to configure against one that does not
export logos_protocol_shared (protocol#65).
10/10 tests green, UiHostUnloadTests included.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
114 lines
5.7 KiB
Nix
114 lines
5.7 KiB
Nix
{
|
|
description = "logos-view-module-runtime — shared library for loading and running Logos UI modules";
|
|
|
|
inputs = {
|
|
logos-nix.url = "github:logos-co/logos-nix";
|
|
nixpkgs.follows = "logos-nix/nixpkgs";
|
|
logos-cpp-sdk = {
|
|
url = "github:logos-co/logos-cpp-sdk";
|
|
inputs.logos-nix.follows = "logos-nix";
|
|
};
|
|
# Master-tracking. This was rev-pinned to c8bab12 on
|
|
# feat/per-client-token-store because logos-qt-host (below) calls
|
|
# TokenManager::forIdentity / isolateIdentity, which were not yet on
|
|
# logos-protocol's master; since logos-plugin-qt's logos-protocol `follows`
|
|
# THIS input, a master-tracking pin would then have built the Qt host
|
|
# runtime against a protocol lacking those symbols.
|
|
#
|
|
# logos-protocol#59 ("per-client token store, the host-services C ABI, and
|
|
# a container shape-check") has since merged, which closes that gap:
|
|
# master (f4407ff) carries forIdentity / isolateIdentity in
|
|
# cpp/token_manager.h and lp_grant_host_services / lp_token_keys in
|
|
# cpp/logos_protocol.h, and its LOGOS_PROTOCOL_VERSION_MINOR reaches the
|
|
# level the cdylib glue's forwarding is guarded on. #59 was SQUASH-merged,
|
|
# so c8bab12 is not an ancestor of master even though every line of it is
|
|
# in master — verify by files, not by `git merge-base --is-ancestor`.
|
|
logos-protocol = {
|
|
url = "github:logos-co/logos-protocol";
|
|
inputs.logos-nix.follows = "logos-nix";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
# The Qt HOST RUNTIME this runtime links: LogosAPI (and, through it, the
|
|
# token manager and consumer core). The B1 split moved it out of
|
|
# logos-qt-sdk into logos-plugin-qt, which exports it as
|
|
# packages.<sys>.logos-qt-host with the CMake target
|
|
# logos-qt-host::logos_qt_host.
|
|
#
|
|
# logos-qt-sdk is deliberately NOT an input any more: the host runtime was
|
|
# the only thing this repo ever took from it. `logos_api.h` is the single
|
|
# qt-sdk-provided header anything here includes — every other non-Qt header
|
|
# (token_manager.h, logos_api_client.h, module_proxy.h, remote_transport.h,
|
|
# logos_instance.h, logos_mode.h, logos_types.h, logos_json_convert.h,
|
|
# logos_call_error.h, logos_object.h, logos_provider_interface.h) comes from
|
|
# logos-protocol, which logos-qt-host links PUBLIC. Nothing here touches the
|
|
# surface that stays behind in qt-sdk: no logos_ui_plugin_context.h (that is
|
|
# for ui_qml module backends, not for the host that loads them), no
|
|
# logos_qt_lp_bridge.h / logos_qt_wire.h, no logos-qt-generator.
|
|
#
|
|
# Master-tracking. This was rev-pinned to cc24fa1 (the tip of that repo's
|
|
# feat/b4-qt-host-windows-target) because `logos-qt-host` did not exist on
|
|
# logos-plugin-qt's master, then 8846fc5 — a master-tracking url failed to
|
|
# evaluate with "attribute 'logos-qt-host' missing" — and because that
|
|
# branch was the SUPERSET of the two rival branches carrying the work.
|
|
#
|
|
# logos-plugin-qt#19 ("the Qt host runtime and cdylib-glue generator") has
|
|
# since merged, which closes both gaps: master (9b2c64e) publishes
|
|
# packages.<sys>.logos-qt-host, keyed by forAllTargets so the x86_64-windows
|
|
# pseudo-system resolves as well, and with one master there is no longer a
|
|
# pair of rival branches to keep the downstream closure down to one host.
|
|
# #19 was SQUASH-merged, so cc24fa1 is not an ancestor of master even though
|
|
# its content is — verify by files, not by ancestry. (master also drops the
|
|
# repo's cmake/ directory, whose view-side templates moved to
|
|
# logos-view-module; nothing here ever consumed it.)
|
|
# Master-tracking again. This was briefly rev-pinned to logos-plugin-qt#23
|
|
# for cpp/logos_plugin_unload.h -- the shared host-side teardown helper
|
|
# ui-host calls below; that has merged (ef11c21).
|
|
logos-plugin-qt = {
|
|
url = "github:logos-co/logos-plugin-qt";
|
|
inputs.logos-nix.follows = "logos-nix";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
inputs.logos-protocol.follows = "logos-protocol";
|
|
};
|
|
};
|
|
|
|
outputs = { self, nixpkgs, logos-nix, logos-cpp-sdk, logos-protocol, logos-plugin-qt }:
|
|
let
|
|
# Adds the "x86_64-windows" pseudo-system. A cross derivation's `system`
|
|
# attr is its BUILD platform, so these evaluate anywhere and realise on
|
|
# x86_64-linux.
|
|
forAllSystems = f: logos-nix.lib.forAllTargets ({ system, pkgs }: f {
|
|
inherit system pkgs;
|
|
logosSdk = logos-cpp-sdk.packages.${system}.default;
|
|
logosQtHost = logos-plugin-qt.packages.${system}.logos-qt-host;
|
|
logosProtocol = logos-protocol.packages.${system}.default;
|
|
});
|
|
in
|
|
{
|
|
packages = forAllSystems ({ pkgs, logosSdk, logosQtHost, logosProtocol, ... }: {
|
|
default = import ./nix/default.nix { inherit pkgs logosSdk logosQtHost logosProtocol; };
|
|
tests = import ./nix/test.nix { inherit pkgs logosSdk logosQtHost logosProtocol; };
|
|
});
|
|
|
|
checks = forAllSystems ({ pkgs, logosSdk, logosQtHost, logosProtocol, ... }: {
|
|
default = import ./nix/test.nix { inherit pkgs logosSdk logosQtHost logosProtocol; };
|
|
});
|
|
|
|
devShells = forAllSystems ({ pkgs, logosSdk, logosQtHost, logosProtocol, ... }: {
|
|
default = pkgs.mkShell {
|
|
nativeBuildInputs = [ pkgs.cmake pkgs.ninja pkgs.pkg-config ];
|
|
buildInputs = [
|
|
pkgs.qt6.qtbase
|
|
pkgs.qt6.qtremoteobjects
|
|
pkgs.qt6.qtdeclarative
|
|
];
|
|
shellHook = ''
|
|
export LOGOS_CPP_SDK_ROOT="${logosSdk}"
|
|
export LOGOS_QT_HOST_ROOT="${logosQtHost}"
|
|
export LOGOS_PROTOCOL_ROOT="${logosProtocol}"
|
|
echo "logos-view-module-runtime dev shell"
|
|
'';
|
|
};
|
|
});
|
|
};
|
|
}
|