#5865: threadDelay is disrupted by system clock changes
---------------------------------+------------------------------------------
Reporter: joeyadams | Owner: pcapriotti
Type: bug | Status: patch
Priority: high | Milestone: 7.4.2
Component: Runtime System | Version: 7.4.1
Keywords: | Os: Unknown/Multiple
Architecture: Unknown/Multiple | Failure: Incorrect result at runtime
Difficulty: Unknown | Testcase:
Blockedby: | Blocking:
Related: |
---------------------------------+------------------------------------------
Comment(by joeyadams):
Replying to [comment:11 pcapriotti]:
> Added patch for win32, using `QueryPerformanceCounter` instead of
`GetSystemTimeAsFileTime`.
Thanks for addressing the problem on Windows, too. However, two things
worry me about this patch:
* The documentation for [http://msdn.microsoft.com/en-
us/library/windows/desktop/ms644905%28v=vs.85%29.aspx
QueryPerformanceFrequency] implies that some hardware does not support a
high-resolution performance counter. On the other hand, I don't know how
likely we are to see such systems running Windows 2000 or later. A
[http://www.virtualdub.org/blog/pivot/entry.php?id=106 post on
virtualdub.org] has some interesting things to say about
`QueryPerformanceCounter`, too.
* The return values of `QueryPerformanceCounter` and
`QueryPerformanceFrequency` aren't even checked. Thus, if one of these
functions fail, the program will silently start acting strangely.
We should at the very least check the return value of
`QueryPerformanceCounter`. Ideally, we would fall back to
[http://msdn.microsoft.com/en-
us/library/windows/desktop/ms724408%28v=vs.85%29.aspx GetTickCount].
Note that `GetTickCount` has a wraparound problem due to its 32-bit return
value. There is a [http://msdn.microsoft.com/en-
us/library/windows/desktop/ms724411%28v=vs.85%29.aspx GetTickCount64]
function, but it is only available for Vista and later.
The easy way to work around the problem: never compare two times more than
49 days apart, and do the subtraction with the original `DWORD`s to make
wraparound work for you. See my
[http://stackoverflow.com/a/9232314/149391 StackOverflow answer] about
this for more details.
One way to emulate a 64-bit counter is to associate the return value of
`GetTickCount` with a 64-bit value that represents, in a sense, the
current time. Something like this:
{{{
uint64_t initMonotonicClock(void)
{
return GetTickCount();
}
uint64_t updateMonotonicClock(uint64_t before)
{
DWORD now = GetTickCount();
DWORD offset = now - (DWORD)before;
return before + offset;
}
}}}
So for every call to `getMonotonicUSec`, update a global variable using
the result of `updateMonotonicClock`. As long as `getMonotonicUSec` is
called at least once every 49 days, any pair of return values from
`getMonotonicUSec` can be compared without overflow issues (that is,
unless the program runs for about 500 million years).
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5865#comment:14>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs