Mercurial > public > mercurial-scm > hg-stable
comparison rust/hg-pyo3/src/utils.rs @ 52983:69d40a9778fe
pyo3: add a util to handle SIGINT from a long-running Rust function
This is going to be useful for the upcoming `update` module, and is the
transliteration of the util of the same name in `hg-cpython`. Explanations
are inline.
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Tue, 18 Feb 2025 11:44:21 +0100 |
parents | 0c7ac026ed63 |
children |
comparison
equal
deleted
inserted
replaced
52982:0c7ac026ed63 | 52983:69d40a9778fe |
---|---|
341 e => PyRuntimeError::new_err(e.to_string()), | 341 e => PyRuntimeError::new_err(e.to_string()), |
342 }) | 342 }) |
343 } | 343 } |
344 } | 344 } |
345 | 345 |
346 /// Wrap a call to `func` so that Python's `SIGINT` handler is first stored, | |
347 /// then restored after the call to `func` and finally raised if | |
348 /// `func` returns a [`HgError::InterruptReceived`]. | |
349 /// | |
350 /// We cannot use [`Python::check_signals`] because it only works from the main | |
351 /// thread of the main interpreter. To that end, long-running Rust functions | |
352 /// need to cooperate by listening to their own `SIGINT` signal and return | |
353 /// the appropriate error on catching that signal: this is especially helpful | |
354 /// in multithreaded operations. | |
355 pub fn with_sigint_wrapper<R>( | |
356 py: Python, | |
357 func: impl Fn() -> Result<R, HgError>, | |
358 ) -> PyResult<Result<R, HgError>> { | |
359 let signal_py_mod = py.import(intern!(py, "signal"))?; | |
360 let sigint_py_const = signal_py_mod.getattr(intern!(py, "SIGINT"))?; | |
361 let old_handler = signal_py_mod | |
362 .call_method1(intern!(py, "getsignal"), (sigint_py_const.clone(),))?; | |
363 let res = func(); | |
364 // Reset the old signal handler in Python because we may have changed it | |
365 signal_py_mod.call_method1( | |
366 intern!(py, "signal"), | |
367 (sigint_py_const.clone(), old_handler), | |
368 )?; | |
369 if let Err(HgError::InterruptReceived) = res { | |
370 // Trigger the signal in Python | |
371 signal_py_mod | |
372 .call_method1(intern!(py, "raise_signal"), (sigint_py_const,))?; | |
373 } | |
374 Ok(res) | |
375 } |