Skip to content

Could Rstd_Busy do something (src/unix/sys-std.c)?

7 messages · Jakson A. Aquino, Simon Urbanek

#
Currently the function Rstd_Busy() does nothing (src/unix/sys-std.c):

    void attribute_hidden Rstd_Busy(int which)
    {
    }

The function is called through a pointer and R interfaces can change
this pointer and, thus, use a different function. I don't plan to
create a whole new interface to R, but I maintain a package whose aim
is to provide a new feature to R when it's running in a terminal
emulator on Unix systems:

    http://cran.r-project.org/web/packages/setwidth/index.html

The package setwidth updates the value of options("width") whenever R receives
SIGWINCH signal. The package does not set the value of any interface pointer,
but it may make R crash if the terminal emulator is resized while R is busy. I
could avoid the crash if I knew that R is busy at the moment that it receives
the SIGWINCH. Thus my question is: Could Rstd_Busy() set the value of a
variable so packages like setwidth could know that R is busy? The function
could be changed to something like:

    void attribute_hidden Rstd_Busy(int which)
    {
        R_is_busy = which;
    }

And the R_is_busy variable could be accessed either directly or through a "get"
function, like:

    int get_busy_state(){
        return R_is_busy;
    }

Thanks!
#
On Dec 15, 2012, at 6:36 AM, Jakson Alves de Aquino wrote:

            
You're looking at the wrong spot - the Busy callback is meant for UI signaling that R may enter a longer time of processing, it is not really an indicator that R is busy - R can be busy even without the busy state being signaled.

But back to your original question - there are a few spots where you can process you request : the most obvious one is in the ReadConsole callback - that callback doesn't return until the user has entered a line - this would be a way to a GUI to handle this. The other way is to register an input handler and signal your FD when you get SIGWINCH, that guarantees that your handler will be called as soon as possible after the signal has arrived - that is probably what you want (see CarbonEL for a simple example how this is used).

Cheers,
Simon
#
On Sat, Dec 15, 2012 at 1:09 PM, Simon Urbanek
<simon.urbanek at r-project.org> wrote:
Thanks for your suggestions!

Although the comment above Rstd_Busy() (at src/unix/sys-std.c) says
"actions during (long) computations", the function is called whenever
any command is entered in R Console.
Both ptr_R_Busy and ptr_R_ReadConsole are declared on Rinterface.h,
but I can't use them because setwidth doesn't provide front-end to R
and Rinterface.h has the following statements:

    This header file is to provide hooks for alternative front-ends,
    e.g. GUIs such as GNOME and Cocoa.  [...] It should not be
    included by package sources unless they are providing such a
    front-end.
Based on CarbolEL, I added the following to setwidth_Start() function:

    int fds[2];
    if(pipe(fds))
        Rprintf("pipe > 0\n");
    else
        Rprintf("pipe = 0\n");
    ifd = fds[0];
    ofd = fds[1];
    addInputHandler(R_InputHandlers, ifd, &uih, 32);

And, also based on CarbolEL, I created the following uih() function:

    static void uih(void *data) {
      char buf[16];

      if(read(ifd, buf, 16) == 0){
          Rprintf("read = 0 :: %s\n", buf);
          Rprintf("%d written\n", write(ofd, buf, 16));
      } else {
          Rprintf("read != 0\n");
      }
    }

However, the uih() function never gets called.

Best,
#
On Dec 15, 2012, at 2:20 PM, Jakson Alves de Aquino wrote:

            
You didn't provide the signal yet - you have the initialization and receiving end ready - now you need to write the piece that triggers the input.

Cheers,
S
#
On Sat, Dec 15, 2012 at 5:41 PM, Simon Urbanek
<simon.urbanek at r-project.org> wrote:
[...]
It works like a charm now. If handle_winch() is called a hundred times
while R is busy, uih() will also be called a hundred times, but only
when R is no longer busy:

    void handle_winch(int sig){
        signal(SIGWINCH, SIG_IGN);
        char buf[16];
        *buf = 0;
        if(write(ofd, buf, 16) <= 0)
            REprintf("setwidth error: write <= 0\n");
        signal(SIGWINCH, handle_winch);
    }

    static void uih(void *data) {
      char buf[16];
      if(read(ifd, buf, 16) == 0)
          REprintf("setwidth error: read = 0\n");
      R_ToplevelExec(setwidth_Set, NULL);
    }

I added the if(read()) and if(write()) to avoid compiler warnings
about return values not being used.

Thank you very much!
#
On Dec 15, 2012, at 5:32 PM, Jakson Alves de Aquino wrote:

            
Note that you're not using the payload of the pipe at all, so you could simply just send a single byte (not that it matters but you don't need the 16-byte packets).

Also you don't want to send anything if the signal is already enqueued, it's pointless to try to send more (you could clog the pipe), so simply use a flag that you set on write and reset it on read -- if that flag is set you don't write anything. That will make sure that you get only one trigger even if more signals arrived while R is busy.  Everything is synchronous here so no need to worry.

Finally, I wouldn't mess with the signal all the time - just keep it active without touching it and use a flag to avoid re-entrance if you really think it's necessary.

Cheers,
Simon
#
On Sun, Dec 16, 2012 at 12:49 AM, Simon Urbanek
<simon.urbanek at r-project.org> wrote:
Thanks for the additional suggestions. It's even better now:

    void handle_winch(int sig){
        if(fired)
            return;
        fired = 1;
        char buf[16];
        *buf = 0;
        if(write(ofd, buf, 1) <= 0)
            REprintf("setwidth error: write <= 0\n");
    }

    static void uih(void *data) {
        char buf[16];
        if(read(ifd, buf, 16) == 0)
            REprintf("setwidth error: read = 0\n");
        R_ToplevelExec(setwidth_Set, NULL);
        fired = 0;
    }

Best,

Jakson