[RFC] base: Handle long timeouts
AbandonedPublic

Authored by bgamari on May 16 2018, 11:05 AM.

Details

Reviewers
simonmar
hvr
Trac Issues
#15158
#8089
Summary

Currently threadDelay maxBound causes the event manager's timer manager to
integer overflow when computing the timeout's expiration time. This causes
threadDelay to return essentially immediately. This causes T8089 to fail with
the threaded runtime. See Trac #15158.

This likely only affects 64-bit machines, since the timer manager uses 64-bit
timestamps for expiration times internally, yes delays are simply Ints.

A hacky but simpler alternative to this would be to decide that in
2^64 ns Earth will have long ago been rendered uninhabitable. We could then
instead simply map any overflowing timeout to expire at maxBound :: Timeout.

Test Plan

make test TEST=T8089 on amd64 Linux

bgamari created this revision.May 16 2018, 11:05 AM
bgamari added inline comments.May 16 2018, 11:09 AM
libraries/base/GHC/Event/EPoll.hsc
208

Whoops, this change should be dropped.

libraries/base/GHC/Event/TimerManager.hs
87

I need to finish writing this.

116

This needs a comment.

This seems like quite an elaborate fix for an overflow problem. Why did the overflow occur in the first place, shouldn't the time remaining be less than maxBound?

bgamari added inline comments.May 20 2018, 1:19 PM
libraries/base/GHC/Event/TimerManager.hs
221

The timeout occurs here; now is the current time and us is maxBound :: Int. Consequently the addition overflows.

simonmar added inline comments.May 21 2018, 2:49 AM
libraries/base/GHC/Event/TimerManager.hs
221

Ok, so there are two problems:

  • The timeout value is really limited to maxBound / 1000
  • If the timeout results in an expiry time greater than maxBound in nanoseconds, then we should clamp it to that

Isn't it possible to do the arithmetic safely here, clamping to maxBound if we go over the limit? Something like

let ns = if us >= maxBound `quot` 1000 then maxBound else us * 1000
    expTime = if ns > maxBound - now then maxBound else ns + now
bgamari added inline comments.May 21 2018, 10:06 AM
libraries/base/GHC/Event/TimerManager.hs
221

Isn't it possible to do the arithmetic safely here, clamping to maxBound if we go over the limit?

Yes, this is the alternative I suggest in the summary. We could do this, afterall the timescales involves are on the order of hundreds of years. However, my first inclination was to fix it "properly".

I take it you would prefer to simply clamp?

simonmar added inline comments.May 21 2018, 3:46 PM
libraries/base/GHC/Event/TimerManager.hs
221

Yeah, I think it's fine. We use 64-bit nanosecond timestamps throughout the RTS, so I don't think it's a problem to do it here too. We'll have to deal with this before the year 2500 or so but we could just make a ticket for that.

bgamari abandoned this revision.May 21 2018, 3:59 PM

Alright, see D4719.