Closing a named in-process session blocks behind a pending wait instead of interrupting it. close_all() interrupts the same wait promptly.
Observed on Windows at commit 2d5f8020ba6eb77b9c4da38892c2f6f200311b90, while testing a new language binding against the existing Rust runtime.
Reproduction
- Start a named session with a program that stays alive.
- Start a text-locator wait for text that will never appear, with a 5-second timeout.
- While that wait is pending, close the same named session from another thread.
- Check whether close completes within 2 seconds.
The close operation misses the 2-second deadline and remains blocked behind the wait. Repeating the scenario with close_all() completes promptly.
Expected behavior
Closing one session should interrupt its pending wait and complete cleanup without waiting for the operation’s timeout, consistently with close_all().
Cause
SessionRegistry::execute holds the per-session generation mutex throughout operation execution, including waits.
Both SessionRegistry::close() and execute(Operation::Close) acquire that same mutex before reaching cleanup. They therefore cannot interrupt the operation holding it.
close_all() takes a different path: it calls session.interrupt() before closing sessions.
Regression coverage
A regression test should establish that the wait has entered the runtime before invoking close, then verify:
- both named-close entrypoints interrupt the wait promptly
- the session is removed and its retained recording remains accessible
- an existing handle can reopen the named session
- unrelated sessions remain open
This is in the shared Rust runtime. JavaScript and Python use the same named-session path, although the reproduction above was exercised through the new binding.
Closing a named in-process session blocks behind a pending wait instead of interrupting it.
close_all()interrupts the same wait promptly.Observed on Windows at commit
2d5f8020ba6eb77b9c4da38892c2f6f200311b90, while testing a new language binding against the existing Rust runtime.Reproduction
The close operation misses the 2-second deadline and remains blocked behind the wait. Repeating the scenario with
close_all()completes promptly.Expected behavior
Closing one session should interrupt its pending wait and complete cleanup without waiting for the operation’s timeout, consistently with
close_all().Cause
SessionRegistry::executeholds the per-session generation mutex throughout operation execution, including waits.Both
SessionRegistry::close()andexecute(Operation::Close)acquire that same mutex before reaching cleanup. They therefore cannot interrupt the operation holding it.close_all()takes a different path: it callssession.interrupt()before closing sessions.Regression coverage
A regression test should establish that the wait has entered the runtime before invoking close, then verify:
This is in the shared Rust runtime. JavaScript and Python use the same named-session path, although the reproduction above was exercised through the new binding.