From 6209cb3f7d32c5806ed0a985e4afa66649befb70 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Mon, 4 Jun 2007 13:39:41 +0000 Subject: [PATCH] On win32, retry reading when WSARecv returns WSAEWOULDBLOCK. There seem to be cases when at least Windows 2000 can do this even though select just indicated that the socket is readable. Per report and analysis from Cyril VELTER. --- src/backend/port/win32/socket.c | 40 ++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index ece0f3397d7..dd1f5f4d5af 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.14.2.2 2007/01/26 20:07:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.14.2.3 2007/06/04 13:39:41 mha Exp $ * *------------------------------------------------------------------------- */ @@ -291,6 +291,7 @@ pgwin32_recv(SOCKET s, char *buf, int len, int f) int r; DWORD b; DWORD flags = f; + int n; if (pgwin32_poll_signals()) return -1; @@ -312,17 +313,36 @@ pgwin32_recv(SOCKET s, char *buf, int len, int f) /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */ - if (pgwin32_waitforsinglesocket(s, FD_READ | FD_CLOSE | FD_ACCEPT, - INFINITE) == 0) - return -1; - - r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL); - if (r == SOCKET_ERROR) + for (n = 0; n < 5; n++) { - TranslateSocketError(); - return -1; + if (pgwin32_waitforsinglesocket(s, FD_READ | FD_CLOSE | FD_ACCEPT, + INFINITE) == 0) + return -1; /* errno already set */ + + r = WSARecv(s, &wbuf, 1, &b, &flags, NULL, NULL); + if (r == SOCKET_ERROR) + { + if (WSAGetLastError() == WSAEWOULDBLOCK) + { + /* + * There seem to be cases on win2k (at least) where WSARecv + * can return WSAEWOULDBLOCK even when pgwin32_waitforsinglesocket + * claims the socket is readable. In this case, just sleep for a + * moment and try again. We try up to 5 times - if it fails more than + * that it's not likely to ever come back. + */ + pg_usleep(10000); + continue; + } + TranslateSocketError(); + return -1; + } + return b; } - return b; + ereport(NOTICE, + (errmsg_internal("Failed to read from ready socket (after retries)"))); + errno = EWOULDBLOCK; + return -1; } int