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 |
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 |
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 |
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] |
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. |
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] |
Free forum by Nabble | Edit this page |