--- 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 #include #include // 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 #include #include // for 'sleep()' #include //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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() ```