The question was answered by Simon Urbanek on the r-devel mailing list. Below a copy of his response for future reference:
What causes this difference?
The time limit can only be checked in R_ProcessEvents() so for all practical purposes it can be only triggered by interruptible code that calls R_CheckUserInterrupt().
Now, it is entirely up to the front-end to decide how it will the the event loop. For example the terminal version of R has no other interrupts to worry about other than input handlers which trigger asynchronously, so it doesn't need to do any polling. Sys.sleep() only triggers on input handlers, so if you don't have any external event source hook as input handler, there is no reason to process any events so Sys.sleep() won't see any reason to check the time limit.
Is there something I can set in my terminal R session such that the time limit is triggered?
On OS X it's actually very easy: quartz(); dev.off()
will do the trick. The reason is that Quartz needs to force the event loop in order to process events from the window asynchronously. It does so by installing a timer-based input handler. This handler will make sure that Sys.sleep() will wake up every 100ms (you can change the value using QuartzCocoa_SetLatency) so it will timeout with that resolution:
> testlimit <- function(){
+ setTimeLimit(elapsed=3, transient=TRUE);
+ Sys.sleep(10);
+ }
> system.time(testlimit());
Error in Sys.sleep(10) : reached elapsed time limit
Timing stopped at: 0 0.001 10.001
> quartz(); dev.off()
null device
1
> testlimit <- function(){
+ setTimeLimit(elapsed=3, transient=TRUE);
+ Sys.sleep(10);
+ }
> system.time(testlimit());
Error in Sys.sleep(10) : reached elapsed time limit
Timing stopped at: 0.002 0.003 3.019
On Linux, there is no built-in timer, so you'd have to add an input handler that will pre-empt Sys.sleep(). If you want a constant timer, you can simply borrow the code from Quartz (have a look at QuartzCocoa_SetupEventLoop in src/library/grDevices/src/qdCocoa.m) or the CarbonEL package. It's really just a pipe that is added as an input handler into which you write asynchronously when you want to wake up the event loop. On top of my head I can't think of a built-in solution in R at this point (even though it could be argued that R might install a handler itself when the limit is set ...).
But note that this is really just a special case of of Sys.sleep(). If you actually run R code, then ProcessEvents is triggered automatically during the evaluation (or in interruptible C code).
Cheers,
Simon
Sys.sleep(10)
you instead invokefor (i in seq(10)) Sys.sleep(1)
? – Hoodlumsudo
the command (or the session)? – Charpentier