diff options
Diffstat (limited to 'src/backend/port/unix_latch.c')
-rw-r--r-- | src/backend/port/unix_latch.c | 47 |
1 files changed, 40 insertions, 7 deletions
diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c index ff4ed8f16cf..a7482facebc 100644 --- a/src/backend/port/unix_latch.c +++ b/src/backend/port/unix_latch.c @@ -138,9 +138,12 @@ DisownLatch(volatile Latch *latch) * function returns immediately. * * The 'timeout' is given in milliseconds. It must be >= 0 if WL_TIMEOUT flag - * is given. On some platforms, signals cause the timeout to be restarted, - * so beware that the function can sleep for several times longer than the - * specified timeout. + * is given. On some platforms, signals do not interrupt the wait, or even + * cause the timeout to be restarted, so beware that the function can sleep + * for several times longer than the requested timeout. However, this + * difficulty is not so great as it seems, because the signal handlers for any + * signals that the caller should respond to ought to be programmed to end the + * wait by calling SetLatch. Ideally, the timeout parameter is vestigial. * * The latch must be owned by the current process, ie. it must be a * backend-local latch initialized with InitLatch, or a shared latch @@ -261,6 +264,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, { if (errno == EINTR) continue; + waiting = false; ereport(ERROR, (errcode_for_socket_access(), errmsg("select() failed: %m"))); @@ -294,6 +298,10 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, * Sets a latch and wakes up anyone waiting on it. * * This is cheap if the latch is already set, otherwise not so much. + * + * NB: when calling this in a signal handler, be sure to save and restore + * errno around it. (That's standard practice in most signal handlers, of + * course, but we used to omit it in handlers that only set a flag.) */ void SetLatch(volatile Latch *latch) @@ -339,7 +347,10 @@ SetLatch(volatile Latch *latch) if (owner_pid == 0) return; else if (owner_pid == MyProcPid) - sendSelfPipeByte(); + { + if (waiting) + sendSelfPipeByte(); + } else kill(owner_pid, SIGUSR1); } @@ -371,7 +382,11 @@ ResetLatch(volatile Latch *latch) * SetLatch uses SIGUSR1 to wake up the process waiting on the latch. * * Wake up WaitLatch, if we're waiting. (We might not be, since SIGUSR1 is - * overloaded for multiple purposes.) + * overloaded for multiple purposes; or we might not have reached WaitLatch + * yet, in which case we don't need to fill the pipe either.) + * + * NB: when calling this in a signal handler, be sure to save and restore + * errno around it. */ void latch_sigusr1_handler(void) @@ -435,13 +450,19 @@ retry: } } -/* Read all available data from the self-pipe */ +/* + * Read all available data from the self-pipe + * + * Note: this is only called when waiting = true. If it fails and doesn't + * return, it must reset that flag first (though ideally, this will never + * happen). + */ static void drainSelfPipe(void) { /* * There shouldn't normally be more than one byte in the pipe, or maybe a - * few more if multiple processes run SetLatch at the same instant. + * few bytes if multiple processes run SetLatch at the same instant. */ char buf[16]; int rc; @@ -456,9 +477,21 @@ drainSelfPipe(void) else if (errno == EINTR) continue; /* retry */ else + { + waiting = false; elog(ERROR, "read() on self-pipe failed: %m"); + } } else if (rc == 0) + { + waiting = false; elog(ERROR, "unexpected EOF on self-pipe"); + } + else if (rc < sizeof(buf)) + { + /* we successfully drained the pipe; no need to read() again */ + break; + } + /* else buffer wasn't big enough, so read again */ } } |