Header And Logo

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

Functions | Variables

proc.c File Reference

#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
#include "replication/syncrep.h"
#include "storage/ipc.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/procsignal.h"
#include "storage/spin.h"
#include "utils/timeout.h"
#include "utils/timestamp.h"
Include dependency graph for proc.c:

Go to the source code of this file.

Functions

static void RemoveProcFromArray (int code, Datum arg)
static void ProcKill (int code, Datum arg)
static void AuxiliaryProcKill (int code, Datum arg)
Size ProcGlobalShmemSize (void)
int ProcGlobalSemas (void)
void InitProcGlobal (void)
void InitProcess (void)
void InitProcessPhase2 (void)
void InitAuxiliaryProcess (void)
void PublishStartupProcessInformation (void)
void SetStartupBufferPinWaitBufId (int bufid)
int GetStartupBufferPinWaitBufId (void)
bool HaveNFreeProcs (int n)
bool IsWaitingForLock (void)
void LockErrorCleanup (void)
void ProcReleaseLocks (bool isCommit)
void ProcQueueInit (PROC_QUEUE *queue)
int ProcSleep (LOCALLOCK *locallock, LockMethod lockMethodTable)
PGPROCProcWakeup (PGPROC *proc, int waitStatus)
void ProcLockWakeup (LockMethod lockMethodTable, LOCK *lock)
void CheckDeadLock (void)
void ProcWaitForSignal (void)
void ProcSendSignal (int pid)

Variables

int DeadlockTimeout = 1000
int StatementTimeout = 0
int LockTimeout = 0
bool log_lock_waits = false
PGPROCMyProc = NULL
PGXACTMyPgXact = NULL
NON_EXEC_STATIC slock_tProcStructLock = NULL
PROC_HDRProcGlobal = NULL
NON_EXEC_STATIC PGPROCAuxiliaryProcs = NULL
PGPROCPreparedXactProcs = NULL
static LOCALLOCKlockAwaited = NULL
static volatile DeadLockState deadlock_state = DS_NOT_YET_CHECKED

Function Documentation

static void AuxiliaryProcKill ( int  code,
Datum  arg 
) [static]

Definition at line 850 of file proc.c.

References Assert, AuxiliaryProcs, DatumGetInt32, DisownLatch(), LWLockReleaseAll(), NUM_AUXILIARY_PROCS, PGPROC::pid, PGPROC::procLatch, ProcStructLock, SpinLockAcquire, SpinLockRelease, PROC_HDR::spins_per_delay, and update_spins_per_delay().

Referenced by InitAuxiliaryProcess().

{
    int         proctype = DatumGetInt32(arg);
    PGPROC     *auxproc PG_USED_FOR_ASSERTS_ONLY;

    Assert(proctype >= 0 && proctype < NUM_AUXILIARY_PROCS);

    auxproc = &AuxiliaryProcs[proctype];

    Assert(MyProc == auxproc);

    /* Release any LW locks I am holding (see notes above) */
    LWLockReleaseAll();

    /* Release ownership of the process's latch, too */
    DisownLatch(&MyProc->procLatch);

    SpinLockAcquire(ProcStructLock);

    /* Mark auxiliary proc no longer in use */
    MyProc->pid = 0;

    /* PGPROC struct isn't mine anymore */
    MyProc = NULL;

    /* Update shared estimate of spins_per_delay */
    ProcGlobal->spins_per_delay = update_spins_per_delay(ProcGlobal->spins_per_delay);

    SpinLockRelease(ProcStructLock);
}

void CheckDeadLock ( void   ) 

Definition at line 1429 of file proc.c.

References Assert, deadlock_state, DeadLockCheck(), DS_BLOCKED_BY_AUTOVACUUM, DS_HARD_DEADLOCK, FirstLockMgrLock, i, PGPROC::links, LockTagHashCode(), log_lock_waits, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SHM_QUEUE::next, NULL, PGSemaphoreUnlock(), SHM_QUEUE::prev, RemoveFromWaitQueue(), PGPROC::sem, LOCK::tag, and PGPROC::waitLock.

Referenced by InitPostgres().

{
    int         i;

    /*
     * Acquire exclusive lock on the entire shared lock data structures. Must
     * grab LWLocks in partition-number order to avoid LWLock deadlock.
     *
     * Note that the deadlock check interrupt had better not be enabled
     * anywhere that this process itself holds lock partition locks, else this
     * will wait forever.  Also note that LWLockAcquire creates a critical
     * section, so that this routine cannot be interrupted by cancel/die
     * interrupts.
     */
    for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
        LWLockAcquire(FirstLockMgrLock + i, LW_EXCLUSIVE);

    /*
     * Check to see if we've been awoken by anyone in the interim.
     *
     * If we have, we can return and resume our transaction -- happy day.
     * Before we are awoken the process releasing the lock grants it to us so
     * we know that we don't have to wait anymore.
     *
     * We check by looking to see if we've been unlinked from the wait queue.
     * This is quicker than checking our semaphore's state, since no kernel
     * call is needed, and it is safe because we hold the lock partition lock.
     */
    if (MyProc->links.prev == NULL ||
        MyProc->links.next == NULL)
        goto check_done;

#ifdef LOCK_DEBUG
    if (Debug_deadlocks)
        DumpAllLocks();
#endif

    /* Run the deadlock check, and set deadlock_state for use by ProcSleep */
    deadlock_state = DeadLockCheck(MyProc);

    if (deadlock_state == DS_HARD_DEADLOCK)
    {
        /*
         * Oops.  We have a deadlock.
         *
         * Get this process out of wait state. (Note: we could do this more
         * efficiently by relying on lockAwaited, but use this coding to
         * preserve the flexibility to kill some other transaction than the
         * one detecting the deadlock.)
         *
         * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, so
         * ProcSleep will report an error after we return from the signal
         * handler.
         */
        Assert(MyProc->waitLock != NULL);
        RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag)));

        /*
         * Unlock my semaphore so that the interrupted ProcSleep() call can
         * finish.
         */
        PGSemaphoreUnlock(&MyProc->sem);

        /*
         * We're done here.  Transaction abort caused by the error that
         * ProcSleep will raise will cause any other locks we hold to be
         * released, thus allowing other processes to wake up; we don't need
         * to do that here.  NOTE: an exception is that releasing locks we
         * hold doesn't consider the possibility of waiters that were blocked
         * behind us on the lock we just failed to get, and might now be
         * wakable because we're not in front of them anymore.  However,
         * RemoveFromWaitQueue took care of waking up any such processes.
         */
    }
    else if (log_lock_waits || deadlock_state == DS_BLOCKED_BY_AUTOVACUUM)
    {
        /*
         * Unlock my semaphore so that the interrupted ProcSleep() call can
         * print the log message (we daren't do it here because we are inside
         * a signal handler).  It will then sleep again until someone releases
         * the lock.
         *
         * If blocked by autovacuum, this wakeup will enable ProcSleep to send
         * the canceling signal to the autovacuum worker.
         */
        PGSemaphoreUnlock(&MyProc->sem);
    }

    /*
     * And release locks.  We do this in reverse order for two reasons: (1)
     * Anyone else who needs more than one of the locks will be trying to lock
     * them in increasing order; we don't want to release the other process
     * until it can get all the locks it needs. (2) This avoids O(N^2)
     * behavior inside LWLockRelease.
     */
check_done:
    for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
        LWLockRelease(FirstLockMgrLock + i);
}

int GetStartupBufferPinWaitBufId ( void   ) 

Definition at line 609 of file proc.c.

References PROC_HDR::startupBufferPinWaitBufId.

Referenced by HoldingBufferPinThatDelaysRecovery().

{
    /* use volatile pointer to prevent code rearrangement */
    volatile PROC_HDR *procglobal = ProcGlobal;

    return procglobal->startupBufferPinWaitBufId;
}

bool HaveNFreeProcs ( int  n  ) 

Definition at line 623 of file proc.c.

References PROC_HDR::freeProcs, PGPROC::links, SHM_QUEUE::next, NULL, ProcStructLock, SpinLockAcquire, and SpinLockRelease.

Referenced by InitPostgres().

{
    PGPROC     *proc;

    /* use volatile pointer to prevent code rearrangement */
    volatile PROC_HDR *procglobal = ProcGlobal;

    SpinLockAcquire(ProcStructLock);

    proc = procglobal->freeProcs;

    while (n > 0 && proc != NULL)
    {
        proc = (PGPROC *) proc->links.next;
        n--;
    }

    SpinLockRelease(ProcStructLock);

    return (n <= 0);
}

void InitAuxiliaryProcess ( void   ) 

Definition at line 463 of file proc.c.

References PROC_HDR::allPgXact, Assert, assert_enabled, AuxiliaryProcKill(), AuxiliaryProcs, PGPROC::backendId, PGPROC::databaseId, PGXACT::delayChkpt, elog, ERROR, FATAL, PGPROC::fpLocalTransactionId, PGPROC::fpVXIDLock, i, InitializeLatchSupport(), Int32GetDatum, PGPROC::links, PGPROC::lwWaiting, PGPROC::lwWaitLink, PGPROC::lwWaitMode, PGPROC::lxid, PGPROC::myProcLocks, MyProcPid, NULL, on_shmem_exit(), OwnLatch(), PANIC, PGPROC::pgprocno, PGSemaphoreReset(), PGPROC::pid, PGPROC::procLatch, ProcStructLock, PGPROC::roleId, PGPROC::sem, set_spins_per_delay(), SHMQueueElemInit(), SHMQueueEmpty(), SpinLockAcquire, SpinLockRelease, PROC_HDR::spins_per_delay, PGXACT::vacuumFlags, PGPROC::waitLock, PGPROC::waitProcLock, PGPROC::waitStatus, PGXACT::xid, and PGXACT::xmin.

Referenced by AuxiliaryProcessMain().

{
    PGPROC     *auxproc;
    int         proctype;

    /*
     * ProcGlobal should be set up already (if we are a backend, we inherit
     * this by fork() or EXEC_BACKEND mechanism from the postmaster).
     */
    if (ProcGlobal == NULL || AuxiliaryProcs == NULL)
        elog(PANIC, "proc header uninitialized");

    if (MyProc != NULL)
        elog(ERROR, "you already exist");

    /*
     * Initialize process-local latch support.  This could fail if the kernel
     * is low on resources, and if so we want to exit cleanly before acquiring
     * any shared-memory resources.
     */
    InitializeLatchSupport();

    /*
     * We use the ProcStructLock to protect assignment and releasing of
     * AuxiliaryProcs entries.
     *
     * While we are holding the ProcStructLock, also copy the current shared
     * estimate of spins_per_delay to local storage.
     */
    SpinLockAcquire(ProcStructLock);

    set_spins_per_delay(ProcGlobal->spins_per_delay);

    /*
     * Find a free auxproc ... *big* trouble if there isn't one ...
     */
    for (proctype = 0; proctype < NUM_AUXILIARY_PROCS; proctype++)
    {
        auxproc = &AuxiliaryProcs[proctype];
        if (auxproc->pid == 0)
            break;
    }
    if (proctype >= NUM_AUXILIARY_PROCS)
    {
        SpinLockRelease(ProcStructLock);
        elog(FATAL, "all AuxiliaryProcs are in use");
    }

    /* Mark auxiliary proc as in use by me */
    /* use volatile pointer to prevent code rearrangement */
    ((volatile PGPROC *) auxproc)->pid = MyProcPid;

    MyProc = auxproc;
    MyPgXact = &ProcGlobal->allPgXact[auxproc->pgprocno];

    SpinLockRelease(ProcStructLock);

    /*
     * Initialize all fields of MyProc, except for those previously
     * initialized by InitProcGlobal.
     */
    SHMQueueElemInit(&(MyProc->links));
    MyProc->waitStatus = STATUS_OK;
    MyProc->lxid = InvalidLocalTransactionId;
    MyProc->fpVXIDLock = false;
    MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
    MyPgXact->xid = InvalidTransactionId;
    MyPgXact->xmin = InvalidTransactionId;
    MyProc->backendId = InvalidBackendId;
    MyProc->databaseId = InvalidOid;
    MyProc->roleId = InvalidOid;
    MyPgXact->delayChkpt = false;
    MyPgXact->vacuumFlags = 0;
    MyProc->lwWaiting = false;
    MyProc->lwWaitMode = 0;
    MyProc->lwWaitLink = NULL;
    MyProc->waitLock = NULL;
    MyProc->waitProcLock = NULL;
#ifdef USE_ASSERT_CHECKING
    if (assert_enabled)
    {
        int         i;

        /* Last process should have released all locks. */
        for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
            Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
    }
#endif

    /*
     * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch.
     * Note that there's no particular need to do ResetLatch here.
     */
    OwnLatch(&MyProc->procLatch);

    /*
     * We might be reusing a semaphore that belonged to a failed process. So
     * be careful and reinitialize its value here.  (This is not strictly
     * necessary anymore, but seems like a good idea for cleanliness.)
     */
    PGSemaphoreReset(&MyProc->sem);

    /*
     * Arrange to clean up at process exit.
     */
    on_shmem_exit(AuxiliaryProcKill, Int32GetDatum(proctype));
}

void InitProcess ( void   ) 

Definition at line 278 of file proc.c.

References PROC_HDR::allPgXact, Assert, assert_enabled, PROC_HDR::autovacFreeProcs, PGPROC::backendId, PROC_HDR::bgworkerFreeProcs, PGPROC::databaseId, PGXACT::delayChkpt, elog, ereport, errcode(), errmsg(), ERROR, FATAL, PGPROC::fpLocalTransactionId, PGPROC::fpVXIDLock, PROC_HDR::freeProcs, i, InitDeadLockChecking(), InitializeLatchSupport(), IsAnyAutoVacuumProcess, IsAutoVacuumLauncherProcess(), IsAutoVacuumWorkerProcess(), IsBackgroundWorker, IsUnderPostmaster, PGPROC::links, PGPROC::lwWaiting, PGPROC::lwWaitLink, PGPROC::lwWaitMode, PGPROC::lxid, MarkPostmasterChildActive(), PGPROC::myProcLocks, MyProcPid, SHM_QUEUE::next, NULL, on_shmem_exit(), OwnLatch(), PANIC, PGPROC::pgprocno, PGSemaphoreReset(), PGPROC::pid, ProcKill(), PGPROC::procLatch, ProcStructLock, PGPROC::recoveryConflictPending, PGPROC::roleId, PGPROC::sem, set_spins_per_delay(), SHMQueueElemInit(), SHMQueueEmpty(), SpinLockAcquire, SpinLockRelease, PROC_HDR::spins_per_delay, PGPROC::syncRepLinks, PGPROC::syncRepState, PGXACT::vacuumFlags, PGPROC::waitLock, PGPROC::waitLSN, PGPROC::waitProcLock, PGPROC::waitStatus, PGXACT::xid, and PGXACT::xmin.

Referenced by AutoVacLauncherMain(), AutoVacWorkerMain(), BootstrapModeMain(), do_start_bgworker(), and PostgresMain().

{
    /* use volatile pointer to prevent code rearrangement */
    volatile PROC_HDR *procglobal = ProcGlobal;

    /*
     * ProcGlobal should be set up already (if we are a backend, we inherit
     * this by fork() or EXEC_BACKEND mechanism from the postmaster).
     */
    if (procglobal == NULL)
        elog(PANIC, "proc header uninitialized");

    if (MyProc != NULL)
        elog(ERROR, "you already exist");

    /*
     * Initialize process-local latch support.  This could fail if the kernel
     * is low on resources, and if so we want to exit cleanly before acquiring
     * any shared-memory resources.
     */
    InitializeLatchSupport();

    /*
     * Try to get a proc struct from the free list.  If this fails, we must be
     * out of PGPROC structures (not to mention semaphores).
     *
     * While we are holding the ProcStructLock, also copy the current shared
     * estimate of spins_per_delay to local storage.
     */
    SpinLockAcquire(ProcStructLock);

    set_spins_per_delay(procglobal->spins_per_delay);

    if (IsAnyAutoVacuumProcess())
        MyProc = procglobal->autovacFreeProcs;
    else if (IsBackgroundWorker)
        MyProc = procglobal->bgworkerFreeProcs;
    else
        MyProc = procglobal->freeProcs;

    if (MyProc != NULL)
    {
        if (IsAnyAutoVacuumProcess())
            procglobal->autovacFreeProcs = (PGPROC *) MyProc->links.next;
        else if (IsBackgroundWorker)
            procglobal->bgworkerFreeProcs = (PGPROC *) MyProc->links.next;
        else
            procglobal->freeProcs = (PGPROC *) MyProc->links.next;
        SpinLockRelease(ProcStructLock);
    }
    else
    {
        /*
         * If we reach here, all the PGPROCs are in use.  This is one of the
         * possible places to detect "too many backends", so give the standard
         * error message.  XXX do we need to give a different failure message
         * in the autovacuum case?
         */
        SpinLockRelease(ProcStructLock);
        ereport(FATAL,
                (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
                 errmsg("sorry, too many clients already")));
    }
    MyPgXact = &ProcGlobal->allPgXact[MyProc->pgprocno];

    /*
     * Now that we have a PGPROC, mark ourselves as an active postmaster
     * child; this is so that the postmaster can detect it if we exit without
     * cleaning up.  (XXX autovac launcher currently doesn't participate in
     * this; it probably should.)
     */
    if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess())
        MarkPostmasterChildActive();

    /*
     * Initialize all fields of MyProc, except for those previously
     * initialized by InitProcGlobal.
     */
    SHMQueueElemInit(&(MyProc->links));
    MyProc->waitStatus = STATUS_OK;
    MyProc->lxid = InvalidLocalTransactionId;
    MyProc->fpVXIDLock = false;
    MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
    MyPgXact->xid = InvalidTransactionId;
    MyPgXact->xmin = InvalidTransactionId;
    MyProc->pid = MyProcPid;
    /* backendId, databaseId and roleId will be filled in later */
    MyProc->backendId = InvalidBackendId;
    MyProc->databaseId = InvalidOid;
    MyProc->roleId = InvalidOid;
    MyPgXact->delayChkpt = false;
    MyPgXact->vacuumFlags = 0;
    /* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
    if (IsAutoVacuumWorkerProcess())
        MyPgXact->vacuumFlags |= PROC_IS_AUTOVACUUM;
    MyProc->lwWaiting = false;
    MyProc->lwWaitMode = 0;
    MyProc->lwWaitLink = NULL;
    MyProc->waitLock = NULL;
    MyProc->waitProcLock = NULL;
#ifdef USE_ASSERT_CHECKING
    if (assert_enabled)
    {
        int         i;

        /* Last process should have released all locks. */
        for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
            Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
    }
#endif
    MyProc->recoveryConflictPending = false;

    /* Initialize fields for sync rep */
    MyProc->waitLSN = 0;
    MyProc->syncRepState = SYNC_REP_NOT_WAITING;
    SHMQueueElemInit(&(MyProc->syncRepLinks));

    /*
     * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch.
     * Note that there's no particular need to do ResetLatch here.
     */
    OwnLatch(&MyProc->procLatch);

    /*
     * We might be reusing a semaphore that belonged to a failed process. So
     * be careful and reinitialize its value here.  (This is not strictly
     * necessary anymore, but seems like a good idea for cleanliness.)
     */
    PGSemaphoreReset(&MyProc->sem);

    /*
     * Arrange to clean up at backend exit.
     */
    on_shmem_exit(ProcKill, 0);

    /*
     * Now that we have a PGPROC, we could try to acquire locks, so initialize
     * the deadlock checker.
     */
    InitDeadLockChecking();
}

void InitProcessPhase2 ( void   ) 

Definition at line 428 of file proc.c.

References Assert, NULL, on_shmem_exit(), ProcArrayAdd(), and RemoveProcFromArray().

Referenced by InitPostgres().

{
    Assert(MyProc != NULL);

    /*
     * Add our PGPROC to the PGPROC array in shared memory.
     */
    ProcArrayAdd(MyProc);

    /*
     * Arrange to clean that up at backend exit.
     */
    on_shmem_exit(RemoveProcFromArray, 0);
}

void InitProcGlobal ( void   ) 

Definition at line 157 of file proc.c.

References PROC_HDR::allPgXact, PROC_HDR::allProcCount, PROC_HDR::allProcs, Assert, PROC_HDR::autovacFreeProcs, autovacuum_max_workers, AuxiliaryProcs, PGPROC::backendLock, PROC_HDR::bgworkerFreeProcs, PROC_HDR::checkpointerLatch, ereport, errcode(), errmsg(), FATAL, PROC_HDR::freeProcs, i, InitSharedLatch(), PGPROC::links, LWLockAssign(), max_prepared_xacts, MaxBackends, MaxConnections, MemSet, SHM_QUEUE::next, NUM_AUXILIARY_PROCS, PGPROC::pgprocno, PGSemaphoreCreate(), ProcStructLock, ShmemAlloc(), ShmemInitStruct(), SHMQueueInit(), SpinLockInit, PROC_HDR::spins_per_delay, PROC_HDR::startupBufferPinWaitBufId, PROC_HDR::startupProc, PROC_HDR::startupProcPid, and PROC_HDR::walwriterLatch.

Referenced by CreateSharedMemoryAndSemaphores().

{
    PGPROC     *procs;
    PGXACT     *pgxacts;
    int         i,
                j;
    bool        found;
    uint32      TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;

    /* Create the ProcGlobal shared structure */
    ProcGlobal = (PROC_HDR *)
        ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
    Assert(!found);

    /*
     * Initialize the data structures.
     */
    ProcGlobal->spins_per_delay = DEFAULT_SPINS_PER_DELAY;
    ProcGlobal->freeProcs = NULL;
    ProcGlobal->autovacFreeProcs = NULL;
    ProcGlobal->bgworkerFreeProcs = NULL;
    ProcGlobal->startupProc = NULL;
    ProcGlobal->startupProcPid = 0;
    ProcGlobal->startupBufferPinWaitBufId = -1;
    ProcGlobal->walwriterLatch = NULL;
    ProcGlobal->checkpointerLatch = NULL;

    /*
     * Create and initialize all the PGPROC structures we'll need.  There are
     * five separate consumers: (1) normal backends, (2) autovacuum workers
     * and the autovacuum launcher, (3) background workers, (4) auxiliary
     * processes, and (5) prepared transactions.  Each PGPROC structure is
     * dedicated to exactly one of these purposes, and they do not move between
     * groups.
     */
    procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC));
    ProcGlobal->allProcs = procs;
    ProcGlobal->allProcCount = TotalProcs;
    if (!procs)
        ereport(FATAL,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of shared memory")));
    MemSet(procs, 0, TotalProcs * sizeof(PGPROC));

    /*
     * Also allocate a separate array of PGXACT structures.  This is separate
     * from the main PGPROC array so that the most heavily accessed data is
     * stored contiguously in memory in as few cache lines as possible. This
     * provides significant performance benefits, especially on a
     * multiprocessor system.  There is one PGXACT structure for every PGPROC
     * structure.
     */
    pgxacts = (PGXACT *) ShmemAlloc(TotalProcs * sizeof(PGXACT));
    MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACT));
    ProcGlobal->allPgXact = pgxacts;

    for (i = 0; i < TotalProcs; i++)
    {
        /* Common initialization for all PGPROCs, regardless of type. */

        /*
         * Set up per-PGPROC semaphore, latch, and backendLock. Prepared xact
         * dummy PGPROCs don't need these though - they're never associated
         * with a real process
         */
        if (i < MaxBackends + NUM_AUXILIARY_PROCS)
        {
            PGSemaphoreCreate(&(procs[i].sem));
            InitSharedLatch(&(procs[i].procLatch));
            procs[i].backendLock = LWLockAssign();
        }
        procs[i].pgprocno = i;

        /*
         * Newly created PGPROCs for normal backends, autovacuum and bgworkers
         * must be queued up on the appropriate free list.  Because there can
         * only ever be a small, fixed number of auxiliary processes, no free
         * list is used in that case; InitAuxiliaryProcess() instead uses a
         * linear search.   PGPROCs for prepared transactions are added to a
         * free list by TwoPhaseShmemInit().
         */
        if (i < MaxConnections)
        {
            /* PGPROC for normal backend, add to freeProcs list */
            procs[i].links.next = (SHM_QUEUE *) ProcGlobal->freeProcs;
            ProcGlobal->freeProcs = &procs[i];
        }
        else if (i < MaxConnections + autovacuum_max_workers + 1)
        {
            /* PGPROC for AV launcher/worker, add to autovacFreeProcs list */
            procs[i].links.next = (SHM_QUEUE *) ProcGlobal->autovacFreeProcs;
            ProcGlobal->autovacFreeProcs = &procs[i];
        }
        else if (i < MaxBackends)
        {
            /* PGPROC for bgworker, add to bgworkerFreeProcs list */
            procs[i].links.next = (SHM_QUEUE *) ProcGlobal->bgworkerFreeProcs;
            ProcGlobal->bgworkerFreeProcs = &procs[i];
        }

        /* Initialize myProcLocks[] shared memory queues. */
        for (j = 0; j < NUM_LOCK_PARTITIONS; j++)
            SHMQueueInit(&(procs[i].myProcLocks[j]));
    }

    /*
     * Save pointers to the blocks of PGPROC structures reserved for auxiliary
     * processes and prepared transactions.
     */
    AuxiliaryProcs = &procs[MaxBackends];
    PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS];

    /* Create ProcStructLock spinlock, too */
    ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
    SpinLockInit(ProcStructLock);
}

bool IsWaitingForLock ( void   ) 

Definition at line 649 of file proc.c.

References NULL.

Referenced by RecoveryConflictInterrupt().

{
    if (lockAwaited == NULL)
        return false;

    return true;
}

void LockErrorCleanup ( void   ) 

Definition at line 666 of file proc.c.

References AbortStrongLockAcquire(), disable_timeouts(), GrantAwaitedLock(), LOCALLOCK::hashcode, DisableTimeoutParams::id, DisableTimeoutParams::keep_indicator, PGPROC::links, LockHashPartitionLock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SHM_QUEUE::next, NULL, RemoveFromWaitQueue(), STATUS_OK, and PGPROC::waitStatus.

Referenced by AbortSubTransaction(), AbortTransaction(), die(), ProcReleaseLocks(), RecoveryConflictInterrupt(), and StatementCancelHandler().

{
    LWLockId    partitionLock;
    DisableTimeoutParams timeouts[2];

    AbortStrongLockAcquire();

    /* Nothing to do if we weren't waiting for a lock */
    if (lockAwaited == NULL)
        return;

    /*
     * Turn off the deadlock and lock timeout timers, if they are still
     * running (see ProcSleep).  Note we must preserve the LOCK_TIMEOUT
     * indicator flag, since this function is executed before
     * ProcessInterrupts when responding to SIGINT; else we'd lose the
     * knowledge that the SIGINT came from a lock timeout and not an external
     * source.
     */
    timeouts[0].id = DEADLOCK_TIMEOUT;
    timeouts[0].keep_indicator = false;
    timeouts[1].id = LOCK_TIMEOUT;
    timeouts[1].keep_indicator = true;
    disable_timeouts(timeouts, 2);

    /* Unlink myself from the wait queue, if on it (might not be anymore!) */
    partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
    LWLockAcquire(partitionLock, LW_EXCLUSIVE);

    if (MyProc->links.next != NULL)
    {
        /* We could not have been granted the lock yet */
        RemoveFromWaitQueue(MyProc, lockAwaited->hashcode);
    }
    else
    {
        /*
         * Somebody kicked us off the lock queue already.  Perhaps they
         * granted us the lock, or perhaps they detected a deadlock. If they
         * did grant us the lock, we'd better remember it in our local lock
         * table.
         */
        if (MyProc->waitStatus == STATUS_OK)
            GrantAwaitedLock();
    }

    lockAwaited = NULL;

    LWLockRelease(partitionLock);

    /*
     * We used to do PGSemaphoreReset() here to ensure that our proc's wait
     * semaphore is reset to zero.  This prevented a leftover wakeup signal
     * from remaining in the semaphore if someone else had granted us the lock
     * we wanted before we were able to remove ourselves from the wait-list.
     * However, now that ProcSleep loops until waitStatus changes, a leftover
     * wakeup signal isn't harmful, and it seems not worth expending cycles to
     * get rid of a signal that most likely isn't there.
     */
}

int ProcGlobalSemas ( void   ) 

Definition at line 121 of file proc.c.

References MaxBackends.

Referenced by CreateSharedMemoryAndSemaphores().

{
    /*
     * We need a sema per backend (including autovacuum), plus one for each
     * auxiliary process.
     */
    return MaxBackends + NUM_AUXILIARY_PROCS;
}

Size ProcGlobalShmemSize ( void   ) 

Definition at line 95 of file proc.c.

References add_size(), max_prepared_xacts, MaxBackends, mul_size(), and NUM_AUXILIARY_PROCS.

Referenced by CreateSharedMemoryAndSemaphores().

{
    Size        size = 0;

    /* ProcGlobal */
    size = add_size(size, sizeof(PROC_HDR));
    /* MyProcs, including autovacuum workers and launcher */
    size = add_size(size, mul_size(MaxBackends, sizeof(PGPROC)));
    /* AuxiliaryProcs */
    size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGPROC)));
    /* Prepared xacts */
    size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGPROC)));
    /* ProcStructLock */
    size = add_size(size, sizeof(slock_t));

    size = add_size(size, mul_size(MaxBackends, sizeof(PGXACT)));
    size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGXACT)));
    size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGXACT)));

    return size;
}

static void ProcKill ( int  code,
Datum  arg 
) [static]

Definition at line 773 of file proc.c.

References Assert, assert_enabled, PROC_HDR::autovacFreeProcs, AutovacuumLauncherPid, PROC_HDR::bgworkerFreeProcs, DisownLatch(), PROC_HDR::freeProcs, i, IsAnyAutoVacuumProcess, IsAutoVacuumLauncherProcess(), IsBackgroundWorker, IsUnderPostmaster, PGPROC::links, LWLockReleaseAll(), MarkPostmasterChildInactive(), PGPROC::myProcLocks, SHM_QUEUE::next, NULL, PGPROC::procLatch, ProcStructLock, SHMQueueEmpty(), SIGUSR2, SpinLockAcquire, SpinLockRelease, PROC_HDR::spins_per_delay, SyncRepCleanupAtProcExit(), and update_spins_per_delay().

Referenced by InitProcess().

{
    /* use volatile pointer to prevent code rearrangement */
    volatile PROC_HDR *procglobal = ProcGlobal;

    Assert(MyProc != NULL);

    /* Make sure we're out of the sync rep lists */
    SyncRepCleanupAtProcExit();

#ifdef USE_ASSERT_CHECKING
    if (assert_enabled)
    {
        int         i;

        /* Last process should have released all locks. */
        for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
            Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));
    }
#endif

    /*
     * Release any LW locks I am holding.  There really shouldn't be any, but
     * it's cheap to check again before we cut the knees off the LWLock
     * facility by releasing our PGPROC ...
     */
    LWLockReleaseAll();

    /* Release ownership of the process's latch, too */
    DisownLatch(&MyProc->procLatch);

    SpinLockAcquire(ProcStructLock);

    /* Return PGPROC structure (and semaphore) to appropriate freelist */
    if (IsAnyAutoVacuumProcess())
    {
        MyProc->links.next = (SHM_QUEUE *) procglobal->autovacFreeProcs;
        procglobal->autovacFreeProcs = MyProc;
    }
    else if (IsBackgroundWorker)
    {
        MyProc->links.next = (SHM_QUEUE *) procglobal->bgworkerFreeProcs;
        procglobal->bgworkerFreeProcs = MyProc;
    }
    else
    {
        MyProc->links.next = (SHM_QUEUE *) procglobal->freeProcs;
        procglobal->freeProcs = MyProc;
    }

    /* PGPROC struct isn't mine anymore */
    MyProc = NULL;

    /* Update shared estimate of spins_per_delay */
    procglobal->spins_per_delay = update_spins_per_delay(procglobal->spins_per_delay);

    SpinLockRelease(ProcStructLock);

    /*
     * This process is no longer present in shared memory in any meaningful
     * way, so tell the postmaster we've cleaned up acceptably well. (XXX
     * autovac launcher should be included here someday)
     */
    if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess())
        MarkPostmasterChildInactive();

    /* wake autovac launcher if needed -- see comments in FreeWorkerInfo */
    if (AutovacuumLauncherPid != 0)
        kill(AutovacuumLauncherPid, SIGUSR2);
}

void ProcLockWakeup ( LockMethod  lockMethodTable,
LOCK lock 
)

Definition at line 1363 of file proc.c.

References Assert, LockMethodData::conflictTab, GrantLock(), PGPROC::links, PROC_QUEUE::links, LOCKBIT_ON, LockCheckConflicts(), SHM_QUEUE::next, ProcWakeup(), PROC_QUEUE::size, STATUS_OK, PGPROC::waitLockMode, PGPROC::waitProcLock, and LOCK::waitProcs.

Referenced by CleanUpLock(), and DeadLockCheck().

{
    PROC_QUEUE *waitQueue = &(lock->waitProcs);
    int         queue_size = waitQueue->size;
    PGPROC     *proc;
    LOCKMASK    aheadRequests = 0;

    Assert(queue_size >= 0);

    if (queue_size == 0)
        return;

    proc = (PGPROC *) waitQueue->links.next;

    while (queue_size-- > 0)
    {
        LOCKMODE    lockmode = proc->waitLockMode;

        /*
         * Waken if (a) doesn't conflict with requests of earlier waiters, and
         * (b) doesn't conflict with already-held locks.
         */
        if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
            LockCheckConflicts(lockMethodTable,
                               lockmode,
                               lock,
                               proc->waitProcLock,
                               proc) == STATUS_OK)
        {
            /* OK to waken */
            GrantLock(lock, proc->waitProcLock, lockmode);
            proc = ProcWakeup(proc, STATUS_OK);

            /*
             * ProcWakeup removes proc from the lock's waiting process queue
             * and returns the next proc in chain; don't use proc's next-link,
             * because it's been cleared.
             */
        }
        else
        {
            /*
             * Cannot wake this guy. Remember his request for later checks.
             */
            aheadRequests |= LOCKBIT_ON(lockmode);
            proc = (PGPROC *) proc->links.next;
        }
    }

    Assert(waitQueue->size >= 0);
}

void ProcQueueInit ( PROC_QUEUE queue  ) 

Definition at line 914 of file proc.c.

References PROC_QUEUE::links, SHMQueueInit(), and PROC_QUEUE::size.

Referenced by DeadLockCheck(), lock_twophase_recover(), and SetupLockInTable().

{
    SHMQueueInit(&(queue->links));
    queue->size = 0;
}

void ProcReleaseLocks ( bool  isCommit  ) 

Definition at line 745 of file proc.c.

References DEFAULT_LOCKMETHOD, LockErrorCleanup(), LockReleaseAll(), and USER_LOCKMETHOD.

Referenced by ResourceOwnerReleaseInternal().

{
    if (!MyProc)
        return;
    /* If waiting, get off wait queue (should only be needed after error) */
    LockErrorCleanup();
    /* Release standard locks, including session-level if aborting */
    LockReleaseAll(DEFAULT_LOCKMETHOD, !isCommit);
    /* Release transaction-level advisory locks */
    LockReleaseAll(USER_LOCKMETHOD, false);
}

void ProcSendSignal ( int  pid  ) 

Definition at line 1551 of file proc.c.

References BackendPidGetProc(), NULL, PGSemaphoreUnlock(), ProcStructLock, RecoveryInProgress(), PGPROC::sem, SpinLockAcquire, SpinLockRelease, PROC_HDR::startupProc, and PROC_HDR::startupProcPid.

Referenced by ReleasePredicateLocks(), and UnpinBuffer().

{
    PGPROC     *proc = NULL;

    if (RecoveryInProgress())
    {
        /* use volatile pointer to prevent code rearrangement */
        volatile PROC_HDR *procglobal = ProcGlobal;

        SpinLockAcquire(ProcStructLock);

        /*
         * Check to see whether it is the Startup process we wish to signal.
         * This call is made by the buffer manager when it wishes to wake up a
         * process that has been waiting for a pin in so it can obtain a
         * cleanup lock using LockBufferForCleanup(). Startup is not a normal
         * backend, so BackendPidGetProc() will not return any pid at all. So
         * we remember the information for this special case.
         */
        if (pid == procglobal->startupProcPid)
            proc = procglobal->startupProc;

        SpinLockRelease(ProcStructLock);
    }

    if (proc == NULL)
        proc = BackendPidGetProc(pid);

    if (proc != NULL)
        PGSemaphoreUnlock(&proc->sem);
}

int ProcSleep ( LOCALLOCK locallock,
LockMethod  lockMethodTable 
)

Definition at line 941 of file proc.c.

References _, PROC_HDR::allPgXact, appendStringInfo(), Assert, buf, CheckRecoveryConflictDeadlock(), LockMethodData::conflictTab, StringInfoData::data, deadlock_state, DEADLOCK_TIMEOUT, DeadlockTimeout, EnableTimeoutParams::delay_ms, DescribeLockTag(), disable_timeout(), disable_timeouts(), DS_BLOCKED_BY_AUTOVACUUM, DS_HARD_DEADLOCK, DS_NOT_YET_CHECKED, DS_SOFT_DEADLOCK, enable_timeout_after(), enable_timeouts(), ereport, errdetail_log(), errmsg(), get_timeout_start_time(), GetBlockingAutoVacuumPgproc(), GetCurrentTimestamp(), GetLockmodeName(), GrantAwaitedLock(), GrantLock(), LOCALLOCK::hashcode, PGPROC::heldLocks, i, DisableTimeoutParams::id, EnableTimeoutParams::id, initStringInfo(), InRecovery, DisableTimeoutParams::keep_indicator, PGPROC::links, PROC_QUEUE::links, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCKBIT_ON, LockCheckConflicts(), LockHashPartitionLock, LOCKTAG::locktag_lockmethodid, LockTimeout, LOG, log_lock_waits, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LOCALLOCKTAG::mode, MyProcPid, SHM_QUEUE::next, NULL, pfree(), PGPROC::pgprocno, PGSemaphoreLock(), PGPROC::pid, PROC_IS_AUTOVACUUM, PROC_VACUUM_FOR_WRAPAROUND, ProcArrayLock, LOCALLOCK::proclock, RecoveryInProgress(), RememberSimpleDeadLock(), RemoveFromWaitQueue(), PGPROC::sem, SHMQueueInsertBefore(), PROC_QUEUE::size, STATUS_ERROR, STATUS_OK, STATUS_WAITING, LOCK::tag, LOCALLOCK::tag, TimestampDifference(), EnableTimeoutParams::type, PGXACT::vacuumFlags, PGPROC::waitLock, PGPROC::waitLockMode, LOCK::waitMask, PGPROC::waitProcLock, LOCK::waitProcs, PGPROC::waitStatus, and WARNING.

Referenced by WaitOnLock().

{
    LOCKMODE    lockmode = locallock->tag.mode;
    LOCK       *lock = locallock->lock;
    PROCLOCK   *proclock = locallock->proclock;
    uint32      hashcode = locallock->hashcode;
    LWLockId    partitionLock = LockHashPartitionLock(hashcode);
    PROC_QUEUE *waitQueue = &(lock->waitProcs);
    LOCKMASK    myHeldLocks = MyProc->heldLocks;
    bool        early_deadlock = false;
    bool        allow_autovacuum_cancel = true;
    int         myWaitStatus;
    PGPROC     *proc;
    int         i;

    /*
     * Determine where to add myself in the wait queue.
     *
     * Normally I should go at the end of the queue.  However, if I already
     * hold locks that conflict with the request of any previous waiter, put
     * myself in the queue just in front of the first such waiter. This is not
     * a necessary step, since deadlock detection would move me to before that
     * waiter anyway; but it's relatively cheap to detect such a conflict
     * immediately, and avoid delaying till deadlock timeout.
     *
     * Special case: if I find I should go in front of some waiter, check to
     * see if I conflict with already-held locks or the requests before that
     * waiter.  If not, then just grant myself the requested lock immediately.
     * This is the same as the test for immediate grant in LockAcquire, except
     * we are only considering the part of the wait queue before my insertion
     * point.
     */
    if (myHeldLocks != 0)
    {
        LOCKMASK    aheadRequests = 0;

        proc = (PGPROC *) waitQueue->links.next;
        for (i = 0; i < waitQueue->size; i++)
        {
            /* Must he wait for me? */
            if (lockMethodTable->conflictTab[proc->waitLockMode] & myHeldLocks)
            {
                /* Must I wait for him ? */
                if (lockMethodTable->conflictTab[lockmode] & proc->heldLocks)
                {
                    /*
                     * Yes, so we have a deadlock.  Easiest way to clean up
                     * correctly is to call RemoveFromWaitQueue(), but we
                     * can't do that until we are *on* the wait queue. So, set
                     * a flag to check below, and break out of loop.  Also,
                     * record deadlock info for later message.
                     */
                    RememberSimpleDeadLock(MyProc, lockmode, lock, proc);
                    early_deadlock = true;
                    break;
                }
                /* I must go before this waiter.  Check special case. */
                if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
                    LockCheckConflicts(lockMethodTable,
                                       lockmode,
                                       lock,
                                       proclock,
                                       MyProc) == STATUS_OK)
                {
                    /* Skip the wait and just grant myself the lock. */
                    GrantLock(lock, proclock, lockmode);
                    GrantAwaitedLock();
                    return STATUS_OK;
                }
                /* Break out of loop to put myself before him */
                break;
            }
            /* Nope, so advance to next waiter */
            aheadRequests |= LOCKBIT_ON(proc->waitLockMode);
            proc = (PGPROC *) proc->links.next;
        }

        /*
         * If we fall out of loop normally, proc points to waitQueue head, so
         * we will insert at tail of queue as desired.
         */
    }
    else
    {
        /* I hold no locks, so I can't push in front of anyone. */
        proc = (PGPROC *) &(waitQueue->links);
    }

    /*
     * Insert self into queue, ahead of the given proc (or at tail of queue).
     */
    SHMQueueInsertBefore(&(proc->links), &(MyProc->links));
    waitQueue->size++;

    lock->waitMask |= LOCKBIT_ON(lockmode);

    /* Set up wait information in PGPROC object, too */
    MyProc->waitLock = lock;
    MyProc->waitProcLock = proclock;
    MyProc->waitLockMode = lockmode;

    MyProc->waitStatus = STATUS_WAITING;

    /*
     * If we detected deadlock, give up without waiting.  This must agree with
     * CheckDeadLock's recovery code, except that we shouldn't release the
     * semaphore since we haven't tried to lock it yet.
     */
    if (early_deadlock)
    {
        RemoveFromWaitQueue(MyProc, hashcode);
        return STATUS_ERROR;
    }

    /* mark that we are waiting for a lock */
    lockAwaited = locallock;

    /*
     * Release the lock table's partition lock.
     *
     * NOTE: this may also cause us to exit critical-section state, possibly
     * allowing a cancel/die interrupt to be accepted. This is OK because we
     * have recorded the fact that we are waiting for a lock, and so
     * LockErrorCleanup will clean up if cancel/die happens.
     */
    LWLockRelease(partitionLock);

    /*
     * Also, now that we will successfully clean up after an ereport, it's
     * safe to check to see if there's a buffer pin deadlock against the
     * Startup process.  Of course, that's only necessary if we're doing Hot
     * Standby and are not the Startup process ourselves.
     */
    if (RecoveryInProgress() && !InRecovery)
        CheckRecoveryConflictDeadlock();

    /* Reset deadlock_state before enabling the timeout handler */
    deadlock_state = DS_NOT_YET_CHECKED;

    /*
     * Set timer so we can wake up after awhile and check for a deadlock. If a
     * deadlock is detected, the handler releases the process's semaphore and
     * sets MyProc->waitStatus = STATUS_ERROR, allowing us to know that we
     * must report failure rather than success.
     *
     * By delaying the check until we've waited for a bit, we can avoid
     * running the rather expensive deadlock-check code in most cases.
     *
     * If LockTimeout is set, also enable the timeout for that.  We can save a
     * few cycles by enabling both timeout sources in one call.
     */
    if (LockTimeout > 0)
    {
        EnableTimeoutParams timeouts[2];

        timeouts[0].id = DEADLOCK_TIMEOUT;
        timeouts[0].type = TMPARAM_AFTER;
        timeouts[0].delay_ms = DeadlockTimeout;
        timeouts[1].id = LOCK_TIMEOUT;
        timeouts[1].type = TMPARAM_AFTER;
        timeouts[1].delay_ms = LockTimeout;
        enable_timeouts(timeouts, 2);
    }
    else
        enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout);

    /*
     * If someone wakes us between LWLockRelease and PGSemaphoreLock,
     * PGSemaphoreLock will not block.  The wakeup is "saved" by the semaphore
     * implementation.  While this is normally good, there are cases where a
     * saved wakeup might be leftover from a previous operation (for example,
     * we aborted ProcWaitForSignal just before someone did ProcSendSignal).
     * So, loop to wait again if the waitStatus shows we haven't been granted
     * nor denied the lock yet.
     *
     * We pass interruptOK = true, which eliminates a window in which
     * cancel/die interrupts would be held off undesirably.  This is a promise
     * that we don't mind losing control to a cancel/die interrupt here.  We
     * don't, because we have no shared-state-change work to do after being
     * granted the lock (the grantor did it all).  We do have to worry about
     * canceling the deadlock timeout and updating the locallock table, but if
     * we lose control to an error, LockErrorCleanup will fix that up.
     */
    do
    {
        PGSemaphoreLock(&MyProc->sem, true);

        /*
         * waitStatus could change from STATUS_WAITING to something else
         * asynchronously.  Read it just once per loop to prevent surprising
         * behavior (such as missing log messages).
         */
        myWaitStatus = MyProc->waitStatus;

        /*
         * If we are not deadlocked, but are waiting on an autovacuum-induced
         * task, send a signal to interrupt it.
         */
        if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && allow_autovacuum_cancel)
        {
            PGPROC     *autovac = GetBlockingAutoVacuumPgproc();
            PGXACT     *autovac_pgxact = &ProcGlobal->allPgXact[autovac->pgprocno];

            LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

            /*
             * Only do it if the worker is not working to protect against Xid
             * wraparound.
             */
            if ((autovac != NULL) &&
                (autovac_pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) &&
                !(autovac_pgxact->vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND))
            {
                int         pid = autovac->pid;
                StringInfoData locktagbuf;
                StringInfoData logbuf;      /* errdetail for server log */

                initStringInfo(&locktagbuf);
                initStringInfo(&logbuf);
                DescribeLockTag(&locktagbuf, &lock->tag);
                appendStringInfo(&logbuf,
                      _("Process %d waits for %s on %s."),
                         MyProcPid,
                         GetLockmodeName(lock->tag.locktag_lockmethodid,
                                         lockmode),
                         locktagbuf.data);

                /* release lock as quickly as possible */
                LWLockRelease(ProcArrayLock);

                ereport(LOG,
                        (errmsg("sending cancel to blocking autovacuum PID %d",
                            pid),
                         errdetail_log("%s", logbuf.data)));

                pfree(logbuf.data);
                pfree(locktagbuf.data);

                /* send the autovacuum worker Back to Old Kent Road */
                if (kill(pid, SIGINT) < 0)
                {
                    /* Just a warning to allow multiple callers */
                    ereport(WARNING,
                            (errmsg("could not send signal to process %d: %m",
                                    pid)));
                }
            }
            else
                LWLockRelease(ProcArrayLock);

            /* prevent signal from being resent more than once */
            allow_autovacuum_cancel = false;
        }

        /*
         * If awoken after the deadlock check interrupt has run, and
         * log_lock_waits is on, then report about the wait.
         */
        if (log_lock_waits && deadlock_state != DS_NOT_YET_CHECKED)
        {
            StringInfoData buf;
            const char *modename;
            long        secs;
            int         usecs;
            long        msecs;

            initStringInfo(&buf);
            DescribeLockTag(&buf, &locallock->tag.lock);
            modename = GetLockmodeName(locallock->tag.lock.locktag_lockmethodid,
                                       lockmode);
            TimestampDifference(get_timeout_start_time(DEADLOCK_TIMEOUT),
                                GetCurrentTimestamp(),
                                &secs, &usecs);
            msecs = secs * 1000 + usecs / 1000;
            usecs = usecs % 1000;

            if (deadlock_state == DS_SOFT_DEADLOCK)
                ereport(LOG,
                        (errmsg("process %d avoided deadlock for %s on %s by rearranging queue order after %ld.%03d ms",
                              MyProcPid, modename, buf.data, msecs, usecs)));
            else if (deadlock_state == DS_HARD_DEADLOCK)
            {
                /*
                 * This message is a bit redundant with the error that will be
                 * reported subsequently, but in some cases the error report
                 * might not make it to the log (eg, if it's caught by an
                 * exception handler), and we want to ensure all long-wait
                 * events get logged.
                 */
                ereport(LOG,
                        (errmsg("process %d detected deadlock while waiting for %s on %s after %ld.%03d ms",
                              MyProcPid, modename, buf.data, msecs, usecs)));
            }

            if (myWaitStatus == STATUS_WAITING)
                ereport(LOG,
                        (errmsg("process %d still waiting for %s on %s after %ld.%03d ms",
                              MyProcPid, modename, buf.data, msecs, usecs)));
            else if (myWaitStatus == STATUS_OK)
                ereport(LOG,
                    (errmsg("process %d acquired %s on %s after %ld.%03d ms",
                            MyProcPid, modename, buf.data, msecs, usecs)));
            else
            {
                Assert(myWaitStatus == STATUS_ERROR);

                /*
                 * Currently, the deadlock checker always kicks its own
                 * process, which means that we'll only see STATUS_ERROR when
                 * deadlock_state == DS_HARD_DEADLOCK, and there's no need to
                 * print redundant messages.  But for completeness and
                 * future-proofing, print a message if it looks like someone
                 * else kicked us off the lock.
                 */
                if (deadlock_state != DS_HARD_DEADLOCK)
                    ereport(LOG,
                            (errmsg("process %d failed to acquire %s on %s after %ld.%03d ms",
                              MyProcPid, modename, buf.data, msecs, usecs)));
            }

            /*
             * At this point we might still need to wait for the lock. Reset
             * state so we don't print the above messages again.
             */
            deadlock_state = DS_NO_DEADLOCK;

            pfree(buf.data);
        }
    } while (myWaitStatus == STATUS_WAITING);

    /*
     * Disable the timers, if they are still running
     */
    if (LockTimeout > 0)
    {
        DisableTimeoutParams timeouts[2];

        timeouts[0].id = DEADLOCK_TIMEOUT;
        timeouts[0].keep_indicator = false;
        timeouts[1].id = LOCK_TIMEOUT;
        timeouts[1].keep_indicator = false;
        disable_timeouts(timeouts, 2);
    }
    else
        disable_timeout(DEADLOCK_TIMEOUT, false);

    /*
     * Re-acquire the lock table's partition lock.  We have to do this to hold
     * off cancel/die interrupts before we can mess with lockAwaited (else we
     * might have a missed or duplicated locallock update).
     */
    LWLockAcquire(partitionLock, LW_EXCLUSIVE);

    /*
     * We no longer want LockErrorCleanup to do anything.
     */
    lockAwaited = NULL;

    /*
     * If we got the lock, be sure to remember it in the locallock table.
     */
    if (MyProc->waitStatus == STATUS_OK)
        GrantAwaitedLock();

    /*
     * We don't have to do anything else, because the awaker did all the
     * necessary update of the lock table and MyProc.
     */
    return MyProc->waitStatus;
}

void ProcWaitForSignal ( void   ) 
PGPROC* ProcWakeup ( PGPROC proc,
int  waitStatus 
)

Definition at line 1327 of file proc.c.

References Assert, PGPROC::links, SHM_QUEUE::next, NULL, PGSemaphoreUnlock(), SHM_QUEUE::prev, PGPROC::sem, SHMQueueDelete(), PROC_QUEUE::size, STATUS_WAITING, PGPROC::waitLock, PGPROC::waitProcLock, LOCK::waitProcs, and PGPROC::waitStatus.

Referenced by ProcLockWakeup().

{
    PGPROC     *retProc;

    /* Proc should be sleeping ... */
    if (proc->links.prev == NULL ||
        proc->links.next == NULL)
        return NULL;
    Assert(proc->waitStatus == STATUS_WAITING);

    /* Save next process before we zap the list link */
    retProc = (PGPROC *) proc->links.next;

    /* Remove process from wait queue */
    SHMQueueDelete(&(proc->links));
    (proc->waitLock->waitProcs.size)--;

    /* Clean up process' state and pass it the ok/fail signal */
    proc->waitLock = NULL;
    proc->waitProcLock = NULL;
    proc->waitStatus = waitStatus;

    /* And awaken it */
    PGSemaphoreUnlock(&proc->sem);

    return retProc;
}

void PublishStartupProcessInformation ( void   ) 

Definition at line 576 of file proc.c.

References MyProcPid, ProcStructLock, SpinLockAcquire, SpinLockRelease, PROC_HDR::startupProc, and PROC_HDR::startupProcPid.

Referenced by StartupXLOG().

{
    /* use volatile pointer to prevent code rearrangement */
    volatile PROC_HDR *procglobal = ProcGlobal;

    SpinLockAcquire(ProcStructLock);

    procglobal->startupProc = MyProc;
    procglobal->startupProcPid = MyProcPid;

    SpinLockRelease(ProcStructLock);
}

static void RemoveProcFromArray ( int  code,
Datum  arg 
) [static]

Definition at line 762 of file proc.c.

References Assert, InvalidTransactionId, NULL, and ProcArrayRemove().

Referenced by InitProcessPhase2().

void SetStartupBufferPinWaitBufId ( int  bufid  ) 

Definition at line 597 of file proc.c.

References PROC_HDR::startupBufferPinWaitBufId.

Referenced by LockBufferForCleanup().

{
    /* use volatile pointer to prevent code rearrangement */
    volatile PROC_HDR *procglobal = ProcGlobal;

    procglobal->startupBufferPinWaitBufId = bufid;
}


Variable Documentation

NON_EXEC_STATIC PGPROC* AuxiliaryProcs = NULL

Definition at line 76 of file proc.c.

Referenced by AuxiliaryProcKill(), InitAuxiliaryProcess(), and InitProcGlobal().

volatile DeadLockState deadlock_state = DS_NOT_YET_CHECKED [static]

Definition at line 83 of file proc.c.

Referenced by CheckDeadLock(), and ProcSleep().

int DeadlockTimeout = 1000

Definition at line 56 of file proc.c.

Referenced by ProcSleep(), and ResolveRecoveryConflictWithBufferPin().

LOCALLOCK* lockAwaited = NULL [static]

Definition at line 80 of file proc.c.

int LockTimeout = 0

Definition at line 58 of file proc.c.

Referenced by ProcSleep().

Definition at line 59 of file proc.c.

Referenced by CheckDeadLock(), and ProcSleep().

PGXACT* MyPgXact = NULL
PGPROC* MyProc = NULL

Definition at line 77 of file proc.c.

Referenced by TwoPhaseShmemInit().

NON_EXEC_STATIC slock_t* ProcStructLock = NULL

Definition at line 57 of file proc.c.

Referenced by start_xact_command().