Skip to content

Commit fd735e9

Browse files
committed
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 3e7fdcf, which was back-patched only as far as 9.2.)
1 parent d27fad7 commit fd735e9

File tree

2 files changed

+19
-10
lines changed

2 files changed

+19
-10
lines changed

src/backend/port/unix_latch.c

+13-7
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
460460
result |= WL_SOCKET_WRITEABLE;
461461
}
462462
if ((wakeEvents & WL_POSTMASTER_DEATH) &&
463-
FD_ISSET(postmaster_alive_fds[POSTMASTER_FD_WATCH], &input_mask))
463+
FD_ISSET(postmaster_alive_fds[POSTMASTER_FD_WATCH],
464+
&input_mask))
464465
{
465466
/*
466467
* According to the select(2) man page on Linux, select(2) may
@@ -479,17 +480,22 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
479480
#endif /* HAVE_POLL */
480481

481482
/* If we're not done, update cur_timeout for next iteration */
482-
if (result == 0 && cur_timeout >= 0)
483+
if (result == 0 && (wakeEvents & WL_TIMEOUT))
483484
{
484485
INSTR_TIME_SET_CURRENT(cur_time);
485486
INSTR_TIME_SUBTRACT(cur_time, start_time);
486487
cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
487-
if (cur_timeout < 0)
488-
cur_timeout = 0;
489-
488+
if (cur_timeout <= 0)
489+
{
490+
/* Timeout has expired, no need to continue looping */
491+
result |= WL_TIMEOUT;
492+
}
490493
#ifndef HAVE_POLL
491-
tv.tv_sec = cur_timeout / 1000L;
492-
tv.tv_usec = (cur_timeout % 1000L) * 1000L;
494+
else
495+
{
496+
tv.tv_sec = cur_timeout / 1000L;
497+
tv.tv_usec = (cur_timeout % 1000L) * 1000L;
498+
}
493499
#endif
494500
}
495501
} while (result == 0);

src/backend/port/win32_latch.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,16 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
265265
elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %lu", rc);
266266

267267
/* If we're not done, update cur_timeout for next iteration */
268-
if (result == 0 && cur_timeout != INFINITE)
268+
if (result == 0 && (wakeEvents & WL_TIMEOUT))
269269
{
270270
INSTR_TIME_SET_CURRENT(cur_time);
271271
INSTR_TIME_SUBTRACT(cur_time, start_time);
272272
cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time);
273-
if (cur_timeout < 0)
274-
cur_timeout = 0;
273+
if (cur_timeout <= 0)
274+
{
275+
/* Timeout has expired, no need to continue looping */
276+
result |= WL_TIMEOUT;
277+
}
275278
}
276279
} while (result == 0);
277280

0 commit comments

Comments
 (0)