* Like WaitLatch, but with an extra socket argument for WL_SOCKET_*
* conditions.
*
- * When waiting on a socket, WL_SOCKET_READABLE *must* be included in
- * 'wakeEvents'; WL_SOCKET_WRITEABLE is optional. The reason for this is
- * that EOF and error conditions are reported only via WL_SOCKET_READABLE.
+ * When waiting on a socket, EOF and error conditions are reported by
+ * returning the socket as readable/writable or both, depending on
+ * WL_SOCKET_READABLE/WL_SOCKET_WRITEABLE being specified.
*/
int
WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
wakeEvents &= ~(WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE);
Assert(wakeEvents != 0); /* must have at least one wake event */
- /* Cannot specify WL_SOCKET_WRITEABLE without WL_SOCKET_READABLE */
- Assert((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) != WL_SOCKET_WRITEABLE);
if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid)
elog(ERROR, "cannot wait on a latch owned by another process");
break;
}
- /* Must wait ... we use poll(2) if available, otherwise select(2) */
+ /*
+ * Must wait ... we use poll(2) if available, otherwise select(2).
+ *
+ * On at least older linux kernels select(), in violation of POSIX,
+ * doesn't reliably return a socket as writable if closed - but we
+ * rely on that. So far all the known cases of this problem are on
+ * platforms that also provide a poll() implementation without that
+ * bug. If we find one where that's not the case, we'll need to add a
+ * workaround.
+ */
#ifdef HAVE_POLL
nfds = 0;
if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE))
{
/* at least one event occurred, so check revents values */
if ((wakeEvents & WL_SOCKET_READABLE) &&
- (pfds[0].revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL)))
+ (pfds[0].revents & POLLIN))
{
/* data available in socket, or EOF/error condition */
result |= WL_SOCKET_READABLE;
if ((wakeEvents & WL_SOCKET_WRITEABLE) &&
(pfds[0].revents & POLLOUT))
{
+ /* socket is writable */
result |= WL_SOCKET_WRITEABLE;
}
+ if (pfds[0].revents & (POLLHUP | POLLERR | POLLNVAL))
+ {
+ /* EOF/error condition */
+ if (wakeEvents & WL_SOCKET_READABLE)
+ result |= WL_SOCKET_READABLE;
+ if (wakeEvents & WL_SOCKET_WRITEABLE)
+ result |= WL_SOCKET_WRITEABLE;
+ }
/*
* We expect a POLLHUP when the remote end is closed, but because
}
if ((wakeEvents & WL_SOCKET_WRITEABLE) && FD_ISSET(sock, &output_mask))
{
+ /* socket is writable, or EOF */
result |= WL_SOCKET_WRITEABLE;
}
if ((wakeEvents & WL_POSTMASTER_DEATH) &&
wakeEvents &= ~(WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE);
Assert(wakeEvents != 0); /* must have at least one wake event */
- /* Cannot specify WL_SOCKET_WRITEABLE without WL_SOCKET_READABLE */
- Assert((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) != WL_SOCKET_WRITEABLE);
if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid)
elog(ERROR, "cannot wait on a latch owned by another process");
if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE))
{
/* Need an event object to represent events on the socket */
- int flags = 0;
+ int flags = FD_CLOSE; /* always check for errors/EOF */
if (wakeEvents & WL_SOCKET_READABLE)
- flags |= (FD_READ | FD_CLOSE);
+ flags |= FD_READ;
if (wakeEvents & WL_SOCKET_WRITEABLE)
flags |= FD_WRITE;
elog(ERROR, "failed to enumerate network events: error code %u",
WSAGetLastError());
if ((wakeEvents & WL_SOCKET_READABLE) &&
- (resEvents.lNetworkEvents & (FD_READ | FD_CLOSE)))
+ (resEvents.lNetworkEvents & FD_READ))
{
result |= WL_SOCKET_READABLE;
}
{
result |= WL_SOCKET_WRITEABLE;
}
+ if (resEvents.lNetworkEvents & FD_CLOSE)
+ {
+ if (wakeEvents & WL_SOCKET_READABLE)
+ result |= WL_SOCKET_READABLE;
+ if (wakeEvents & WL_SOCKET_WRITEABLE)
+ result |= WL_SOCKET_WRITEABLE;
+ }
}
else if ((wakeEvents & WL_POSTMASTER_DEATH) &&
rc == WAIT_OBJECT_0 + pmdeath_eventno)