# Checking for Interrupts

## Introduction

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()` example

In 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;
    }

Click to show R code

    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)

    interruptable_sleep()

## Continuing C execution after the interrupt

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;
    }

Click to show R code

    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)

    interruptable_sleep2()