Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions

latch.h File Reference

#include <signal.h>
Include dependency graph for latch.h:
This graph shows which files directly or indirectly include this file:

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 Documentation

#define TestLatch (   latch  )     (((volatile Latch *) (latch))->is_set)

Definition at line 127 of file latch.h.

#define WL_LATCH_SET   (1 << 0)
#define WL_POSTMASTER_DEATH   (1 << 4)
#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)

Function Documentation

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().

{
    Assert(latch->is_shared);
    Assert(latch->owner_pid == MyProcPid);

    latch->owner_pid = 0;
}

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   ) 
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().

{
    /* Assert InitializeLatchSupport has been called in this process */
    Assert(selfpipe_readfd >= 0);

    Assert(latch->is_shared);

    /* sanity check */
    if (latch->owner_pid != 0)
        elog(ERROR, "latch already owned");

    latch->owner_pid = MyProcPid;
}

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 
)
int WaitLatchOrSocket ( volatile Latch latch,
int  wakeEvents,
pgsocket  sock,
long  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;
}