#elif defined(WAIT_USE_WIN32)
/*
- * Wait using Windows' WaitForMultipleObjects().
+ * Wait using Windows' WaitForMultipleObjects(). Each call only "consumes" one
+ * event, so we keep calling until we've filled up our output buffer to match
+ * the behavior of the other implementations.
*
- * Unfortunately this will only ever return a single readiness notification at
- * a time. Note that while the official documentation for
- * WaitForMultipleObjects is ambiguous about multiple events being "consumed"
- * with a single bWaitAll = FALSE call,
- * https://blogs.msdn.microsoft.com/oldnewthing/20150409-00/?p=44273 confirms
- * that only one event is "consumed".
+ * https://blogs.msdn.microsoft.com/oldnewthing/20150409-00/?p=44273
*/
static inline int
WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
*/
cur_event = (WaitEvent *) &set->events[rc - WAIT_OBJECT_0 - 1];
- occurred_events->pos = cur_event->pos;
- occurred_events->user_data = cur_event->user_data;
- occurred_events->events = 0;
-
- if (cur_event->events == WL_LATCH_SET)
- {
- /*
- * We cannot use set->latch->event to reset the fired event if we
- * aren't waiting on this latch now.
- */
- if (!ResetEvent(set->handles[cur_event->pos + 1]))
- elog(ERROR, "ResetEvent failed: error code %lu", GetLastError());
-
- if (set->latch && set->latch->is_set)
- {
- occurred_events->fd = PGINVALID_SOCKET;
- occurred_events->events = WL_LATCH_SET;
- occurred_events++;
- returned_events++;
- }
- }
- else if (cur_event->events == WL_POSTMASTER_DEATH)
- {
- /*
- * Postmaster apparently died. Since the consequences of falsely
- * returning WL_POSTMASTER_DEATH could be pretty unpleasant, we take
- * the trouble to positively verify this with PostmasterIsAlive(),
- * even though there is no known reason to think that the event could
- * be falsely set on Windows.
- */
- if (!PostmasterIsAliveInternal())
- {
- if (set->exit_on_postmaster_death)
- proc_exit(1);
- occurred_events->fd = PGINVALID_SOCKET;
- occurred_events->events = WL_POSTMASTER_DEATH;
- occurred_events++;
- returned_events++;
- }
- }
- else if (cur_event->events & WL_SOCKET_MASK)
+ for (;;)
{
- WSANETWORKEVENTS resEvents;
- HANDLE handle = set->handles[cur_event->pos + 1];
-
- Assert(cur_event->fd);
+ int next_pos;
+ int count;
- occurred_events->fd = cur_event->fd;
+ occurred_events->pos = cur_event->pos;
+ occurred_events->user_data = cur_event->user_data;
+ occurred_events->events = 0;
- ZeroMemory(&resEvents, sizeof(resEvents));
- if (WSAEnumNetworkEvents(cur_event->fd, handle, &resEvents) != 0)
- elog(ERROR, "failed to enumerate network events: error code %d",
- WSAGetLastError());
- if ((cur_event->events & WL_SOCKET_READABLE) &&
- (resEvents.lNetworkEvents & FD_READ))
+ if (cur_event->events == WL_LATCH_SET)
{
- /* data available in socket */
- occurred_events->events |= WL_SOCKET_READABLE;
-
- /*------
- * WaitForMultipleObjects doesn't guarantee that a read event will
- * be returned if the latch is set at the same time. Even if it
- * did, the caller might drop that event expecting it to reoccur
- * on next call. So, we must force the event to be reset if this
- * WaitEventSet is used again in order to avoid an indefinite
- * hang. Refer https://msdn.microsoft.com/en-us/library/windows/desktop/ms741576(v=vs.85).aspx
- * for the behavior of socket events.
- *------
+ /*
+ * We cannot use set->latch->event to reset the fired event if we
+ * aren't waiting on this latch now.
*/
- cur_event->reset = true;
- }
- if ((cur_event->events & WL_SOCKET_WRITEABLE) &&
- (resEvents.lNetworkEvents & FD_WRITE))
- {
- /* writeable */
- occurred_events->events |= WL_SOCKET_WRITEABLE;
- }
- if ((cur_event->events & WL_SOCKET_CONNECTED) &&
- (resEvents.lNetworkEvents & FD_CONNECT))
- {
- /* connected */
- occurred_events->events |= WL_SOCKET_CONNECTED;
+ if (!ResetEvent(set->handles[cur_event->pos + 1]))
+ elog(ERROR, "ResetEvent failed: error code %lu", GetLastError());
+
+ if (set->latch && set->latch->is_set)
+ {
+ occurred_events->fd = PGINVALID_SOCKET;
+ occurred_events->events = WL_LATCH_SET;
+ occurred_events++;
+ returned_events++;
+ }
}
- if ((cur_event->events & WL_SOCKET_ACCEPT) &&
- (resEvents.lNetworkEvents & FD_ACCEPT))
+ else if (cur_event->events == WL_POSTMASTER_DEATH)
{
- /* incoming connection could be accepted */
- occurred_events->events |= WL_SOCKET_ACCEPT;
+ /*
+ * Postmaster apparently died. Since the consequences of falsely
+ * returning WL_POSTMASTER_DEATH could be pretty unpleasant, we
+ * take the trouble to positively verify this with
+ * PostmasterIsAlive(), even though there is no known reason to
+ * think that the event could be falsely set on Windows.
+ */
+ if (!PostmasterIsAliveInternal())
+ {
+ if (set->exit_on_postmaster_death)
+ proc_exit(1);
+ occurred_events->fd = PGINVALID_SOCKET;
+ occurred_events->events = WL_POSTMASTER_DEATH;
+ occurred_events++;
+ returned_events++;
+ }
}
- if (resEvents.lNetworkEvents & FD_CLOSE)
+ else if (cur_event->events & WL_SOCKET_MASK)
{
- /* EOF/error, so signal all caller-requested socket flags */
- occurred_events->events |= (cur_event->events & WL_SOCKET_MASK);
- }
+ WSANETWORKEVENTS resEvents;
+ HANDLE handle = set->handles[cur_event->pos + 1];
- if (occurred_events->events != 0)
- {
- occurred_events++;
- returned_events++;
+ Assert(cur_event->fd);
+
+ occurred_events->fd = cur_event->fd;
+
+ ZeroMemory(&resEvents, sizeof(resEvents));
+ if (WSAEnumNetworkEvents(cur_event->fd, handle, &resEvents) != 0)
+ elog(ERROR, "failed to enumerate network events: error code %d",
+ WSAGetLastError());
+ if ((cur_event->events & WL_SOCKET_READABLE) &&
+ (resEvents.lNetworkEvents & FD_READ))
+ {
+ /* data available in socket */
+ occurred_events->events |= WL_SOCKET_READABLE;
+
+ /*------
+ * WaitForMultipleObjects doesn't guarantee that a read event
+ * will be returned if the latch is set at the same time. Even
+ * if it did, the caller might drop that event expecting it to
+ * reoccur on next call. So, we must force the event to be
+ * reset if this WaitEventSet is used again in order to avoid
+ * an indefinite hang.
+ *
+ * Refer
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms741576(v=vs.85).aspx
+ * for the behavior of socket events.
+ *------
+ */
+ cur_event->reset = true;
+ }
+ if ((cur_event->events & WL_SOCKET_WRITEABLE) &&
+ (resEvents.lNetworkEvents & FD_WRITE))
+ {
+ /* writeable */
+ occurred_events->events |= WL_SOCKET_WRITEABLE;
+ }
+ if ((cur_event->events & WL_SOCKET_CONNECTED) &&
+ (resEvents.lNetworkEvents & FD_CONNECT))
+ {
+ /* connected */
+ occurred_events->events |= WL_SOCKET_CONNECTED;
+ }
+ if ((cur_event->events & WL_SOCKET_ACCEPT) &&
+ (resEvents.lNetworkEvents & FD_ACCEPT))
+ {
+ /* incoming connection could be accepted */
+ occurred_events->events |= WL_SOCKET_ACCEPT;
+ }
+ if (resEvents.lNetworkEvents & FD_CLOSE)
+ {
+ /* EOF/error, so signal all caller-requested socket flags */
+ occurred_events->events |= (cur_event->events & WL_SOCKET_MASK);
+ }
+
+ if (occurred_events->events != 0)
+ {
+ occurred_events++;
+ returned_events++;
+ }
}
+
+ /* Is the output buffer full? */
+ if (returned_events == nevents)
+ break;
+
+ /* Have we run out of possible events? */
+ next_pos = cur_event->pos + 1;
+ if (next_pos == set->nevents)
+ break;
+
+ /*
+ * Poll the rest of the event handles in the array starting at
+ * next_pos being careful to skip over the initial signal handle too.
+ * This time we use a zero timeout.
+ */
+ count = set->nevents - next_pos;
+ rc = WaitForMultipleObjects(count,
+ set->handles + 1 + next_pos,
+ false,
+ 0);
+
+ /*
+ * We don't distinguish between errors and WAIT_TIMEOUT here because
+ * we already have events to report.
+ */
+ if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0 + count)
+ break;
+
+ /* We have another event to decode. */
+ cur_event = &set->events[next_pos + (rc - WAIT_OBJECT_0)];
}
return returned_events;