---
title: "Checking for Interrupts"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Checking for Interrupts}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---


```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
knitr::knit_engines$set(callme = callme:::callme_engine)
library(callme)
```

```{css, echo=FALSE}
.callme         { background-color: #E3F2FD; }
pre.callme span { background-color: #E3F2FD; }
```

## 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.

```{callme}
#| invisible=TRUE
#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;
}
```


```{r eval=FALSE}
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.


```{callme}
#| compile=FALSE
#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;
}
```


```{r eval=FALSE}
interruptable_sleep2()
```