#include <signal.h>
Go to the source code of this file.
Data Structures | |
struct | Latch |
Defines | |
#define | WL_LATCH_SET (1 << 0) |
#define | WL_SOCKET_READABLE (1 << 1) |
#define | WL_SOCKET_WRITEABLE (1 << 2) |
#define | WL_TIMEOUT (1 << 3) |
#define | WL_POSTMASTER_DEATH (1 << 4) |
#define | TestLatch(latch) (((volatile Latch *) (latch))->is_set) |
Functions | |
void | InitializeLatchSupport (void) |
void | InitLatch (volatile Latch *latch) |
void | InitSharedLatch (volatile Latch *latch) |
void | OwnLatch (volatile Latch *latch) |
void | DisownLatch (volatile Latch *latch) |
int | WaitLatch (volatile Latch *latch, int wakeEvents, long timeout) |
int | WaitLatchOrSocket (volatile Latch *latch, int wakeEvents, pgsocket sock, long timeout) |
void | SetLatch (volatile Latch *latch) |
void | ResetLatch (volatile Latch *latch) |
void | latch_sigusr1_handler (void) |
#define TestLatch | ( | latch | ) | (((volatile Latch *) (latch))->is_set) |
#define WL_LATCH_SET (1 << 0) |
Definition at line 106 of file latch.h.
Referenced by AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), pgarch_MainLoop(), PgstatCollectorMain(), SyncRepWaitForLSN(), SysLoggerMain(), WaitForWALToBecomeAvailable(), WaitLatchOrSocket(), WalRcvWaitForStartPosition(), WalSndLoop(), WalWriterMain(), and worker_spi_main().
#define WL_POSTMASTER_DEATH (1 << 4) |
Definition at line 110 of file latch.h.
Referenced by AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), pgarch_MainLoop(), PgstatCollectorMain(), SyncRepWaitForLSN(), WaitLatchOrSocket(), WalRcvWaitForStartPosition(), WalSndLoop(), WalWriterMain(), and worker_spi_main().
#define WL_SOCKET_READABLE (1 << 1) |
Definition at line 107 of file latch.h.
Referenced by PgstatCollectorMain(), SysLoggerMain(), and WaitLatchOrSocket().
#define WL_SOCKET_WRITEABLE (1 << 2) |
Definition at line 108 of file latch.h.
Referenced by WaitLatchOrSocket().
#define WL_TIMEOUT (1 << 3) |
Definition at line 109 of file latch.h.
Referenced by AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), pgarch_MainLoop(), PgstatCollectorMain(), WaitForWALToBecomeAvailable(), WaitLatchOrSocket(), WalSndLoop(), WalWriterMain(), and worker_spi_main().
void DisownLatch | ( | volatile Latch * | latch | ) |
Definition at line 166 of file unix_latch.c.
References Assert, Latch::is_shared, MyProcPid, and Latch::owner_pid.
Referenced by AuxiliaryProcKill(), ProcKill(), StartupXLOG(), WalRcvDie(), and WalSndKill().
void InitializeLatchSupport | ( | void | ) |
Definition at line 77 of file unix_latch.c.
References Assert, elog, FATAL, selfpipe_readfd, and selfpipe_writefd.
Referenced by InitAuxiliaryProcess(), InitProcess(), PgArchiverMain(), PgstatCollectorMain(), and SysLoggerMain().
{ int pipefd[2]; Assert(selfpipe_readfd == -1); /* * Set up the self-pipe that allows a signal handler to wake up the * select() in WaitLatch. Make the write-end non-blocking, so that * SetLatch won't block if the event has already been set many times * filling the kernel buffer. Make the read-end non-blocking too, so that * we can easily clear the pipe by reading until EAGAIN or EWOULDBLOCK. */ if (pipe(pipefd) < 0) elog(FATAL, "pipe() failed: %m"); if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) < 0) elog(FATAL, "fcntl() failed on read-end of self-pipe: %m"); if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) < 0) elog(FATAL, "fcntl() failed on write-end of self-pipe: %m"); selfpipe_readfd = pipefd[0]; selfpipe_writefd = pipefd[1]; }
void InitLatch | ( | volatile Latch * | latch | ) |
Definition at line 105 of file unix_latch.c.
References Assert, elog, ERROR, FALSE, Latch::is_set, Latch::is_shared, MyProcPid, NULL, Latch::owner_pid, selfpipe_readfd, and TRUE.
Referenced by PgArchiverMain(), PgstatCollectorMain(), and SysLoggerMain().
{ /* Assert InitializeLatchSupport has been called in this process */ Assert(selfpipe_readfd >= 0); latch->is_set = false; latch->owner_pid = MyProcPid; latch->is_shared = false; }
void InitSharedLatch | ( | volatile Latch * | latch | ) |
Definition at line 127 of file unix_latch.c.
References elog, ERROR, FALSE, Latch::is_set, Latch::is_shared, NULL, Latch::owner_pid, and TRUE.
Referenced by InitProcGlobal(), WalRcvShmemInit(), WalSndShmemInit(), and XLOGShmemInit().
{ latch->is_set = false; latch->owner_pid = 0; latch->is_shared = true; }
void latch_sigusr1_handler | ( | void | ) |
Definition at line 581 of file unix_latch.c.
References sendSelfPipeByte(), and waiting.
Referenced by bgworker_sigusr1_handler(), bgwriter_sigusr1_handler(), chkpt_sigusr1_handler(), procsignal_sigusr1_handler(), StartupProcSigUsr1Handler(), WalRcvSigUsr1Handler(), WalSndXLogSendHandler(), and walwriter_sigusr1_handler().
{ if (waiting) sendSelfPipeByte(); }
void OwnLatch | ( | volatile Latch * | latch | ) |
Definition at line 148 of file unix_latch.c.
References Assert, elog, ERROR, Latch::is_shared, MyProcPid, Latch::owner_pid, and selfpipe_readfd.
Referenced by InitAuxiliaryProcess(), InitProcess(), InitWalSenderSlot(), StartupXLOG(), and WalReceiverMain().
void ResetLatch | ( | volatile Latch * | latch | ) |
Definition at line 552 of file unix_latch.c.
References Assert, Latch::is_set, MyProcPid, and Latch::owner_pid.
Referenced by AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), pgarch_MainLoop(), PgstatCollectorMain(), SyncRepWaitForLSN(), SysLoggerMain(), WaitForWALToBecomeAvailable(), WalRcvWaitForStartPosition(), WalSndLoop(), WalWriterMain(), and worker_spi_main().
{ /* Only the owner should reset the latch */ Assert(latch->owner_pid == MyProcPid); latch->is_set = false; /* * XXX there really ought to be a memory barrier operation right here, to * ensure that the write to is_set gets flushed to main memory before we * examine any flag variables. Otherwise a concurrent SetLatch might * falsely conclude that it needn't signal us, even though we have missed * seeing some flag updates that SetLatch was supposed to inform us of. * For the moment, callers must supply their own synchronization of flag * variables (see latch.h). */ }
void SetLatch | ( | volatile Latch * | latch | ) |
Definition at line 496 of file unix_latch.c.
References Latch::is_set, MyProcPid, Latch::owner_pid, sendSelfPipeByte(), SIGUSR1, and waiting.
Referenced by ArchSigHupHandler(), ArchSigTermHandler(), avl_sighup_handler(), avl_sigterm_handler(), avl_sigusr2_handler(), BgSigHupHandler(), ChkptSigHupHandler(), die(), ForwardFsyncRequest(), handle_sig_alarm(), pgarch_waken(), pgarch_waken_stop(), pgstat_exit(), pgstat_sighup_handler(), ReqCheckpointHandler(), ReqShutdownHandler(), RequestXLogStreaming(), SigHupHandler(), sigHupHandler(), sigUsr1Handler(), StatementCancelHandler(), StrategyGetBuffer(), SyncRepWakeQueue(), WakeupRecovery(), WalRcvShutdownHandler(), WalShutdownHandler(), WalSigHupHandler(), WalSndLastCycleHandler(), WalSndSigHupHandler(), WalSndWakeup(), worker_spi_sighup(), worker_spi_sigterm(), and XLogSetAsyncXactLSN().
{ pid_t owner_pid; /* * XXX there really ought to be a memory barrier operation right here, to * ensure that any flag variables we might have changed get flushed to * main memory before we check/set is_set. Without that, we have to * require that callers provide their own synchronization for machines * with weak memory ordering (see latch.h). */ /* Quick exit if already set */ if (latch->is_set) return; latch->is_set = true; /* * See if anyone's waiting for the latch. It can be the current process if * we're in a signal handler. We use the self-pipe to wake up the select() * in that case. If it's another process, send a signal. * * Fetch owner_pid only once, in case the latch is concurrently getting * owned or disowned. XXX: This assumes that pid_t is atomic, which isn't * guaranteed to be true! In practice, the effective range of pid_t fits * in a 32 bit integer, and so should be atomic. In the worst case, we * might end up signaling the wrong process. Even then, you're very * unlucky if a process with that bogus pid exists and belongs to * Postgres; and PG database processes should handle excess SIGUSR1 * interrupts without a problem anyhow. * * Another sort of race condition that's possible here is for a new * process to own the latch immediately after we look, so we don't signal * it. This is okay so long as all callers of ResetLatch/WaitLatch follow * the standard coding convention of waiting at the bottom of their loops, * not the top, so that they'll correctly process latch-setting events * that happen before they enter the loop. */ owner_pid = latch->owner_pid; if (owner_pid == 0) return; else if (owner_pid == MyProcPid) { if (waiting) sendSelfPipeByte(); } else kill(owner_pid, SIGUSR1); }
int WaitLatch | ( | volatile Latch * | latch, | |
int | wakeEvents, | |||
long | timeout | |||
) |
Definition at line 194 of file unix_latch.c.
References PGINVALID_SOCKET, and WaitLatchOrSocket().
Referenced by AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), pgarch_MainLoop(), SyncRepWaitForLSN(), SysLoggerMain(), WaitForWALToBecomeAvailable(), WalRcvWaitForStartPosition(), WalWriterMain(), and worker_spi_main().
{ return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout); }
Definition at line 208 of file unix_latch.c.
References Assert, drainSelfPipe(), EINTR, elog, ereport, errcode_for_socket_access(), errmsg(), ERROR, FALSE, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, Latch::is_set, MyProcPid, NULL, Latch::owner_pid, PGINVALID_SOCKET, pgwin32_dispatch_queued_signals(), pgwin32_signal_event, postmaster_alive_fds, POSTMASTER_FD_WATCH, PostmasterIsAlive(), select, selfpipe_readfd, start_time, waiting, WL_LATCH_SET, WL_POSTMASTER_DEATH, WL_SOCKET_READABLE, WL_SOCKET_WRITEABLE, and WL_TIMEOUT.
Referenced by PgstatCollectorMain(), SysLoggerMain(), WaitLatch(), and WalSndLoop().
{ int result = 0; int rc; instr_time start_time, cur_time; long cur_timeout; #ifdef HAVE_POLL struct pollfd pfds[3]; int nfds; #else struct timeval tv, *tvp; fd_set input_mask; fd_set output_mask; int hifd; #endif /* Ignore WL_SOCKET_* events if no valid socket is given */ if (sock == PGINVALID_SOCKET) 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"); /* * Initialize timeout if requested. We must record the current time so * that we can determine the remaining timeout if the poll() or select() * is interrupted. (On some platforms, select() will update the contents * of "tv" for us, but unfortunately we can't rely on that.) */ if (wakeEvents & WL_TIMEOUT) { INSTR_TIME_SET_CURRENT(start_time); Assert(timeout >= 0 && timeout <= INT_MAX); cur_timeout = timeout; #ifndef HAVE_POLL tv.tv_sec = cur_timeout / 1000L; tv.tv_usec = (cur_timeout % 1000L) * 1000L; tvp = &tv; #endif } else { cur_timeout = -1; #ifndef HAVE_POLL tvp = NULL; #endif } waiting = true; do { /* * Clear the pipe, then check if the latch is set already. If someone * sets the latch between this and the poll()/select() below, the * setter will write a byte to the pipe (or signal us and the signal * handler will do that), and the poll()/select() will return * immediately. * * Note: we assume that the kernel calls involved in drainSelfPipe() * and SetLatch() will provide adequate synchronization on machines * with weak memory ordering, so that we cannot miss seeing is_set if * the signal byte is already in the pipe when we drain it. */ drainSelfPipe(); if ((wakeEvents & WL_LATCH_SET) && latch->is_set) { result |= WL_LATCH_SET; /* * Leave loop immediately, avoid blocking again. We don't attempt * to report any other events that might also be satisfied. */ break; } /* Must wait ... we use poll(2) if available, otherwise select(2) */ #ifdef HAVE_POLL nfds = 0; if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) { /* socket, if used, is always in pfds[0] */ pfds[0].fd = sock; pfds[0].events = 0; if (wakeEvents & WL_SOCKET_READABLE) pfds[0].events |= POLLIN; if (wakeEvents & WL_SOCKET_WRITEABLE) pfds[0].events |= POLLOUT; pfds[0].revents = 0; nfds++; } pfds[nfds].fd = selfpipe_readfd; pfds[nfds].events = POLLIN; pfds[nfds].revents = 0; nfds++; if (wakeEvents & WL_POSTMASTER_DEATH) { /* postmaster fd, if used, is always in pfds[nfds - 1] */ pfds[nfds].fd = postmaster_alive_fds[POSTMASTER_FD_WATCH]; pfds[nfds].events = POLLIN; pfds[nfds].revents = 0; nfds++; } /* Sleep */ rc = poll(pfds, nfds, (int) cur_timeout); /* Check return code */ if (rc < 0) { /* EINTR is okay, otherwise complain */ if (errno != EINTR) { waiting = false; ereport(ERROR, (errcode_for_socket_access(), errmsg("poll() failed: %m"))); } } else if (rc == 0) { /* timeout exceeded */ if (wakeEvents & WL_TIMEOUT) result |= WL_TIMEOUT; } else { /* at least one event occurred, so check revents values */ if ((wakeEvents & WL_SOCKET_READABLE) && (pfds[0].revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL))) { /* data available in socket, or EOF/error condition */ result |= WL_SOCKET_READABLE; } if ((wakeEvents & WL_SOCKET_WRITEABLE) && (pfds[0].revents & POLLOUT)) { result |= WL_SOCKET_WRITEABLE; } /* * We expect a POLLHUP when the remote end is closed, but because * we don't expect the pipe to become readable or to have any * errors either, treat those cases as postmaster death, too. */ if ((wakeEvents & WL_POSTMASTER_DEATH) && (pfds[nfds - 1].revents & (POLLHUP | POLLIN | POLLERR | POLLNVAL))) { /* * According to the select(2) man page on Linux, select(2) may * spuriously return and report a file descriptor as readable, * when it's not; and presumably so can poll(2). It's not * clear that the relevant cases would ever apply to the * postmaster pipe, but since the consequences of falsely * returning WL_POSTMASTER_DEATH could be pretty unpleasant, * we take the trouble to positively verify EOF with * PostmasterIsAlive(). */ if (!PostmasterIsAlive()) result |= WL_POSTMASTER_DEATH; } } #else /* !HAVE_POLL */ FD_ZERO(&input_mask); FD_ZERO(&output_mask); FD_SET(selfpipe_readfd, &input_mask); hifd = selfpipe_readfd; if (wakeEvents & WL_POSTMASTER_DEATH) { FD_SET(postmaster_alive_fds[POSTMASTER_FD_WATCH], &input_mask); if (postmaster_alive_fds[POSTMASTER_FD_WATCH] > hifd) hifd = postmaster_alive_fds[POSTMASTER_FD_WATCH]; } if (wakeEvents & WL_SOCKET_READABLE) { FD_SET(sock, &input_mask); if (sock > hifd) hifd = sock; } if (wakeEvents & WL_SOCKET_WRITEABLE) { FD_SET(sock, &output_mask); if (sock > hifd) hifd = sock; } /* Sleep */ rc = select(hifd + 1, &input_mask, &output_mask, NULL, tvp); /* Check return code */ if (rc < 0) { /* EINTR is okay, otherwise complain */ if (errno != EINTR) { waiting = false; ereport(ERROR, (errcode_for_socket_access(), errmsg("select() failed: %m"))); } } else if (rc == 0) { /* timeout exceeded */ if (wakeEvents & WL_TIMEOUT) result |= WL_TIMEOUT; } else { /* at least one event occurred, so check masks */ if ((wakeEvents & WL_SOCKET_READABLE) && FD_ISSET(sock, &input_mask)) { /* data available in socket, or EOF */ result |= WL_SOCKET_READABLE; } if ((wakeEvents & WL_SOCKET_WRITEABLE) && FD_ISSET(sock, &output_mask)) { result |= WL_SOCKET_WRITEABLE; } if ((wakeEvents & WL_POSTMASTER_DEATH) && FD_ISSET(postmaster_alive_fds[POSTMASTER_FD_WATCH], &input_mask)) { /* * According to the select(2) man page on Linux, select(2) may * spuriously return and report a file descriptor as readable, * when it's not; and presumably so can poll(2). It's not * clear that the relevant cases would ever apply to the * postmaster pipe, but since the consequences of falsely * returning WL_POSTMASTER_DEATH could be pretty unpleasant, * we take the trouble to positively verify EOF with * PostmasterIsAlive(). */ if (!PostmasterIsAlive()) result |= WL_POSTMASTER_DEATH; } } #endif /* HAVE_POLL */ /* If we're not done, update cur_timeout for next iteration */ if (result == 0 && cur_timeout >= 0) { 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; #ifndef HAVE_POLL tv.tv_sec = cur_timeout / 1000L; tv.tv_usec = (cur_timeout % 1000L) * 1000L; #endif } } while (result == 0); waiting = false; return result; }