It is considered good practice to allow C code to be interupted if it runs for an extended period.
R_CheckUserInterrupt()
checks whether the user is trying
to interrupt (using ctrl-c
or similar) and will immediately
abort the execution of the code.
R_CheckUserInterrupt()
exampleIn the folowing example, when interrupted, the Rprintf()
and return
statements will not be executed. Control will
immediately return to the user’s R session.
#include <R.h>
#include <Rinternals.h>
#include <unistd.h> // for 'sleep()'
SEXP interruptable_sleep(void) {
while (1) {
R_CheckUserInterrupt(); // abort if user interrupts. no recovery.
sleep(1);
}
Rprintf("Never get here! Interrupt causes immediate exit!");
return R_NilValue;
}
code = r"(
#include <R.h>
#include <Rinternals.h>
#include <unistd.h> // for 'sleep()'
SEXP interruptable_sleep(void) {
while (1) {
R_CheckUserInterrupt(); // abort if user interrupts. no recovery.
sleep(1);
}
Rprintf("Never get here! Interrupt causes immediate exit!");
return R_NilValue;
}
)"
callme::compile(code)
You may also wish to continue execution of the C code after the interrupt (e.g. to tidy and free any resources).
In this example the Rprintf()
statment and
return
will be executed following the interuption.
#include <R.h>
#include <Rinternals.h>
#include <unistd.h> // for 'sleep()'
#include <stdbool.h>
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// As suggested by Simon Urbanek
// https://stat.ethz.ch/pipermail/r-devel/2011-April/060702.html
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static void check_interrupt_internal(void *dummy) {
R_CheckUserInterrupt();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// this will call the above in a top-level context so it won't
// longjmp-out of your context
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool check_interrupt(void) {
return (R_ToplevelExec(check_interrupt_internal, NULL) == FALSE);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Your code goes here
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP interruptable_sleep2(void) {
while (1) {
if (check_interrupt()) break; // break out of while(). Keep executing
sleep(1);
}
Rprintf("My sleep was interrupted!\n");
return R_NilValue;
}
code = r"(
#include <R.h>
#include <Rinternals.h>
#include <unistd.h> // for 'sleep()'
#include <stdbool.h>
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// As suggested by Simon Urbanek
// https://stat.ethz.ch/pipermail/r-devel/2011-April/060702.html
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static void check_interrupt_internal(void *dummy) {
R_CheckUserInterrupt();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// this will call the above in a top-level context so it won't
// longjmp-out of your context
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool check_interrupt(void) {
return (R_ToplevelExec(check_interrupt_internal, NULL) == FALSE);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Your code goes here
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP interruptable_sleep2(void) {
while (1) {
if (check_interrupt()) break; // break out of while(). Keep executing
sleep(1);
}
Rprintf("My sleep was interrupted!\n");
return R_NilValue;
}
)"
callme::compile(code)