rust/hg-pyo3/src/utils.rs
changeset 52978 69d40a9778fe
parent 52977 0c7ac026ed63
equal deleted inserted replaced
52977:0c7ac026ed63 52978: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 }