[Rd] Capturing signals from within external libs

Jeffrey Ryan jeff.a.ryan at gmail.com
Wed May 23 19:23:31 CEST 2012


Simon,

Very likely butchered my initial problem explanation. The issue is that I
make a call to a library, something like:

SEXP my_fun() {
...
CB = MyCallback("XYZ");  /* this contains callback functions that in turn
use R */
externalLibCall(CB);     /* infinite loop that won't return as it is
capturing streaming data */

/* we never get here */

Return(R_NilValue);
}

My callbacks look something like

on_event_A () {
  R_CheckUserInterrupt():
  evalRFunctionFromC();
}

But event_A only gets called when a new message arrives.  When a new
message arrives the on_event_A gets called from within the external
library code (hence calling R), but only when a message arrives.

At this point R_CheckUserInterrupt() works just fine.  The problem is when
the external process is waiting on a new message.  I have no entry to
check whether or not a message is available, nothing akin to select().
Basically I only get control in my callback when a new message happens.
So if there is no new message (in the context above it is a message/tick
from an exchange), the process spins/waits/not too sure what happens
internally, but the net result is I don't see anything.  I am waiting.  It
is at this point that I want to force an interrupt.

My current solution is just to redefine as my SIGINT handler before the
externalLibCall call, with an ungraceful exit() internal to it.  Dirty,
but lets me break. In the ideal world I would be returned to the R prompt,
but it isn't overly critical in this application since it is being run
more or less headless as is.

The other problem, which makes me cringe of course, is that this is all
further complicated by the fact that it is not just C, but C++ and running
on Win64 ;-)   I tried not to mention that of course ...

Your insights are very appreciated, and I now have further knowledge into
making this work in other applications, but my hope for this one is
dwindling.

Best,
Jeff


On 5/23/12 11:49 AM, "Simon Urbanek" <simon.urbanek at r-project.org> wrote:

>
>On May 23, 2012, at 12:40 PM, Jeffrey Ryan wrote:
>
>> Simon,
>> 
>> Thanks for the clarifying example.  I fear my current set up fails the
>> test for 'no R calls',
>
>Well, but in that case you already have interrupt points so I'm not sure
>what is the problem? I thought the whole point is that you have long
>processing in some 3rd party library where you can't call R API so that's
>why you need the hack in the first place ...
>
>
>> so I think I am stuck on the ugly variant for my
>> current challenge, but I will be able to use this in other places.
>> 
>> Thanks again,
>> Jeff
>> 
>> On 5/22/12 4:45 PM, "Simon Urbanek" <simon.urbanek at r-project.org> wrote:
>> 
>>> 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