embed: add tacky_destroy_wait, a destroy bounded by the host #7
Loading…
Reference in a new issue
No description provided.
Delete branch "asxpi/libtacky:fix/destroy-wait"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The bug. another.im's desktop app (0.5.4 to 0.5.7, Flatpak) segfaults every time it quits. Closing the window hangs for ~15 s while systemd writes the core dump, and the backend's last store transaction may be lost. Symbolized with the app's debug extension and
org.gnome.Sdk.Debug//50:Why. The app's
RunEvent::Exitdrops the backend (tacky_destroy), and Tauri callsprocess::exit()as soon as that returns.tacky_destroywaits two seconds (TACKY_REAP_MS) and then returns, leaving a slower destroy to finish on its own (embed/tacky.h). With three accounts the destroy outlasts the bound: the accounts shut down one after another, and the stop is deferred while a request with a nested event loop is on the stack (StopEventProc,t->depth > 0). So the process exits while the backend is still committing, and the commit dies under the exit handlers. The same frame shows up at every quit in every build I ran today.The change.
tacky_destroy_wait(tacky *t, unsigned int max_ms)istacky_destroywith the host's own bound,0for none. A host about to end its process can now wait for the destroy to finish. A host that destroys a backend and carries on keeps the two-second bound.tacky_destroy(t)is nowtacky_destroy_wait(t, TACKY_REAP_MS), so its behaviour is unchanged.Reaptakes the bound as a parameter.Tests.
embed_host's hooked cases gainstall waitedandstall unbounded: the existing 3 s stop script, destroyed with a 6 s bound and with none. Each returns only once the destroy has ended, the stop script's late emit reaches the host before the call returns, and nothing arrives after.make test-embed-host: all cases pass.README.md,docs/using.mdandROBOTS.mdname the new call.What a host does with it. another.im's shell should hide the window, then call
tacky_destroy_waitwith a generous bound (not 0, so a wedged backend can't hold the quit forever) before Tauri exits. That's a small follow-up in anotherim-js, sent once this is in.🤖 Generated with Claude Code
tacky_destroy waits two seconds (TACKY_REAP_MS) for the backend's destroy and then returns, leaving a slower one to finish on its own with the callback disarmed. That is right for a host that destroys a backend and carries on, but not for one about to end its process: the destroy is still running when the process exits, and exit tears down state it still uses. another.im's desktop app quits exactly so. With three accounts its destroy outlasts the bound (a stop held by a request in flight, the accounts shut down one after another), Tauri's event loop calls process::exit() as soon as tacky_destroy returns, and the backend's last store commit crashes in SQLCipher under the exit handlers, every time the app quits: BackendThread -> StopEventProc -> DbTransPostCmd -> sqlite3_exec -> walWriteOneFrame -> sqlite3Codec SIGSEGV main: tao event loop -> std::process::exit -> __run_exit_handlers Add tacky_destroy_wait(t, max_ms): tacky_destroy with the host's own bound, 0 for none, so a quitting host can wait for the destroy to end. tacky_destroy is tacky_destroy_wait(t, TACKY_REAP_MS) and is unchanged. Reap takes the bound as a parameter. embed_host's hooked cases gain stall waited and stall unbounded: the 3 s stop script waited for with a 6 s bound and with none, its late emit reaching the host before the call returns and nothing after. README, docs/using.md and ROBOTS.md name the call. Assisted-by: Claude:opus-5-5Merged into develop by hand as
0cffcae7(merge of5fc35e36plus the review fixes,246294ac, pushed as fix/destroy-wait-review), pushed 2026-10-16. Review summary: the change is right, and under it sat an older bug that explains the crash without any slow destroy: Reap counted each wake-up as 100 ms and every emit woke it, so a destroy that emitted twenty times used up tacky_destroy's two seconds at once and returned with the destroy still running. The bound is now a clock deadline (Tcl_GetTime), 0 still no bound; tacky.h states the contract only and says 0 never returns from a destroy that never ends, so a quitting host passes a generous finite bound; tackyd-json waits up to 15 s; make host-swift wraps tacky.h (the Swift wording and ios-check's "three" fixed); stop_wait moved under TACKY_TEST_HOOKS. New embed_host cases: chatty destroy (30 emits during the destroy under plain tacky_destroy; 96 ms and the late emit lost before the fix, 1.66 s and seen after) and stall bounded (destroy_wait 500 against the 3 s stall). Gate on develop: Tcl unit suite 5526 passed (one known test_omemo_devices load flake, 44/44 alone), embed_host and hooks PASS, check-api/headers/native-neutral clean. Thank you for the report and the trace.Pull request closed