Skip to content

interrupting native code

12 messages · Kjell Konis, Brian Ripley, Simon Urbanek +1 more

#
Hello,

I have some native code that I would like to allow users to interrupt.  
However, I would like to do it more gracefully than with  
R_CheckUserInterrupt(). The solution I came up with is to call the  
following abort function periodically - if it returns 1 then I clean  
up and return.

int __WINAPI RlpSolveAbortFunction(lprec *lp, void *userhandle)
{
   if(R_interrupts_pending)
     return(1);

   return(0);
}

This seems to work fine on Mac (sans Aqua) and Linux. Is this going to  
be portable?  Also, is there anything else I need to do?  For instance  
set R_interrupts_pending to 0 after I respond to it?

Thanks.
Kjell
#
How is R_interrupts_pending going to be set?

It is set in the interrupt handler for SIGINT, but that is not the only 
way to indicate an interrupt, and it is not necessarily available to users 
of GUIs and embedded R.

Without servicing the GUIs all interaction will be dead, including sending 
an interrrupt from menus/buttons/keyboard.  See the comment in the code 
for R_CheckUserInterrupt.
On Thu, 15 May 2008, Kjell Konis wrote:

            

  
    
#
The problem is that my package uses an external pointer to keep track  
of a structure created by the lp_solve library. If I use  
R_CheckUserInterrupt in the lp_solve abort function it leaves the  
structure in a messed-up state after an interrupt occurs. I am not  
even able to free the memory allocated in the structure. I need to be  
able to tell the lp_solve functions to interrupt themselves if I am  
going to support interrupts at all.

I took a longer look at errors.c and it seems my solution should work  
as long as neither HAVE_AQUA nor Win32 are defined. Under the  
circumstances, I think that's the best I can do.

Any suggestions for a UI independent way to check for interrupts would  
be appreciated.

Thanks,
Kjell
On 15 mai 08, at 16:41, Prof Brian Ripley wrote:

            
#
On Fri, 16 May 2008, Kjell Konis wrote:

            
Why not use the same code as R_CheckUserInterrupt but instead of calling 
onintr, call your own interrupt routine?

  
    
#
You mean something like this (I return 1 instead of calling onintr())?  
Will HAVE_AQUA and Win32 be appropriately defined when building my  
package (I can't see how to check with R CMD config)?

int My_CheckUserInterrupt(void)
{
     R_CheckStack();

#if  ( defined(HAVE_AQUA) )

   /* R_ProcessEvents() from unix/aqua.c*/

   if (ptr_R_ProcessEvents)
     ptr_R_ProcessEvents();
   if (R_interrupts_pending)
     return(1);

#elseif ( defined(Win32) )

   /* R_ProcessEvents() from gnuwin32/system.c */

     while (peekevent()) doevent();
     if (UserBreak) {
	UserBreak = FALSE;
	return(1);
     }
     R_CallBackHook();
     if(R_tcldo) R_tcldo();

#else

     R_PolledEvents();
     if (R_interrupts_pending)
	return(1);

#endif

   return(0);
}
On 16 mai 08, at 12:43, Prof Brian Ripley wrote:

            
#
I'm not sure you can make this work as some of the things needed
either are or should be private to the core implementation and not
available to package code.  In any case I would not recommend this
approach for two reasons.  First, details of what happens in interrupt
checking are subject to change and your code would miss those changes
unless you track them carefully.  More importantly, several things
here could generate an error that results in a longjmp and leaves your
code in an unstable state.

What is needed for this is a mechanism for detecting an interrupt but
not doing the longjmp, just returning a flag that a longjmp is needed
and enough information to allow it to be made after cleanup code has
been run.  This has been on my to do list for a while but getting the
semantics right is tricky and so it hasn't happened yet.  Hopefully it
will be in 2.8.0.  In the interim you can cobble something together
using R_ToplevelExec, interpreting all FALSE return values as user
interrupts.

Another option, also under consideration but not available yet, is a C
mechanism for registering cleanup operations if a longjmp occurs.  A
quick and dirty version of that could be provided fairly easily but a
better version, which would be preferable in the long run, requires a
rewrite of the code that implements jumps and cleanup/on.exit actions.
This may take a bit longer to implement.

Best,

luke
On Fri, 16 May 2008, Kjell Konis wrote:

            

  
    
#
On Fri, 16 May 2008, Kjell Konis wrote:

            
HAVE_AQUA is in Rconfig.h, and WIN32 (not Win32) is defined for a package 
on Windows.

I think R_ProcessEvents() is available to you -- certainly on Windows.

  
    
4 days later
#
I would actually prefer a mechanism that simply returns a flag  
indicating that an interrupt has been requested. Then I would be able  
to clean up and return on my own - no longjmp required. Also, it would  
be useful if there was a function similar to R_ProcessEvents that only  
dealt with keeping the GUI responsive.

Cheers,
Kjell
On 16 mai 08, at 13:54, Luke Tierney wrote:

            
#
On May 20, 2008, at 10:58 AM, Kjell Konis wrote:

            
I don't understand what you mean by the last sentence - that is  
exactly what R_ProcessEvents is for - or am I missing something?

Cheers,

Simon
#
On Tue, 20 May 2008, Kjell Konis wrote:

            
Whether that makes sense depends on why the jump is being taken.  In
most cses I suspect that stopping the jump is OK but there may be
cases where it is not -- this is one of the issues that needs thinking
through.

luke

Also, it would be useful if there was

  
    
#
I have a structure from a library that I am using an external pointer  
to keep track of. The methods in this library (lp_solve) have the  
facility to call a function periodically and I would like to use  
R_ProcessEvents. The problem is that if an interrupt is requested then  
R returns to the command prompt without completing the library method.  
This leaves the structure in a messed-up state so that I can't even  
successfully delete it, potentially leaking a lot of memory. So what I  
am trying to do is find a way to see if an event has occurred (in this  
case an interrupt) so I can respond to it before onintr() gets called.

Kjell
On 20 mai 08, at 19:22, Simon Urbanek wrote:

            
#
If you are using an external pointer you can register a finalizer that
does the cleanup at gc time in case of an abnormal exit.  Otherwise
you should for now be able to use R_ToplevelExec tigether with
R_CheckUserInterrupt as I suggested previously.

Best,

luke
On Wed, 21 May 2008, Kjell Konis wrote: