Re: [Rd] Capturing signals from within external libs

From: Jeffrey Ryan <jeff.a.ryan_at_gmail.com>
Date: Wed, 23 May 2012 12:23:31 -0500


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



R-devel_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Wed 23 May 2012 - 17:27:49 GMT

This quarter's messages: by month, or sorted: [ by date ] [ by thread ] [ by subject ] [ by author ]

All messages

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Thu 24 May 2012 - 10:11:47 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-devel. Please read the posting guide before posting to the list.

list of date sections of archive