aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-07-18 11:47:13 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-07-18 11:47:13 -0400
commit29efe1b5ebc82512cae363349bae6dd22e9b00eb (patch)
tree702a8aa5e7ad2b4c4eacc97db7645ddba2f03771
parentf3f037e187c601d76777ae10b10657a0c0d3299c (diff)
downloadpostgresql-29efe1b5ebc82512cae363349bae6dd22e9b00eb.tar.gz
postgresql-29efe1b5ebc82512cae363349bae6dd22e9b00eb.zip
Make WaitLatchOrSocket's timeout detection more robust.
In the previous coding, timeout would be noticed and reported only when poll() or socket() returned zero (or the equivalent behavior on Windows). Ordinarily that should work well enough, but it seems conceivable that we could get into a state where poll() always returns a nonzero value --- for example, if it is noticing a condition on one of the file descriptors that we do not think is reason to exit the loop. If that happened, we'd be in a busy-wait loop that would fail to terminate even when the timeout expires. We can make this more robust at essentially no cost, by deciding to exit of our own accord if we compute a zero or negative time-remaining-to-wait. Previously the code noted this but just clamped the time-remaining to zero, expecting that we'd detect timeout on the next loop iteration. Back-patch to 9.2. While 9.1 had a version of WaitLatchOrSocket, it was primitive compared to later versions, and did not guarantee reliable detection of timeouts anyway. (Essentially, this is a refinement of commit 3e7fdcffd6f77187, which was back-patched only as far as 9.2.)
-rw-r--r--src/backend/port/unix_latch.c20
-rw-r--r--src/backend/port/win32_latch.c9
2 files changed, 19 insertions, 10 deletions
diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c
index d0e928f8c49..abfc2455dbe 100644
--- a/src/backend/port/unix_latch.c
+++ b/src/backend/port/unix_latch.c
@@ -442,7 +442,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
result |= WL_SOCKET_WRITEABLE;
}
if ((wakeEvents & WL_POSTMASTER_DEATH) &&
- FD_ISSET(postmaster_alive_fds[POSTMASTER_FD_WATCH], &input_mask))
+ FD_ISSET(postmaster_alive_fds[POSTMASTER_FD_WATCH],
+ &input_mask))
{
/*
* According to the select(2) man page on Linux, select(2) may
@@ -461,17 +462,22 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
#endif /* HAVE_POLL */
/* If we're not done, update cur_timeout for next iteration */
- if (result == 0 && cur_timeout >= 0)
+ if (result == 0 && (wakeEvents & WL_TIMEOUT))
{
INSTR_TIME_SET_CURRENT(cur_time);
INSTR_TIME_SUBTRACT(cur_time, start_time);
cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
- if (cur_timeout < 0)
- cur_timeout = 0;
-
+ if (cur_timeout <= 0)
+ {
+ /* Timeout has expired, no need to continue looping */
+ result |= WL_TIMEOUT;
+ }
#ifndef HAVE_POLL
- tv.tv_sec = cur_timeout / 1000L;
- tv.tv_usec = (cur_timeout % 1000L) * 1000L;
+ else
+ {
+ tv.tv_sec = cur_timeout / 1000L;
+ tv.tv_usec = (cur_timeout % 1000L) * 1000L;
+ }
#endif
}
} while (result == 0);
diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c
index 6c50dbbe019..3cd3f83cad4 100644
--- a/src/backend/port/win32_latch.c
+++ b/src/backend/port/win32_latch.c
@@ -259,13 +259,16 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %lu", rc);
/* If we're not done, update cur_timeout for next iteration */
- if (result == 0 && cur_timeout != INFINITE)
+ if (result == 0 && (wakeEvents & WL_TIMEOUT))
{
INSTR_TIME_SET_CURRENT(cur_time);
INSTR_TIME_SUBTRACT(cur_time, start_time);
cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
- if (cur_timeout < 0)
- cur_timeout = 0;
+ if (cur_timeout <= 0)
+ {
+ /* Timeout has expired, no need to continue looping */
+ result |= WL_TIMEOUT;
+ }
}
} while (result == 0);