Skip to content

Commit

Permalink
method to handle signals/interrupts in long-running foreign code
Browse files Browse the repository at this point in the history
  • Loading branch information
matko committed Feb 20, 2024
1 parent 346631c commit 837b44a
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
16 changes: 16 additions & 0 deletions examples/swipl-module-example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use swipl::prelude::*;
use std::cmp::Ordering;
use std::io::{self, Write};
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;

predicates! {
semidet fn unify_with_foo(_context, term) {
Expand Down Expand Up @@ -112,6 +114,18 @@ predicates! {

context.try_or_die(writeln!(stream, "こんにちは! 🫡"))
}

semidet fn sleep_n_secs(context, n_term) {
let n: u64 = n_term.get_ex()?;
for _ in 0..n {
sleep(Duration::from_secs(1));
// this handle_signals ensures that every second the user
// is able to safely interrupt this sleep.
context.handle_signals()?;
}

Ok(())
}
}

#[arc_blob("moo")]
Expand Down Expand Up @@ -161,4 +175,6 @@ pub extern "C" fn install() {
register_unify_with_bar_baz();

register_stream_write_hello();

register_sleep_n_secs();
}
26 changes: 26 additions & 0 deletions swipl/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,32 @@ impl<'a, T: ContextType> Context<'a, T> {
WritablePrologStream::new(current_output)
}
}

/// Handle any outstanding synchronous signals, including user interrupts.
///
/// This could return PrologError::Exception, which should
/// normally be propagated all the way back to SWI-Prolog. In
/// particular, the raised exception will be a term containing the
/// atom '$aborted' for the case where a user interrupts.
///
/// This should be regularly called for long-running foreign code.
/// SWI-Prolog handles signals synchronously at safe points, and
/// therefore will never do so while a foreign predicate is
/// running. The most visible outcome of this is that long-running
/// predicates can normally not be interrupted by the user when
/// they press ctrl-c once.
///
/// On success, the number of outstanding signals handled is
/// returned.
pub fn handle_signals(&self) -> PrologResult<u32> {
let result: i32 = unsafe { PL_handle_signals() };

if result == -1 {
Err(PrologError::Exception)
} else {
Ok(result as u32)
}
}
}

trait ContextParent {
Expand Down

0 comments on commit 837b44a

Please sign in to comment.