Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8e6333e

Browse files
committed
Fix WaitEventSetWait() to handle write-ready waits properly on Windows.
Windows apparently will not detect socket write-ready events unless a preceding send attempt returned WSAEWOULDBLOCK. In many usage patterns that's satisfied by the caller of WaitEvenSetWait(), but not always. Apply the same solution that we already had in pgwin32_select(), namely to perform a dummy WSASend() call with len=0. This will return WSAEWOULDBLOCK if there's no buffer space (even though it could legitimately do nothing and report success, which makes me a bit nervous about this solution; but since it's been working fine in libpq, let's roll with it). In passing, improve the comments about this in pgwin32_select(), and remove duplicated code there. Back-patch to 9.6 where WaitEventSetWait() was introduced. We might need to back-patch something similar into predecessor code. But given the lack of complaints so far, it's not clear that the case ever gets exercised in the back branches, so I'm not going to expend effort on it right now. This should resolve recurring failures on buildfarm member bowerbird, which has been failing since 1e8a850 went in. Diagnosis and patch by Petr Jelinek, cosmetic adjustments by me. Discussion: https://postgr.es/m/5b6a6d6d-fb45-0afb-2e95-5600063c3dbd@2ndquadrant.com
1 parent 733488d commit 8e6333e

File tree

2 files changed

+44
-16
lines changed

2 files changed

+44
-16
lines changed

src/backend/port/win32/socket.c

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -523,11 +523,16 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c
523523
FD_ZERO(&outwritefds);
524524

525525
/*
526-
* Write FDs are different in the way that it is only flagged by
527-
* WSASelectEvent() if we have tried to write to them first. So try an
528-
* empty write
526+
* Windows does not guarantee to log an FD_WRITE network event indicating
527+
* that more data can be sent unless the previous send() failed with
528+
* WSAEWOULDBLOCK. While our caller might well have made such a call, we
529+
* cannot assume that here. Therefore, if waiting for write-ready, force
530+
* the issue by doing a dummy send(). If the dummy send() succeeds,
531+
* assume that the socket is in fact write-ready, and return immediately.
532+
* Also, if it fails with something other than WSAEWOULDBLOCK, return a
533+
* write-ready indication to let our caller deal with the error condition.
529534
*/
530-
if (writefds)
535+
if (writefds != NULL)
531536
{
532537
for (i = 0; i < writefds->fd_count; i++)
533538
{
@@ -539,20 +544,11 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c
539544
buf.len = 0;
540545

541546
r = WSASend(writefds->fd_array[i], &buf, 1, &sent, 0, NULL, NULL);
542-
if (r == 0) /* Completed - means things are fine! */
547+
if (r == 0 || WSAGetLastError() != WSAEWOULDBLOCK)
543548
FD_SET(writefds->fd_array[i], &outwritefds);
544-
545-
else
546-
{ /* Not completed */
547-
if (WSAGetLastError() != WSAEWOULDBLOCK)
548-
549-
/*
550-
* Not completed, and not just "would block", so an error
551-
* occurred
552-
*/
553-
FD_SET(writefds->fd_array[i], &outwritefds);
554-
}
555549
}
550+
551+
/* If we found any write-ready sockets, just return them immediately */
556552
if (outwritefds.fd_count > 0)
557553
{
558554
memcpy(writefds, &outwritefds, sizeof(fd_set));

src/backend/storage/ipc/latch.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,38 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
13941394
WaitEventAdjustWin32(set, cur_event);
13951395
cur_event->reset = false;
13961396
}
1397+
1398+
/*
1399+
* Windows does not guarantee to log an FD_WRITE network event
1400+
* indicating that more data can be sent unless the previous send()
1401+
* failed with WSAEWOULDBLOCK. While our caller might well have made
1402+
* such a call, we cannot assume that here. Therefore, if waiting for
1403+
* write-ready, force the issue by doing a dummy send(). If the dummy
1404+
* send() succeeds, assume that the socket is in fact write-ready, and
1405+
* return immediately. Also, if it fails with something other than
1406+
* WSAEWOULDBLOCK, return a write-ready indication to let our caller
1407+
* deal with the error condition.
1408+
*/
1409+
if (cur_event->events & WL_SOCKET_WRITEABLE)
1410+
{
1411+
char c;
1412+
WSABUF buf;
1413+
DWORD sent;
1414+
int r;
1415+
1416+
buf.buf = &c;
1417+
buf.len = 0;
1418+
1419+
r = WSASend(cur_event->fd, &buf, 1, &sent, 0, NULL, NULL);
1420+
if (r == 0 || WSAGetLastError() != WSAEWOULDBLOCK)
1421+
{
1422+
occurred_events->pos = cur_event->pos;
1423+
occurred_events->user_data = cur_event->user_data;
1424+
occurred_events->events = WL_SOCKET_WRITEABLE;
1425+
occurred_events->fd = cur_event->fd;
1426+
return 1;
1427+
}
1428+
}
13971429
}
13981430

13991431
/*

0 commit comments

Comments
 (0)