mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
Change the autovacuum launcher to use WaitLatch instead of a poll loop.
In pursuit of this (and with the expectation that WaitLatch will be needed in more places), convert the latch field that was already added to PGPROC for sync rep into a generic latch that is activated for all PGPROC-owning processes, and change many of the standard backend signal handlers to set that latch when a signal happens. This will allow WaitLatch callers to be wakened properly by these signals. In passing, fix a whole bunch of signal handlers that had been hacked to do things that might change errno, without adding the necessary save/restore logic for errno. Also make some minor fixes in unix_latch.c, and clean up bizarre and unsafe scheme for disowning the process's latch. Much of this has to be back-patched into 9.1. Peter Geoghegan, with additional work by Tom
This commit is contained in:
@ -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 */
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user