Skip to content

Commit b98e551

Browse files
committed
Fix corner-case bug in WaitEventSetWaitBlock on Windows.
If we do not reset the FD_READ event, WaitForMultipleObjects won't return it again again unless we've meanwhile read from the socket, which is generally true but not guaranteed. WaitEventSetWaitBlock itself may fail to return the event to the caller if the latch is also set, and even if we changed that, the caller isn't obliged to handle all returned events at once. On non-Windows systems, the socket-read event is purely level-triggered, so this issue does not exist. To fix, make Windows reset the event when needed. This bug was introduced by 98a64d0, and causes hangs when trying to use the pldebugger extension. Patch by Amit Kapial. Reported and tested by Ashutosh Sharma, who also provided some analysis. Further analysis by Michael Paquier.
1 parent ce92fc4 commit b98e551

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/backend/storage/ipc/latch.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,9 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
640640
event->fd = fd;
641641
event->events = events;
642642
event->user_data = user_data;
643+
#ifdef WIN32
644+
event->reset = false;
645+
#endif
643646

644647
if (events == WL_LATCH_SET)
645648
{
@@ -1381,6 +1384,18 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
13811384
DWORD rc;
13821385
WaitEvent *cur_event;
13831386

1387+
/* Reset any wait events that need it */
1388+
for (cur_event = set->events;
1389+
cur_event < (set->events + set->nevents);
1390+
cur_event++)
1391+
{
1392+
if (cur_event->reset)
1393+
{
1394+
WaitEventAdjustWin32(set, cur_event);
1395+
cur_event->reset = false;
1396+
}
1397+
}
1398+
13841399
/*
13851400
* Sleep.
13861401
*
@@ -1464,6 +1479,18 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
14641479
{
14651480
/* data available in socket */
14661481
occurred_events->events |= WL_SOCKET_READABLE;
1482+
1483+
/*------
1484+
* WaitForMultipleObjects doesn't guarantee that a read event will
1485+
* be returned if the latch is set at the same time. Even if it
1486+
* did, the caller might drop that event expecting it to reoccur
1487+
* on next call. So, we must force the event to be reset if this
1488+
* WaitEventSet is used again in order to avoid an indefinite
1489+
* hang. Refer https://msdn.microsoft.com/en-us/library/windows/desktop/ms741576(v=vs.85).aspx
1490+
* for the behavior of socket events.
1491+
*------
1492+
*/
1493+
cur_event->reset = true;
14671494
}
14681495
if ((cur_event->events & WL_SOCKET_WRITEABLE) &&
14691496
(resEvents.lNetworkEvents & FD_WRITE))

src/include/storage/latch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ typedef struct WaitEvent
133133
uint32 events; /* triggered events */
134134
pgsocket fd; /* socket fd associated with event */
135135
void *user_data; /* pointer provided in AddWaitEventToSet */
136+
#ifdef WIN32
137+
bool reset; /* Is reset of the event required? */
138+
#endif
136139
} WaitEvent;
137140

138141
/* forward declaration to avoid exposing latch.c implementation details */

0 commit comments

Comments
 (0)