[Rd] Capturing signals from within external libs
Simon Urbanek
simon.urbanek at r-project.org
Wed May 23 18:49:33 CEST 2012
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