poll: honor the timeout on Win32

Ensure that when passing a pipe, the gnulib poll replacement will not return 0 before the timeout has passed. Not obeying the timeout (and merely returning 0) causes pathological behavior when preparing a packfile for a repository and taking a long time to do so. If poll were to return 0 immediately, this would cause keep-alives to get sent as quickly as possible until the packfile was created. Such deviance from the standard would cause megabytes (or more) of keep-alive packets to be sent. GetTickCount is used as it is efficient, stable and monotonically increasing. (Neither GetSystemTime nor QueryPerformanceCounter have all three of these properties.) Signed-off-by: Edward Thomson <ethomson@microsoft.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Edward Thomson committed Sep 12, 2015 at 17:50 UTC ef8b53e78c534d732fe58a46da8dbd922287a56b
1 file changed +14 -2
compat/poll/poll.c
+14 -2
@@ -446,7 +446,7 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout)
446 static HANDLE hEvent;
447 WSANETWORKEVENTS ev;
448 HANDLE h, handle_array[FD_SETSIZE + 2];
449 - DWORD ret, wait_timeout, nhandles;
449 + DWORD ret, wait_timeout, nhandles, start = 0, elapsed, orig_timeout = 0;
450 fd_set rfds, wfds, xfds;
451 BOOL poll_again;
452 MSG msg;
@@ -459,6 +459,12 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout)
459 return -1;
460 }
461
462 + if (timeout != INFTIM)
463 + {
464 + orig_timeout = timeout;
465 + start = GetTickCount();
466 + }
467 +
468 if (!hEvent)
469 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
470
@@ -603,7 +609,13 @@ restart:
609 rc++;
610 }
611
606 - if (!rc && timeout == INFTIM)
612 + if (!rc && orig_timeout && timeout != INFTIM)
613 + {
614 + elapsed = GetTickCount() - start;
615 + timeout = elapsed >= orig_timeout ? 0 : orig_timeout - elapsed;
616 + }
617 +
618 + if (!rc && timeout)
619 {
620 SleepEx (1, TRUE);
621 goto restart;