[Rd] Capturing signals from within external libs

Simon Urbanek simon.urbanek at r-project.org
Tue May 22 23:45:34 CEST 2012


Jeff,

On May 22, 2012, at 4:31 PM, Jeffrey Ryan wrote:

> I have a continuous loop running in an external library that I am calling
> from C (R API).  This loop is processing events in real time with the
> possibility of significant lag between events.
> 
> When processing an event, I can make use of R_CheckUserInterrupt, but
> while the external library code is waiting on a new event, I don't have an
> opportunity to call this - my entry points are only on events.
> 

Assuming that while in the library there are no R calls (important!), you can use setjmp/longjmp to branch your code depending on whether you raise an interrupt or not (see below). This also makes sure that you process things on the R side properly

Another alternative is to run your library call on a separate thread and have R wait for the result. In that case you don't need to mess with interrupts since your library code will run separately from R. The downside is that you need to mess with threads which may or may not be an issue depending on the complexity of your code and whether you want it to be cross-platform or not.

Cheers,
Simon


Example code:

#include <signal.h>
#include <setjmp.h>
#include <unistd.h>

#include <Rinternals.h>
#include <R_ext/GraphicsEngine.h> /* only needed if you use R_interrupts_pending */

static jmp_buf jenv;

static void my_int(int sig) {
  longjmp(jenv, 1); /* this also restores the interrupt handlers */
}

SEXP my_R_function(...) {

if (setjmp(jenv) == 0) { /* enter your protected code */
  void (*old_sig)(int);
  old_sig = signal(SIGINT, my_int);
  /* call your library here */
  /* restore original INT handler */
 signal(SIGINT, old_sig);
} else { /* this will get called on interrupt */
  /* you can do what you want - you're back to R-safe code here, so you can either raise an error or return from your function */
  /* if you want to trigger regular R interrupt handling, use this: */
   R_interrupts_pending = 1;
   R_CheckUserInterrupt();
  /* the above should not return */
}



> I can capture a SIGINT by redefining signal(SIGINT, myhandler) before
> calling the lib, but I am somewhat at a loss in terms of what I can do
> within the handler that would let me pass control back to R.
> 
> void myhandler (int s) {
>  error("interrupt caught!");
> }
> 
> Works, but I am sure it isn't supposed to.  In fact I know it is wrong,
> since after interrupting once SIGINTs are subsequently ignored, even if I
> reset the signal to the original one (as returned by the first call to
> signal).
> 
> Currently I can exit(1) of course, but that is tragically bad form IMO,
> though will work in my situation.
> 
> In short, what is the proper way to handle SIGINT in external code that is
> called from R, that allows R to handle the signal.  Thoughts or
> suggestions appreciated.
> 
> Thanks,
> Jeff
> 
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
> 
> 



More information about the R-devel mailing list