@@ -256,30 +256,48 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) {
256
256
ULONG_PTR key ;
257
257
OVERLAPPED * overlapped ;
258
258
uv_req_t * req ;
259
+ int repeat ;
260
+ uint64_t timeout_time ;
259
261
260
- GetQueuedCompletionStatus (loop -> iocp ,
261
- & bytes ,
262
- & key ,
263
- & overlapped ,
264
- timeout );
262
+ timeout_time = loop -> time + timeout ;
265
263
266
- if (overlapped ) {
267
- /* Package was dequeued */
268
- req = uv_overlapped_to_req (overlapped );
269
- uv_insert_pending_req (loop , req );
264
+ for (repeat = 0 ; ; repeat ++ ) {
265
+ GetQueuedCompletionStatus (loop -> iocp ,
266
+ & bytes ,
267
+ & key ,
268
+ & overlapped ,
269
+ timeout );
270
270
271
- /* Some time might have passed waiting for I/O,
272
- * so update the loop time here.
273
- */
274
- uv_update_time (loop );
275
- } else if (GetLastError () != WAIT_TIMEOUT ) {
276
- /* Serious error */
277
- uv_fatal_error (GetLastError (), "GetQueuedCompletionStatus" );
278
- } else if (timeout > 0 ) {
279
- /* GetQueuedCompletionStatus can occasionally return a little early.
280
- * Make sure that the desired timeout is reflected in the loop time.
281
- */
282
- uv__time_forward (loop , timeout );
271
+ if (overlapped ) {
272
+ /* Package was dequeued */
273
+ req = uv_overlapped_to_req (overlapped );
274
+ uv_insert_pending_req (loop , req );
275
+
276
+ /* Some time might have passed waiting for I/O,
277
+ * so update the loop time here.
278
+ */
279
+ uv_update_time (loop );
280
+ } else if (GetLastError () != WAIT_TIMEOUT ) {
281
+ /* Serious error */
282
+ uv_fatal_error (GetLastError (), "GetQueuedCompletionStatus" );
283
+ } else if (timeout > 0 ) {
284
+ /* GetQueuedCompletionStatus can occasionally return a little early.
285
+ * Make sure that the desired timeout target time is reached.
286
+ */
287
+ uv_update_time (loop );
288
+ if (timeout_time > loop -> time ) {
289
+ timeout = (DWORD )(timeout_time - loop -> time );
290
+ /* The first call to GetQueuedCompletionStatus should return very
291
+ * close to the target time and the second should reach it, but
292
+ * this is not stated in the documentation. To make sure a busy
293
+ * loop cannot happen, the timeout is increased exponentially
294
+ * starting on the third round.
295
+ */
296
+ timeout += repeat ? (1 << (repeat - 1 )) : 0 ;
297
+ continue ;
298
+ }
299
+ }
300
+ break ;
283
301
}
284
302
}
285
303
@@ -290,33 +308,51 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
290
308
OVERLAPPED_ENTRY overlappeds [128 ];
291
309
ULONG count ;
292
310
ULONG i ;
293
-
294
- success = pGetQueuedCompletionStatusEx (loop -> iocp ,
295
- overlappeds ,
296
- ARRAY_SIZE (overlappeds ),
297
- & count ,
298
- timeout ,
299
- FALSE);
300
-
301
- if (success ) {
302
- for (i = 0 ; i < count ; i ++ ) {
303
- /* Package was dequeued */
304
- req = uv_overlapped_to_req (overlappeds [i ].lpOverlapped );
305
- uv_insert_pending_req (loop , req );
311
+ int repeat ;
312
+ uint64_t timeout_time ;
313
+
314
+ timeout_time = loop -> time + timeout ;
315
+
316
+ for (repeat = 0 ; ; repeat ++ ) {
317
+ success = pGetQueuedCompletionStatusEx (loop -> iocp ,
318
+ overlappeds ,
319
+ ARRAY_SIZE (overlappeds ),
320
+ & count ,
321
+ timeout ,
322
+ FALSE);
323
+
324
+ if (success ) {
325
+ for (i = 0 ; i < count ; i ++ ) {
326
+ /* Package was dequeued */
327
+ req = uv_overlapped_to_req (overlappeds [i ].lpOverlapped );
328
+ uv_insert_pending_req (loop , req );
329
+ }
330
+
331
+ /* Some time might have passed waiting for I/O,
332
+ * so update the loop time here.
333
+ */
334
+ uv_update_time (loop );
335
+ } else if (GetLastError () != WAIT_TIMEOUT ) {
336
+ /* Serious error */
337
+ uv_fatal_error (GetLastError (), "GetQueuedCompletionStatusEx" );
338
+ } else if (timeout > 0 ) {
339
+ /* GetQueuedCompletionStatus can occasionally return a little early.
340
+ * Make sure that the desired timeout target time is reached.
341
+ */
342
+ uv_update_time (loop );
343
+ if (timeout_time > loop -> time ) {
344
+ timeout = (DWORD )(timeout_time - loop -> time );
345
+ /* The first call to GetQueuedCompletionStatus should return very
346
+ * close to the target time and the second should reach it, but
347
+ * this is not stated in the documentation. To make sure a busy
348
+ * loop cannot happen, the timeout is increased exponentially
349
+ * starting on the third round.
350
+ */
351
+ timeout += repeat ? (1 << (repeat - 1 )) : 0 ;
352
+ continue ;
353
+ }
306
354
}
307
-
308
- /* Some time might have passed waiting for I/O,
309
- * so update the loop time here.
310
- */
311
- uv_update_time (loop );
312
- } else if (GetLastError () != WAIT_TIMEOUT ) {
313
- /* Serious error */
314
- uv_fatal_error (GetLastError (), "GetQueuedCompletionStatusEx" );
315
- } else if (timeout > 0 ) {
316
- /* GetQueuedCompletionStatus can occasionally return a little early.
317
- * Make sure that the desired timeout is reflected in the loop time.
318
- */
319
- uv__time_forward (loop , timeout );
355
+ break ;
320
356
}
321
357
}
322
358
0 commit comments