From luke-tierney at uiowa.edu  Fri Jan 27 15:25:11 2012
From: luke-tierney at uiowa.edu (luke-tierney at uiowa.edu)
Date: Fri, 27 Jan 2012 08:25:11 -0600
Subject: [Rd] Ignore user interrupts
In-Reply-To: <1327608987129-4331653.post@n4.nabble.com>
References: <1327337214864-4321252.post@n4.nabble.com>
	<1327348807154-4321817.post@n4.nabble.com>
	<1327608987129-4331653.post@n4.nabble.com>
Message-ID: <alpine.DEB.2.00.1201270815280.2339@luke-inspiron>

On Thu, 26 Jan 2012, Sharpie wrote:

>
> Sharpie wrote
>>
>> evalWithoutInterrupts <- function(expr, envir = parent.frame())
>> {
>>   .Call(do_evalWithoutInterrupts, expr, envir)
>> }
>>
>>
>> With a C-level implemention:
>>
>> SEXPR do_evalWithoutInterrupts(SEXP expr, SEXP envir)
>> {
>>   SEXP result;
>>
>>   BEGIN_SUSPEND_INTERRUPTS{
>>     result = eval(expr, envir);
>>   }END_SUSPEND_INTERRUPTS;
>>
>>   return result;
>> }
>>
>
> Some more info, and a possible bug:
>
> This approach appears to work if I change `evalWithoutInterrupts` so that it
> invokes `substitute` on `expr` before passing to the C code:
>
>
>    evalWithoutInterrupts <- function(expr, envir = parent.frame())
>    {
>      .Call(do_evalWithoutInterrupts, substitute(expr), envir)
>    }
>
>
> For example, I can do the following (using OS X, R 2.14.1 in Terminal.app):
>
>    eval({for(i in 1:10000000){log(i)};message("Hello, world!")})
>    evalWithoutInterrupts({for(i in 1:10000000){log(i)};message("Hello,
> world!")})
>
> The `eval` call can be interrupted by CTRL-C as normal. However, with the
> `evalWithoutInterrupts` call, I can tap on CTRL-C and the loop will still
> execute, "Hello, world!" will be printed and then the interrupt will be
> registered:
>
>    > evalWithoutInterrupts({for(i in 1:10000000){log(i)};message("Hello,
> world!")})
>    ^C^C^C^C^CHello, world!
>
>    >
>
>
> The only odd thing I came across was when I tried to test this function
> using `Sys.sleep` instead of a long loop:
>
>    evalWithoutInterrupts(Sys.sleep(3);message("Hello, world!")})
>
> The call can be interrupted immediately by CTRL-C. Some poking in GDB
> reveals that the call chain passes from my C function
> `evalWithoutInterrupts` to `do_syssleep` an finally to `Rf_onintr` through
> `R_checkActivity`:
>
> Breakpoint 1, Rf_onintr () at errors.c:123
> 123	    if (R_interrupts_suspended) {
> (gdb) bt
> #0  Rf_onintr () at errors.c:123
> #1  0x00000001001ced41 in R_SelectEx (n=1, readfds=0x10038cdc0,
> writefds=0x0, exceptfds=0x0, timeout=0x7fff5fbf8b60, intr=0) at
> sys-std.c:127
> #2  0x00000001001cf109 in R_checkActivityEx (usec=3000000, ignore_stdin=1,
> intr=0) at sys-std.c:329
> #3  0x00000001001cf14b in R_checkActivity (usec=3000000, ignore_stdin=1) at
> sys-std.c:338
> #4  0x00000001001d0fbb in do_syssleep (call=0x1025bb200, op=0x10086d0d8,
> args=0x1033679b8, rho=0x1033679f0) at sys-std.c:1299
> #5  0x00000001000c7608 in bcEval (body=0x1025ba878, rho=0x1033679f0,
> useCache=TRUE) at eval.c:4445
> #6  0x00000001000bcb69 in Rf_eval (e=0x1025ba878, rho=0x1033679f0) at
> eval.c:401
> #7  0x00000001000bddd7 in Rf_applyClosure (call=0x103366e38, op=0x1025ba8e8,
> arglist=0x103367a60, rho=0x100877ea8, suppliedenv=0x100877ee0) at eval.c:840
> #8  0x00000001000bd22e in Rf_eval (e=0x103366e38, rho=0x100877ea8) at
> eval.c:515
> #9  0x00000001000bf879 in do_begin (call=0x103366ee0, op=0x10084e6e0,
> args=0x103366dc8, rho=0x100877ea8) at eval.c:1422
> #10 0x00000001000bcf40 in Rf_eval (e=0x103366ee0, rho=0x100877ea8) at
> eval.c:471
> #11 0x0000000102fc736d in evalWithoutInterrupts ()
>
>
> However, at this point the variable `R_interrupts_suspended` is not set to
> `TRUE` as I would expect due to the `BEGIN_SUSPEND_INTERRUPTS` block in
> `evalWithoutInterrupts`:
>
> (gdb) p R_interrupts_suspended
> $1 = FALSE
>
>
> Bug?

No.

The interrupt managemant we have now is intended for the C level to
make sure interrupts can only occur where they are safe for the C
code, and at this point in sleep they are and so do_syssleep enables
them.

There is a need for interrupt management at the R level but getting it
right is not easy.  It isn't just a matter of suspending them, but
suspending and and re-enabling them where they are safe. Some code
that would potentially hang needs to enable them -- typically these
are operations that could signal other sorts of errors, like read
errors, timeouts, etc. and code that needs to ensure cleanup code is
run would need to catch those as well. (Interrupts are catchable as
"interrupt" conditions by the way).  There is some literature on this
(in particular an article "Asynchronous Exceptions in Haskell") that I
need to study more before implementing something at the R level.

luke

>
> -Charlie
>
>
> -----
> Charlie Sharpsteen
> Undergraduate-- Environmental Resources Engineering
> Humboldt State University
> --
> View this message in context: http://r.789695.n4.nabble.com/Ignore-user-interrupts-tp4321252p4331653.html
> Sent from the R devel mailing list archive at Nabble.com.
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

-- 
Luke Tierney
Chair, Statistics and Actuarial Science
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:   luke-tierney at uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



[Rd] Ignore user interrupts
luke-tierney at uiowa.edu