Bug in the class Delay?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Bug in the class Delay?

David Gorisek-5
The method Delay>>#calcResumptionTime calculates the time at which the
Delay will expire by adding the delay duration. But since this method
uses the 32-bit system millisecond clock value I think it should have
some code to handle the timer wrap around which happens every 28 days.
What if the delay is started right before the timer wraps around. Then
the timer will wrap around and the delayed process will never get above
resumptionTime and will therefore wait forever. Is this true or am I
missing something?

I think there should be some method giving the #maxTimerValue. Then the
resumptionTime would be:

resumptionTime := (self class millisecondClockValue + duration) \\
maxTimerValue

See code below.

Best regards,

David Gorisek

---
calcResumptionTime
        "Private - Calculate and answer the value of the millisecond clock
after which any
        Process waiting on the receiver will be rescheduled. We could lazily
evaluate this
        from the normal accessor, but we want to ensure that scheduling Delays
is as fast
        as possible, and we also want to be able to control when the
calculation is made,
        as for relative durations (the most common case) we really want to
calculate off
        the clock just before the receiver is scheduled, certainly not before
that."

        resumptionTime isNil ifTrue: [resumptionTime := self class
millisecondClockValue + duration].
        ^resumptionTime


Reply | Threaded
Open this post in threaded view
|

Re: Bug in the class Delay?

David Gorisek-5
Ok, no need to answer this. I've looked up the archives and it is a bug.
  For now I have fixed it in my image. This explains to me why some
background processes stopped working now and then with no apparent reason...

One way you can do to fix it in Dolphin without having to change
anything else in the image is to store the previous value of the counter
in the method  #millisecondClockValue. Then, if the next reading is
smaller then the previous one, add another 2^32 to some inst var called
e.g. "offset". As a result of the method answer the current timer
reading incremented by the offset value. The offset is incremented by
2^32 everytime you detect a wrap-around of the clock (every 2^32 /
86400000 days).

Thanks,

David Gorisek


David Gorisek wrote:

> The method Delay>>#calcResumptionTime calculates the time at which the
> Delay will expire by adding the delay duration. But since this method
> uses the 32-bit system millisecond clock value I think it should have
> some code to handle the timer wrap around which happens every 28 days.
> What if the delay is started right before the timer wraps around. Then
> the timer will wrap around and the delayed process will never get above
> resumptionTime and will therefore wait forever. Is this true or am I
> missing something?
>
> I think there should be some method giving the #maxTimerValue. Then the
> resumptionTime would be:
>
> resumptionTime := (self class millisecondClockValue + duration) \\
> maxTimerValue
>
> See code below.
>
> Best regards,
>
> David Gorisek
>
> ---
> calcResumptionTime
>     "Private - Calculate and answer the value of the millisecond clock
> after which any
>     Process waiting on the receiver will be rescheduled. We could lazily
> evaluate this
>     from the normal accessor, but we want to ensure that scheduling
> Delays is as fast
>     as possible, and we also want to be able to control when the
> calculation is made,
>     as for relative durations (the most common case) we really want to
> calculate off
>     the clock just before the receiver is scheduled, certainly not
> before that."
>
>     resumptionTime isNil ifTrue: [resumptionTime := self class
> millisecondClockValue + duration].
>     ^resumptionTime


Reply | Threaded
Open this post in threaded view
|

Re: Bug in the class Delay?

David Gorisek-5
In reply to this post by David Gorisek-5
Ok, no need to answer this. I've looked up the archives and it is a bug.
  For now I have fixed it in my image. This explains to me why some
background processes stopped working now and then with no apparent reason...

One way you can do to fix it in Dolphin without having to change
anything else in the image is to store the previous value of the counter
in the method  #millisecondClockValue. Then, if the next reading is
smaller then the previous one, add another 2^32 to some inst var called
e.g. "offset". As a result of the method answer the current timer
reading incremented by the offset value. The offset is incremented by
2^32 everytime you detect a wrap-around of the clock (every 2^32 /
86400000 days).

Thanks,

David Gorisek


David Gorisek wrote:

> The method Delay>>#calcResumptionTime calculates the time at which the
> Delay will expire by adding the delay duration. But since this method
> uses the 32-bit system millisecond clock value I think it should have
> some code to handle the timer wrap around which happens every 28 days.
> What if the delay is started right before the timer wraps around. Then
> the timer will wrap around and the delayed process will never get above
> resumptionTime and will therefore wait forever. Is this true or am I
> missing something?
>
> I think there should be some method giving the #maxTimerValue. Then the
> resumptionTime would be:
>
> resumptionTime := (self class millisecondClockValue + duration) \\
> maxTimerValue
>
> See code below.
>
> Best regards,
>
> David Gorisek
>
> ---
> calcResumptionTime
>     "Private - Calculate and answer the value of the millisecond clock
> after which any
>     Process waiting on the receiver will be rescheduled. We could lazily
> evaluate this
>     from the normal accessor, but we want to ensure that scheduling
> Delays is as fast
>     as possible, and we also want to be able to control when the
> calculation is made,
>     as for relative durations (the most common case) we really want to
> calculate off
>     the clock just before the receiver is scheduled, certainly not
> before that."
>
>     resumptionTime isNil ifTrue: [resumptionTime := self class
> millisecondClockValue + duration].
>     ^resumptionTime


Reply | Threaded
Open this post in threaded view
|

Re: Bug in the class Delay?

Schwab,Wilhelm K
David,

> Ok, no need to answer this. I've looked up the archives and it is a bug.
>  For now I have fixed it in my image. This explains to me why some
> background processes stopped working now and then with no apparent
> reason...

Can you distill this to a few chunks?  I share Blair's goal of making
the change testable, but would also like to see this fixed.  49.7 days
really isn't all that long =:0

Depending on what you produce, we might be able to factor out a
component that would handle the wraps and still be sufficiently mutable
to allow good unit tests.

Have a good one,

Bill


--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Bug in the class Delay?

David Gorisek-5
Bill Schwab wrote:

> David,
>
>> Ok, no need to answer this. I've looked up the archives and it is a
>> bug.  For now I have fixed it in my image. This explains to me why
>> some background processes stopped working now and then with no
>> apparent reason...
>
>
> Can you distill this to a few chunks?  I share Blair's goal of making
> the change testable, but would also like to see this fixed.  49.7 days
> really isn't all that long =:0
>
> Depending on what you produce, we might be able to factor out a
> component that would handle the wraps and still be sufficiently mutable
> to allow good unit tests.
>
> Have a good one,
>
> Bill
>

Bill,

I have created another method in my "dialect abstraction layer" which is
the following:

---
absoluteMillisecondsClockValue
        "Answer system milliseconds clock value.
        Value is always incremented, no wrap-around can occur and no daylight
saving occurs."

        | time |
        time := Time millisecondClockValue.
        rollOverValue isNil ifTrue: [rollOverValue := 0] ifFalse: [time := time
+ rollOverValue].
        (previousTimeReading isNil or: [time >= previousTimeReading])
                ifFalse:
                        [rollOverValue := rollOverValue + (2 raisedTo: 32).
                        time := time + (2 raisedTo: 32)].
        previousTimeReading := time.
        ^time

---

Variables 'previousTimeReading' and 'offset' are class inst vars. The
precondition here is that this method is called at least once every 49
days which will always hold for my server application which does a lot
of process switching using delays. So I have just replaced the default
Delay class #millisecondsClockValue method with a message send to my method.

Best regards,

David Gorisek

PS: I agree that 49.7 days is really not that long. Especially when you
are running server machines which are always on-line and never rebooted.
So even if you restart a Dolphin server on the 49th day it will not work
correctly without rebooting the whole machine.


Reply | Threaded
Open this post in threaded view
|

Re: Bug in the class Delay?

Schwab,Wilhelm K
David,

> I have created another method in my "dialect abstraction layer" which is
> the following:

[code snipped]

> Variables 'previousTimeReading' and 'offset' are class inst vars. The
> precondition here is that this method is called at least once every 49
> days which will always hold for my server application which does a lot
> of process switching using delays. So I have just replaced the default
> Delay class #millisecondsClockValue method with a message send to my
> method.

Thanks for working on this.  It sounds like a job for a psuedo (for
benefit of unit tests) singleton.  I am hoping that we can create
something that OA is comfortable including in the base system.

I also use quite a few delays, and so would have very little trouble
ensuring that it was called in the required time window.  However, one
might provide a couple of classes, one with a background thread that
simply waits on delays to bang on the box.  OA could always add
something to one of the normal threads, at which point they could change
the default class and remove the hacked one.

I will be happy to work on it, but feel free to beat me to it.


> PS: I agree that 49.7 days is really not that long. Especially when you
> are running server machines which are always on-line and never rebooted.
> So even if you restart a Dolphin server on the 49th day it will not work
> correctly without rebooting the whole machine.

I started to sleep better after finding what was wrong and how to
prevent it, but have I mentioned that 49.7 days is not a long time ;)
To put it another way, when I had to tell people it "looks like the
timers quit firing", that was one thing; now I have to tell them I
couldn't reliably count to seven (weeks) :(

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]