On Fri, 2 Mar 2007, Eric Hodel wrote:

> On Mar 1, 2007, at 07:12, Avdi Grimm wrote:
>> On 3/1/07, Tomas Pospisek <tpo2 / sourcepole.ch> wrote:
>>> However, this applies in exactly the same way to libc-select as well and 
>>> thus replacing the select/gettimeofday mechanism by libc-sleep should 
>>> at least work no worse. Objections?
>> 
>> My first reaction was:  good god, the scheduler uses wallclock time?!
>> Speaking as someone who works on realtime systems (and thus has to
>> think about scheduler implementation often), this is never a good
>> idea.  I don't know the background for Ruby's scheduler design, but
>> normally I'd regard a scheduler which uses wallclock time as just
>> plain *broken*.  I'm heartily in favor of changing it to something
>> which isn't dependent on the clock.
>
> The Ruby thread scheduler uses setitimer(2) and select(2).  It depends on the 
> wall-clock for implementing features defined in terms of the wall-clock 
> (Kernel#sleep and Thread#join).

You need to add Timeout#timeout to this. But:

$ ri Kernel#sleep

      Suspends the current thread for _duration_ seconds (which may be
      any number, including a +Float+ with fractional seconds). Returns
      the actual number of seconds slept (rounded), which may be less
      than that asked for if another thread calls +Thread#run+. Zero
      arguments causes +sleep+ to sleep forever.

No reference to wall-clock in there. What do you mean by "defined in terms 
of the wall-clock"?

>> That "indeterminate amount" referenced above is simply the price you
>> pay for running in userspace ion a modern multitasking OS.  Yes,
>> system activity could delay the return.  That's what multitasking
>> means: you don't get to choose when you get the CPU.  In practice, if
>> applications are experiencing unacceptable latency in OS scheduling
>> then 1) your gettimeofday()-based implementation is going to be
>> delayed right along with everything else; and 2) you have bigger
>> problems, because your system is overloaded.
>
> Kernel#sleep behaves differently in Ruby programs using threads.  If you 
> sleep in a thread you end up context switching to other threads instead of 
> calling sleep(3).
>
> Since you aren't using sleep(3) in threaded mode, Ruby instead uses 
> gettimeofday(2) to implement Kernel#sleep for the calling thread (has this 
> thread slept its N seconds?), so you may sleep longer than you expect.
>
> The other place gettimeofday(2) is used is Thread#join's timeout, for similar 
> reason.

The problem is that when you set system time into the past by a month, 
then your thread will also sleep for a month and not, as you probably 
expected, only a few seconds. Which is actually the hint for the 
solution... to be followed.

*t

--
-----------------------------------------------------------
   Tomas Pospisek
   http://sourcepole.com -  Linux & Open Source Solutions
-----------------------------------------------------------