https://bz.mercurial-scm.org/show_bug.cgi?id=6961
Bug ID: 6961 Summary: fast update introduces hard incompatibility with HGitaly Product: Mercurial Version: unspecified Hardware: PC OS: Linux Status: UNCONFIRMED Severity: bug Priority: wish Component: Mercurial Assignee: bugzi...@mercurial-scm.org Reporter: georges.raci...@octobus.net CC: mercurial-de...@mercurial-scm.org Python Version: --- Seen on 6.9.3, as far as I can tell, the code is the same in 7.0rc0 This is a hard blocker for integration of Mercurial >= 6.9 in Heptapod All operations involving a working directory update crash in this way: File "/home/gracinet/heptapod/hdk/future/venv/lib64/python3.11/site-packages/mercurial/merge.py", line 2063, in _update updated_count = rust_update_mod.update_from_null( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib64/python3.11/signal.py", line 58, in signal handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ValueError: signal only works in main thread of the main interpreter The root cause is `update.rs` indeed installing a signal handler by calling back in the Python interpreter: /// Wrap a call to `func` so that Python's `SIGINT` handler is first stored, /// then restored after the call to `func` and finally raised if /// `func` returns a [`HgError::InterruptReceived`]. /// /// We cannot use [`Python::check_signals`] because it only works from the main /// thread of the main interpreter. To that end, long-running Rust functions /// need to cooperate by listening to their own `SIGINT` signal and return /// the appropriate error on catching that signal: this is especially helpful /// in multithreaded operations. pub fn with_sigint_wrapper<R>( py: Python, func: impl Fn() -> Result<R, HgError>, ) -> PyResult<Result<R, HgError>> { let signal_py_mod = py.import(intern!(py, "signal"))?; let sigint_py_const = signal_py_mod.getattr(intern!(py, "SIGINT"))?; let old_handler = signal_py_mod .call_method1(intern!(py, "getsignal"), (sigint_py_const.clone(),))?; let res = func(); // Reset the old signal handler in Python because we may have changed it signal_py_mod.call_method1( intern!(py, "signal"), (sigint_py_const.clone(), old_handler), )?; if let Err(HgError::InterruptReceived) = res { // Trigger the signal in Python signal_py_mod .call_method1(intern!(py, "raise_signal"), (sigint_py_const,))?; } Ok(res) } The problem is that HGitaly services are never in the main thread of the main interpreter, and that is forced on us by the gRPC server library itself: HGitaly does not try to be really multithreaded, the server starts with a threading of 1, but the server still runs all applicative code in a thread. HGitaly does have its SIGINT/SIGTERM handlers, that it sets up before launching the gRPC services. They are important for graceful shutdown, but I think we can live without the code above if that just means that a fast Rust update cannot be interrupted. Obviously, this cannot just be monkey-patched, so I'd need Mercurial core to provide more options (tweaking via environment variable would be just fine). If we have a solution in 7.0 (final), I can try and skip 6.9. -- You are receiving this mail because: You are on the CC list for the bug. _______________________________________________ Mercurial-devel mailing list Mercurial-devel@lists.mercurial-scm.org https://lists.mercurial-scm.org/mailman/listinfo/mercurial-devel