Skip to content

fix: bound stalled CEF startup and shutdown (obs-studio#3833) - #19

Merged
zackees merged 3 commits into
masterfrom
fix/3833-browser-startup-timeout
Nov 7, 2026
Merged

zackees merged 3 commits into
masterfrom
fix/3833-browser-startup-timeout

Conversation

@zackees

@zackees zackees commented Nov 7, 2026 •

Copy link
Copy Markdown
Member

Refs obs-rust/obs-studio#3833.

When CefInitialize() never returns, Linux manager-thread unload now stops waiting after 5 seconds and logs the runtime CEF version. Startup independently warns once after 10 seconds; a CEF that finishes later can still recover. Actual initialization failure also warns once.

The timeout retains the manager thread, events and CEF state. A late initialization result parks before restoring signal handlers or touching OBS. The frontend prepares a private shutdown hook and calls its finalizer after normal Qt, OBS and platform cleanup, with its log flushed. Only this fatal case uses _Exit(0) before static CEF/thread destructors; the real-helper test verifies descendants exit after parent IPC closes. Hosts without that handshake log the limitation and exit immediately on timeout rather than returning through unsafe unload. Normal startup and failure keep the normal quit/join path. The companion obs-studio PR installs the frontend hook and updates the submodule/features ledger.

RED: 2de6932 interposes the real CEF 156.0.14 cef_initialize in a real obs-browser module linked to hybrid libobs. Normal immediate unload (initialize and source modes) and a released slow initializer passed. An initializer never released stayed silent, then OBS shutdown exceeded the 12-second subprocess bound. Evidence was rerun in a fresh build after a pool checkout collision; no result from the collision window is used.

Reproduction: uv run tests/stalled_initialization.py --include-dir <obs>/libobs --include-dir <build>/config --library-dir <build>/libobs --module <staged>/obs-browser.so --data data --output-dir <fresh-dir> under Xvfb with the build's library paths. The new C fixture also checks that a stalled initialization never reaches static destructors; the helper case must verify actual CEF descendants exit.

GREEN: 4ba3c02 built the real Linux module and helper against pinned CEF 156.0.14 and hybrid libobs. Under Xvfb, both unchanged immediate-unload modes passed; actual profile-lock initialization failure passed with exactly one warning. All four interposition cases passed: released slow start, never-returning init, a stall after real CEF created helpers, and recovery after the startup warning. Shutdown stayed within the 12-second subprocess bound, actual helper pidfds signaled exit within 5 seconds, and the static-destructor sentinel was bypassed. The CEF-independent production handshake passed 100 runs, including late return after abandonment. Parent browser tests: 4 passed. Read-only clud-review: clean, with its own 100-run handshake replay.

Not exercised: the Arch CEF 152.0.6 installation or the full GUI; this deliberately uses Refs, not Fixes. The production module and real CEF were exercised through the lifecycle fixture, including the same private frontend hooks. No CEF version-support decision is made. This is a C++ bug fix, not a Rust port; Rust port tiers do not apply. Existing C tests, public headers, WebSocket and workflows are unchanged.

@zackees
zackees marked this pull request as ready for review November 7, 2026 08:02
@zackees
zackees merged commit 21d6bba into master Nov 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant