@@ -17,6 +17,19 @@ module IOCP.FFI (
17
17
-- * Cancel pending I/O
18
18
cancelIo ,
19
19
20
+ -- * Monotonic time
21
+ -- | Windows has multiple monotonic time APIs, each with its own caveats.
22
+ -- It seems that QueryPerformanceCounter has higher precision,
23
+ -- while GetTickCount(64) has better accuracy and consistency.
24
+
25
+ -- ** GetTickCount
26
+ getTickCount ,
27
+ loadGetTickCount64 ,
28
+
29
+ -- ** QueryPerformanceCounter
30
+ queryPerformanceCounter ,
31
+ queryPerformanceFrequency ,
32
+
20
33
-- * Miscellaneous
21
34
throwWinErr ,
22
35
) where
@@ -142,6 +155,101 @@ foreign import WINDOWS_CCONV safe "windows.h CancelIo"
142
155
cancelIo :: HANDLE -> IO ()
143
156
cancelIo = Win32. failIfFalse_ " CancelIo" . c_CancelIo
144
157
158
+ ------------------------------------------------------------------------
159
+ -- Monotonic time
160
+
161
+ foreign import WINDOWS_CCONV " windows.h GetTickCount"
162
+ c_GetTickCount :: IO # {type DWORD }
163
+
164
+ -- | Call the @GetTickCount@ function, which returns a monotonic time in
165
+ -- milliseconds.
166
+ --
167
+ -- Problems:
168
+ --
169
+ -- * Low resolution (10 to 16 milliseconds).
170
+ --
171
+ -- * Wraps around when the system runs continuously for 49.7 days.
172
+ --
173
+ -- * Not available for Windows Store apps.
174
+ --
175
+ -- <http://msdn.microsoft.com/en-us/library/windows/desktop/ms724408%28v=vs.85%29.aspx>
176
+ getTickCount :: IO Word32
177
+ getTickCount = c_GetTickCount
178
+
179
+ type C_GetTickCount64 = IO # {type ULONGLONG }
180
+
181
+ -- Defined in cbits/dll.c
182
+ foreign import ccall
183
+ iocp_load_GetTickCount64 :: IO (FunPtr C_GetTickCount64 )
184
+
185
+ foreign import WINDOWS_CCONV " dynamic"
186
+ mkGetTickCount64 :: FunPtr C_GetTickCount64 -> C_GetTickCount64
187
+
188
+ -- | Load the @GetTickCount64@ function, or return 'Nothing' if it is
189
+ -- not available.
190
+ --
191
+ -- Problems:
192
+ --
193
+ -- * Low resolution (10 to 16 milliseconds).
194
+ --
195
+ -- * Introduced in Windows Vista, so not available under Windows XP.
196
+ --
197
+ -- <http://msdn.microsoft.com/en-us/library/windows/desktop/ms724411%28v=vs.85%29.aspx>
198
+ loadGetTickCount64 :: IO (Maybe (IO Word64 ))
199
+ loadGetTickCount64 = do
200
+ fun <- iocp_load_GetTickCount64
201
+ if fun == nullFunPtr then
202
+ return Nothing
203
+ else
204
+ return $ Just $ mkGetTickCount64 fun
205
+
206
+ type QPFunc = Ptr Int64 -> IO BOOL
207
+
208
+ foreign import WINDOWS_CCONV " Windows.h QueryPerformanceCounter"
209
+ c_QueryPerformanceCounter :: QPFunc
210
+
211
+ foreign import WINDOWS_CCONV " Windows.h QueryPerformanceFrequency"
212
+ c_QueryPerformanceFrequency :: QPFunc
213
+
214
+ callQP :: QPFunc -> IO (Maybe Int64 )
215
+ callQP qpfunc =
216
+ allocaBytes # {size LARGE_INTEGER } $ \ ptr -> do
217
+ ok <- qpfunc ptr
218
+ if ok then do
219
+ n <- # {peek LARGE_INTEGER , QuadPart } ptr
220
+ return (Just n)
221
+ else
222
+ return Nothing
223
+
224
+ -- | Call the @QueryPerformanceCounter@ function.
225
+ --
226
+ -- Problems:
227
+ --
228
+ -- * On a multiprocessor computer, may produce different results on
229
+ -- different processors due to hardware bugs.
230
+ --
231
+ -- * May drift when the computer is put to sleep.
232
+ --
233
+ -- To get a monotonic time in seconds, divide the result of
234
+ -- 'queryPerformanceCounter' by that of 'queryPerformanceFrequency'.
235
+ --
236
+ -- <http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904%28v=vs.85%29.aspx>
237
+ queryPerformanceCounter :: IO (Maybe Int64 )
238
+ queryPerformanceCounter = callQP c_QueryPerformanceCounter
239
+
240
+ -- | Call the @QueryPerformanceFrequency@ function. Return 'Nothing' if the
241
+ -- hardware does not provide a high-resolution performance counter.
242
+ --
243
+ -- <http://msdn.microsoft.com/en-us/library/windows/desktop/ms644905%28v=vs.85%29.aspx>
244
+ queryPerformanceFrequency :: IO (Maybe Int64 )
245
+ queryPerformanceFrequency = do
246
+ m <- callQP c_QueryPerformanceFrequency
247
+ case m of
248
+ Nothing -> return Nothing
249
+ Just 0 -> return Nothing -- Shouldn't happen; just a safeguard to
250
+ -- avoid a zero denominator.
251
+ Just freq -> return (Just freq)
252
+
145
253
------------------------------------------------------------------------
146
254
-- Miscellaneous
147
255
0 commit comments