[Rd] sending signals to embedded R

deepayan.sarkar at gmail.com deepayan.sarkar at gmail.com
Mon May 7 02:57:04 CEST 2007


On 5/6/07, Jeffrey Horner <jeff.horner at vanderbilt.edu> wrote:
> Luke Tierney wrote:

[...]

> >> Is there a reason R_ProcessEvents cannot be set on Unix but can on
> >> Mac? It doesn't seem user-settable on Windows, but whatever the built
> >> in default is seems to handle the Qt event loop. And for that matter,
> >> why is it possible to set the file.edit callback on Mac but not Linux?
> >> This seems arbitrary, and no explanation is given (that I could find).
> >
> > The R_PRocessEvents callback may be settable on MacOS but I'm not sure
> > it's used -- at least a quick grep didn't reveal its use anywhere
> > outside the gnuwin32 code.

I meant the callback ptr_R_ProcessEvents (in Rinterface.h).  The Mac
GUI source has (this is probably not the latest version):

dsarkar at kanika:~/Mac-GUI-1.17$ grep -i ptr_r_process */*
REngine/Rinit.c:extern void (*ptr_R_ProcessEvents)();
REngine/Rinit.c:    ptr_R_ProcessEvents =  Re_ProcessEvents;

and R/trunk/src/unix/aqua.c has:

void R_ProcessEvents(void)
{
    if(!useaqua){
        if (R_interrupts_pending)
            onintr();
        return;
    } else
        ptr_R_ProcessEvents();
}

> > It would be good to unify the Mac and *nix mechanisms here since the
> > OS underpinings are now so similar, but it will have to get high
> > enough on someone's priority list to happen.

[...]

> >> The problem I'm having with this solution is that whenever I interrupt
> >> a graphics command, R crashes. This is true for commands being
> >> evaluated by R_tryEval, but not those run from the REPL (for example,
> >> if I make the call inside a debug() environment, interrupting it
> >> causes no problems). As far as I can tell, this is only a problem with
> >> graphics; other commands can be interrupted even when run using
> >> R_tryEval().
> >
> > That sounds like a longjmp being done to a place that doesn't exist --
> > maybe a threading issue in Qt.  See what gdb tells you about where the
> > crash is occurring. It might be different for onintr and kill.  You
> > might also try just setting the R_interrupts_pending flag from the
> > interrupt event handler rather than calling onintr (which probably
> > longjmp's) or kill (which may be doing something you don't want if
> > other threads with other signal handlers are involved).


I will have to start learning about gdb sometime soon, but in this case, the
problem seems to be due to the interaction of R_tryEval() and
graphics, and has nothing to do with interruptions.  Here's a variant
of the trEval test case that triggers a legitimate error caused by

grid.text('foo', gp = gpar(font=1, fontface=1))

dsarkar at kanika:~$ cat tryEvalGraphics.c ## beware of line wrapping

/*
   Compile this as:

RPROG=R-devel

export LD_LIBRARY_PATH=`${RPROG} RHOME`/lib:\${LD_LIBRARY_PATH}
gcc `${RPROG} CMD config --cppflags` \
    `${RPROG} CMD config --ldflags`  \
    -o tryEvalGraphics tryEvalGraphics.c

 */


#include <Rinternals.h>
#include <Rembedded.h>

#include <R_ext/Parse.h>


int
main(int argc, char *argv[])
{
    SEXP e, val;
    int i, errorOccurred;
    ParseStatus status;
    char *cmds[] = {
        "library(lattice)",
        "library(grid)",
        "grid.text('foo', gp = gpar(font=1, fontface=1))",
        "xyplot(1 ~ 1, panel = function() grid.text('foo', gp =
gpar(font=1, fontface=1)))"
    };

    argv[0] = "R";
    Rf_initEmbeddedR(argc, argv);

    for (i = 0; i < 4; i++) {
        printf("** I **: Executing command: %s\n", cmds[i]);
        fflush(stdout); sleep(1);
        PROTECT(e = R_ParseVector(mkString(cmds[i]), -1, &status, R_NilValue));
        val = R_tryEval(VECTOR_ELT(e, 0), NULL, &errorOccurred);
        if (errorOccurred) { Rprintf("Error executing: %s\n", cmds[i]); }
        else Rf_PrintValue(val);
        UNPROTECT(1);
        printf("** I **: Succeeded\n");
        fflush(stdout); sleep(1);
    }

    Rf_endEmbeddedR(0);
    return(0);
}


Running this, I get:


dsarkar at kanika:~$ R-devel CMD ./tryEvalGraphics

R version 2.6.0 Under development (unstable) (2007-05-04 r41439)

[...]

[Previously saved workspace restored]

** I **: Executing command: library(lattice)
[1] "stats"     "graphics"  "grDevices" "utils"     "datasets"  "lattice"
[7] "rcompgen"  "methods"   "base"
** I **: Succeeded
** I **: Executing command: library(grid)
 [1] "grid"      "stats"     "graphics"  "grDevices" "utils"     "datasets"
 [7] "lattice"   "rcompgen"  "methods"   "base"
** I **: Succeeded
** I **: Executing command: grid.text('foo', gp = gpar(font=1, fontface=1))
Error in validGP(list(...)) : Must specify only one of 'font' and 'fontface'
Error executing: grid.text('foo', gp = gpar(font=1, fontface=1))
** I **: Succeeded
** I **: Executing command: xyplot(1 ~ 1, panel = function()
grid.text('foo', gp = gpar(font=1, fontface=1)))
Error in validGP(list(...)) : Must specify only one of 'font' and 'fontface'

 *** caught segfault ***
address 0x22000440, cause 'memory not mapped'

Possible actions:
1: abort (with core dump, if enabled)
2: normal R exit
3: exit R without saving workspace
4: exit R saving workspace
Selection: 3
dsarkar at kanika:~$

Note that the first error (which doesn't actually get around to
starting a device) is handled properly, while the second is not.

[...]


> Deepayan, this is your code from quter-20070502 below, where R_tryEval
> is called:
>
>      PROTECT(cmdSexp = mkString(cmd));
>      PROTECT(cmdExpr = R_ParseVector(cmdSexp, -1, &status, R_NilValue));
>      if (status == PARSE_OK) {
>          int i, errorOccurred;
>          for(i = 0; i < length(cmdExpr); i++) {
>          ans = R_tryEval(VECTOR_ELT(cmdExpr, i),
>                  NULL, &errorOccurred);
>      }
>      if (errorOccurred) ans = R_NilValue;
>      UNPROTECT(2);
>
> Question: is each element of cmdExpr actually on the protection stack?
> Or rather, is the caller guaranteed that the cmdExpr element will not be
> garbage collected? My assumption is yes, since cmdExpr is, but I could
> be wrong.

Normally I would say yes, because my understanding is that
sub-elements of protected SEXP's are supposed to be automatically
protected. But I don't really know what happens when there is an
error. On the other hand, I haven't been seeing any errors (other than
the graphics one described above) recently with that code.

One possibly relevant factoid: a few days ago I was trying to play
with R_topLevelExec(), and that seemed to require an extra UNPROTECT()
for no reason (there's a similar hack in rkward). I sort of got it
working, but two consecutive errors reproducibly took me to a
situation where the same error message would get repeated whatever I
did after that. I didn't pursue this because I figured out an
alternative solution to my problem.

-Deepayan

> Just curious because I just ran into troubles with calling
> R_tryEval with unprotected expressions and accepting signals. I
> witnessed what Luke explained above, that longjmp's were being done to a
> place that I wasn't anticipating, e.g. R_tryEval was never returning.
>
> Jeff



More information about the R-devel mailing list