Keep the argument tuple owned by varfunc for its full per-call lifetime.
ConvertFunc destroys varfunc before ScopedFuncCall, so the tuple is released
exactly once while the GIL is still held, including failed callbacks.
Clear the argument tuple after calling a Python callback so varfunc's
destructor cannot decrement it a second time. This prevents repeated
zero-argument callbacks from losing references to the shared empty tuple.
Skip callback reference cleanup after Python has shut down, since Qt can
destroy pending callback closures during QApplication teardown.
Validation:
- Regression harness using this header and bundled Python 3.6.4: 20,000
callbacks with balanced references, nonempty arguments, exception paths,
deferred release, and callback destruction after Py_Finalize.
- Windows x64 Release build: no warnings or errors.
- MI 8 remote replay: 1.rdc -> 2.rdc -> 1.rdc -> 2.rdc; normal exit with
a pending callback, exit code 0.
Build and device checks used the existing development checkout, which also
contains separate local changes excluded from this commit.
* Anything obtained via the aliased interfaces will act as if it's a List[], but
any globals from the repl will be rdcarray typed so we need to handle looking
up the 'real' type for that.
* This helps with type checkers to know that things can be None or not (both to
silence previous warnings about "unnecessary" checks that are actually
necessary, and to ensure those checks aren't omitted by accident)
* During capture shutdown on Python < 3.13 the replay thread will try to remove
itself as a debuggable thread which requires being able to run python (holding
the GIL). If the UI thread is the one triggering the capture shutdown and is
running a call from a python script it may hold the GIL while waiting for the
replay thread to close, deadlocking.
* To alleviate this, while the UI thread is about to block on the replay thread
we try to release the python state if we are holding it so that the replay
thread can run python code if needed.
* We already do this in a manual wrapper around BlockInvoke.