Header And Logo

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

Data Structures | Defines | Typedefs | Enumerations | Functions | Variables

postmaster.c File Reference

#include "postgres.h"
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <limits.h>
#include "access/transam.h"
#include "access/xlog.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_control.h"
#include "lib/ilist.h"
#include "libpq/auth.h"
#include "libpq/ip.h"
#include "libpq/libpq.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/bgworker.h"
#include "postmaster/fork_process.h"
#include "postmaster/pgarch.h"
#include "postmaster/postmaster.h"
#include "postmaster/syslogger.h"
#include "replication/walsender.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
Include dependency graph for postmaster.c:

Go to the source code of this file.

Data Structures

struct  bkend
struct  RegisteredBgWorker

Defines

#define BACKEND_TYPE_NORMAL   0x0001
#define BACKEND_TYPE_AUTOVAC   0x0002
#define BACKEND_TYPE_WALSND   0x0004
#define BACKEND_TYPE_BGWORKER   0x0008
#define BACKEND_TYPE_ALL   0x000F
#define BACKEND_TYPE_WORKER   (BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER)
#define MAXLISTEN   64
#define NoShutdown   0
#define SmartShutdown   1
#define FastShutdown   2
#define SignalChildren(sig)   SignalSomeChildren(sig, BACKEND_TYPE_ALL)
#define StartupDataBase()   StartChildProcess(StartupProcess)
#define StartBackgroundWriter()   StartChildProcess(BgWriterProcess)
#define StartCheckpointer()   StartChildProcess(CheckpointerProcess)
#define StartWalWriter()   StartChildProcess(WalWriterProcess)
#define StartWalReceiver()   StartChildProcess(WalReceiverProcess)
#define EXIT_STATUS_0(st)   ((st) == 0)
#define EXIT_STATUS_1(st)   (WIFEXITED(st) && WEXITSTATUS(st) == 1)
#define OPTS_FILE   "postmaster.opts"

Typedefs

typedef struct bkend Backend
typedef struct RegisteredBgWorker RegisteredBgWorker

Enumerations

enum  PMState {
  PM_INIT, PM_STARTUP, PM_RECOVERY, PM_HOT_STANDBY,
  PM_RUN, PM_WAIT_BACKUP, PM_WAIT_READONLY, PM_WAIT_BACKENDS,
  PM_SHUTDOWN, PM_SHUTDOWN_2, PM_WAIT_DEAD_END, PM_NO_CHILDREN
}

Functions

static void unlink_external_pid_file (int status, Datum arg)
static void getInstallationPaths (const char *argv0)
static void checkDataDir (void)
static PortConnCreate (int serverFd)
static void ConnFree (Port *port)
static void reset_shared (int port)
static void SIGHUP_handler (SIGNAL_ARGS)
static void pmdie (SIGNAL_ARGS)
static void reaper (SIGNAL_ARGS)
static void sigusr1_handler (SIGNAL_ARGS)
static void startup_die (SIGNAL_ARGS)
static void dummy_handler (SIGNAL_ARGS)
static int GetNumRegisteredBackgroundWorkers (int flags)
static void StartupPacketTimeoutHandler (void)
static void CleanupBackend (int pid, int exitstatus)
static bool CleanupBackgroundWorker (int pid, int exitstatus)
static void do_start_bgworker (void)
static void HandleChildCrash (int pid, int exitstatus, const char *procname)
static void LogChildExit (int lev, const char *procname, int pid, int exitstatus)
static void PostmasterStateMachine (void)
static void BackendInitialize (Port *port)
static void BackendRun (Port *port) __attribute__((noreturn))
static void ExitPostmaster (int status) __attribute__((noreturn))
static int ServerLoop (void)
static int BackendStartup (Port *port)
static int ProcessStartupPacket (Port *port, bool SSLdone)
static void processCancelRequest (Port *port, void *pkt)
static int initMasks (fd_set *rmask)
static void report_fork_failure_to_client (Port *port, int errnum)
static CAC_state canAcceptConnections (void)
static long PostmasterRandom (void)
static void RandomSalt (char *md5Salt)
static void signal_child (pid_t pid, int signal)
static bool SignalSomeChildren (int signal, int targets)
static bool SignalUnconnectedWorkers (int signal)
static int CountChildren (int target)
static int CountUnconnectedWorkers (void)
static void StartOneBackgroundWorker (void)
static bool CreateOptsFile (int argc, char *argv[], char *fullprogname)
static pid_t StartChildProcess (AuxProcType type)
static void StartAutovacuumWorker (void)
static void InitPostmasterDeathWatchHandle (void)
void PostmasterMain (int argc, char *argv[])
static void DetermineSleepTime (struct timeval *timeout)
void ClosePostmasterPorts (bool am_syslogger)
int MaxLivePostmasterChildren (void)
void RegisterBackgroundWorker (BackgroundWorker *worker)
void BackgroundWorkerInitializeConnection (char *dbname, char *username)
void BackgroundWorkerBlockSignals (void)
void BackgroundWorkerUnblockSignals (void)
static void bgworker_quickdie (SIGNAL_ARGS)
static void bgworker_die (SIGNAL_ARGS)
static void bgworker_sigusr1_handler (SIGNAL_ARGS)
int GetNumShmemAttachedBgworkers (void)
static void start_bgworker (RegisteredBgWorker *rw)
static bool bgworker_should_start_now (BgWorkerStartTime start_time)
static bool assign_backendlist_entry (RegisteredBgWorker *rw)

Variables

static dlist_head BackendList = DLIST_STATIC_INIT(BackendList)
static slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList)
BackgroundWorkerMyBgworkerEntry = NULL
int PostPortNumber
char * Unix_socket_directories
char * ListenAddresses
int ReservedBackends
static pgsocket ListenSocket [MAXLISTEN]
static char ExtraOptions [MAXPGPATH]
static bool Reinit = true
static int SendStop = false
bool EnableSSL = false
int PreAuthDelay = 0
int AuthenticationTimeout = 60
bool log_hostname
bool Log_connections = false
bool Db_user_namespace = false
bool enable_bonjour = false
char * bonjour_name
bool restart_after_crash = true
char * output_config_variable = NULL
static pid_t StartupPID = 0
static pid_t BgWriterPID = 0
static pid_t CheckpointerPID = 0
static pid_t WalWriterPID = 0
static pid_t WalReceiverPID = 0
static pid_t AutoVacPID = 0
static pid_t PgArchPID = 0
static pid_t PgStatPID = 0
static pid_t SysLoggerPID = 0
static int Shutdown = NoShutdown
static bool FatalError = false
static bool RecoveryError = false
static PMState pmState = PM_INIT
static bool ReachedNormalRunning = false
bool ClientAuthInProgress = false
bool redirection_done = false
static volatile sig_atomic_t start_autovac_launcher = false
static volatile bool avlauncher_needs_signal = false
static volatile bool StartWorkerNeeded = true
static volatile bool HaveCrashedWorker = false
static unsigned int random_seed = 0
static struct timeval random_start_time
char * optarg
int optind
int opterr
int postmaster_alive_fds [2] = {-1, -1}

Define Documentation

#define BACKEND_TYPE_ALL   0x000F
#define BACKEND_TYPE_AUTOVAC   0x0002

Definition at line 135 of file postmaster.c.

Referenced by pmdie().

#define BACKEND_TYPE_BGWORKER   0x0008

Definition at line 137 of file postmaster.c.

Referenced by HandleChildCrash(), and pmdie().

#define BACKEND_TYPE_NORMAL   0x0001

Definition at line 134 of file postmaster.c.

Referenced by CountChildren(), pmdie(), PostmasterStateMachine(), and SignalSomeChildren().

#define BACKEND_TYPE_WALSND   0x0004

Definition at line 136 of file postmaster.c.

#define BACKEND_TYPE_WORKER   (BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER)

Definition at line 140 of file postmaster.c.

Referenced by PostmasterStateMachine().

#define EXIT_STATUS_0 (   st  )     ((st) == 0)

Definition at line 539 of file postmaster.c.

Referenced by CleanupBackend(), CleanupBackgroundWorker(), LogChildExit(), and reaper().

#define EXIT_STATUS_1 (   st  )     (WIFEXITED(st) && WEXITSTATUS(st) == 1)

Definition at line 540 of file postmaster.c.

Referenced by CleanupBackend(), CleanupBackgroundWorker(), and reaper().

#define FastShutdown   2

Definition at line 275 of file postmaster.c.

Referenced by pmdie().

#define MAXLISTEN   64

Definition at line 227 of file postmaster.c.

#define NoShutdown   0
#define OPTS_FILE   "postmaster.opts"

Referenced by CreateOptsFile().

#define SignalChildren (   sig  )     SignalSomeChildren(sig, BACKEND_TYPE_ALL)

Definition at line 423 of file postmaster.c.

Referenced by pmdie(), PostmasterStateMachine(), reaper(), and SIGHUP_handler().

#define SmartShutdown   1

Definition at line 274 of file postmaster.c.

Referenced by pmdie(), and SIGHUP_handler().

#define StartBackgroundWriter (  )     StartChildProcess(BgWriterProcess)

Definition at line 533 of file postmaster.c.

Referenced by reaper(), ServerLoop(), and sigusr1_handler().

#define StartCheckpointer (  )     StartChildProcess(CheckpointerProcess)

Definition at line 534 of file postmaster.c.

Referenced by PostmasterStateMachine(), reaper(), ServerLoop(), and sigusr1_handler().

#define StartupDataBase (  )     StartChildProcess(StartupProcess)

Definition at line 532 of file postmaster.c.

Referenced by PostmasterMain(), and PostmasterStateMachine().

#define StartWalReceiver (  )     StartChildProcess(WalReceiverProcess)

Definition at line 536 of file postmaster.c.

Referenced by sigusr1_handler().

#define StartWalWriter (  )     StartChildProcess(WalWriterProcess)

Definition at line 535 of file postmaster.c.

Referenced by reaper(), and ServerLoop().


Typedef Documentation

typedef struct bkend Backend

Enumeration Type Documentation

enum PMState
Enumerator:
PM_INIT 
PM_STARTUP 
PM_RECOVERY 
PM_HOT_STANDBY 
PM_RUN 
PM_WAIT_BACKUP 
PM_WAIT_READONLY 
PM_WAIT_BACKENDS 
PM_SHUTDOWN 
PM_SHUTDOWN_2 
PM_WAIT_DEAD_END 
PM_NO_CHILDREN 

Definition at line 326 of file postmaster.c.

{
    PM_INIT,                    /* postmaster starting */
    PM_STARTUP,                 /* waiting for startup subprocess */
    PM_RECOVERY,                /* in archive recovery mode */
    PM_HOT_STANDBY,             /* in hot standby mode */
    PM_RUN,                     /* normal "database is alive" state */
    PM_WAIT_BACKUP,             /* waiting for online backup mode to end */
    PM_WAIT_READONLY,           /* waiting for read only backends to exit */
    PM_WAIT_BACKENDS,           /* waiting for live backends to exit */
    PM_SHUTDOWN,                /* waiting for checkpointer to do shutdown
                                 * ckpt */
    PM_SHUTDOWN_2,              /* waiting for archiver and walsenders to
                                 * finish */
    PM_WAIT_DEAD_END,           /* waiting for dead_end children to exit */
    PM_NO_CHILDREN              /* all important children have exited */
} PMState;


Function Documentation

static bool assign_backendlist_entry ( RegisteredBgWorker rw  )  [static]

Definition at line 5661 of file postmaster.c.

References AssignPostmasterChildSlot(), bkend::bkend_type, bkend::cancel_key, bkend::child_slot, bkend::dead_end, ereport, errcode(), errmsg(), GetCurrentTimestamp(), LOG, malloc, MyCancelKey, MyPMChildSlot, NULL, PostmasterRandom(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, and RegisteredBgWorker::rw_crashed_at.

Referenced by StartOneBackgroundWorker().

{
    Backend    *bn = malloc(sizeof(Backend));

    if (bn == NULL)
    {
        ereport(LOG,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of memory")));

        /*
         * The worker didn't really crash, but setting this nonzero makes
         * postmaster wait a bit before attempting to start it again; if it
         * tried again right away, most likely it'd find itself under the same
         * memory pressure.
         */
        rw->rw_crashed_at = GetCurrentTimestamp();
        return false;
    }

    /*
     * Compute the cancel key that will be assigned to this session. We
     * probably don't need cancel keys for background workers, but we'd better
     * have something random in the field to prevent unfriendly people from
     * sending cancels to them.
     */
    MyCancelKey = PostmasterRandom();
    bn->cancel_key = MyCancelKey;

    bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
    bn->bkend_type = BACKEND_TYPE_BGWORKER;
    bn->dead_end = false;

    rw->rw_backend = bn;
    rw->rw_child_slot = bn->child_slot;

    return true;
}

static void BackendInitialize ( Port port  )  [static]

Definition at line 3756 of file postmaster.c.

References SockAddr::addr, am_walsender, AuthenticationTimeout, BlockSig, ClientAuthInProgress, Port::database_name, disable_timeout(), elog, enable_timeout_after(), ereport, errmsg(), errmsg_internal(), FATAL, gai_strerror, GetCurrentTimestamp(), init_ps_display(), InitializeTimeouts(), LOG, Log_connections, log_hostname, MyProcPort, MyStartTime, NI_NUMERICHOST, NI_NUMERICSERV, pg_getnameinfo_all(), PG_SETMASK, pg_usleep(), pq_init(), pqsignal(), PreAuthDelay, proc_exit(), ProcessStartupPacket(), Port::raddr, RegisterTimeout(), Port::remote_host, Port::remote_hostname, Port::remote_port, SockAddr::salen, Port::SessionStartTime, SIGQUIT, snprintf(), startup_die(), STARTUP_PACKET_TIMEOUT, StartupBlockSig, StartupPacketTimeoutHandler(), STATUS_OK, timestamptz_to_time_t(), update_process_title, Port::user_name, WARNING, and whereToSendOutput.

Referenced by BackendStartup().

{
    int         status;
    int         ret;
    char        remote_host[NI_MAXHOST];
    char        remote_port[NI_MAXSERV];
    char        remote_ps_data[NI_MAXHOST];

    /* Save port etc. for ps status */
    MyProcPort = port;

    /*
     * PreAuthDelay is a debugging aid for investigating problems in the
     * authentication cycle: it can be set in postgresql.conf to allow time to
     * attach to the newly-forked backend with a debugger.  (See also
     * PostAuthDelay, which we allow clients to pass through PGOPTIONS, but it
     * is not honored until after authentication.)
     */
    if (PreAuthDelay > 0)
        pg_usleep(PreAuthDelay * 1000000L);

    /* This flag will remain set until InitPostgres finishes authentication */
    ClientAuthInProgress = true;    /* limit visibility of log messages */

    /* save process start time */
    port->SessionStartTime = GetCurrentTimestamp();
    MyStartTime = timestamptz_to_time_t(port->SessionStartTime);

    /* set these to empty in case they are needed before we set them up */
    port->remote_host = "";
    port->remote_port = "";

    /*
     * Initialize libpq and enable reporting of ereport errors to the client.
     * Must do this now because authentication uses libpq to send messages.
     */
    pq_init();                  /* initialize libpq to talk to client */
    whereToSendOutput = DestRemote;     /* now safe to ereport to client */

    /*
     * If possible, make this process a group leader, so that the postmaster
     * can signal any child processes too.  (We do this now on the off chance
     * that something might spawn a child process during authentication.)
     */
#ifdef HAVE_SETSID
    if (setsid() < 0)
        elog(FATAL, "setsid() failed: %m");
#endif

    /*
     * We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT or
     * timeout while trying to collect the startup packet.  Otherwise the
     * postmaster cannot shutdown the database FAST or IMMED cleanly if a
     * buggy client fails to send the packet promptly.
     */
    pqsignal(SIGTERM, startup_die);
    pqsignal(SIGQUIT, startup_die);
    InitializeTimeouts();       /* establishes SIGALRM handler */
    PG_SETMASK(&StartupBlockSig);

    /*
     * Get the remote host name and port for logging and status display.
     */
    remote_host[0] = '\0';
    remote_port[0] = '\0';
    if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
                           remote_host, sizeof(remote_host),
                           remote_port, sizeof(remote_port),
                  (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0)
        ereport(WARNING,
                (errmsg_internal("pg_getnameinfo_all() failed: %s",
                                 gai_strerror(ret))));
    if (remote_port[0] == '\0')
        snprintf(remote_ps_data, sizeof(remote_ps_data), "%s", remote_host);
    else
        snprintf(remote_ps_data, sizeof(remote_ps_data), "%s(%s)", remote_host, remote_port);

    if (Log_connections)
    {
        if (remote_port[0])
            ereport(LOG,
                    (errmsg("connection received: host=%s port=%s",
                            remote_host,
                            remote_port)));
        else
            ereport(LOG,
                    (errmsg("connection received: host=%s",
                            remote_host)));
    }

    /*
     * save remote_host and remote_port in port structure
     */
    port->remote_host = strdup(remote_host);
    port->remote_port = strdup(remote_port);
    if (log_hostname)
        port->remote_hostname = port->remote_host;

    /*
     * Ready to begin client interaction.  We will give up and exit(1) after a
     * time delay, so that a broken client can't hog a connection
     * indefinitely.  PreAuthDelay and any DNS interactions above don't count
     * against the time limit.
     *
     * Note: AuthenticationTimeout is applied here while waiting for the
     * startup packet, and then again in InitPostgres for the duration of any
     * authentication operations.  So a hostile client could tie up the
     * process for nearly twice AuthenticationTimeout before we kick him off.
     *
     * Note: because PostgresMain will call InitializeTimeouts again, the
     * registration of STARTUP_PACKET_TIMEOUT will be lost.  This is okay
     * since we never use it again after this function.
     */
    RegisterTimeout(STARTUP_PACKET_TIMEOUT, StartupPacketTimeoutHandler);
    enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000);

    /*
     * Receive the startup packet (which might turn out to be a cancel request
     * packet).
     */
    status = ProcessStartupPacket(port, false);

    /*
     * Stop here if it was bad or a cancel packet.  ProcessStartupPacket
     * already did any appropriate error reporting.
     */
    if (status != STATUS_OK)
        proc_exit(0);

    /*
     * Now that we have the user and database name, we can set the process
     * title for ps.  It's good to do this as early as possible in startup.
     *
     * For a walsender, the ps display is set in the following form:
     *
     * postgres: wal sender process <user> <host> <activity>
     *
     * To achieve that, we pass "wal sender process" as username and username
     * as dbname to init_ps_display(). XXX: should add a new variant of
     * init_ps_display() to avoid abusing the parameters like this.
     */
    if (am_walsender)
        init_ps_display("wal sender process", port->user_name, remote_ps_data,
                        update_process_title ? "authentication" : "");
    else
        init_ps_display(port->user_name, port->database_name, remote_ps_data,
                        update_process_title ? "authentication" : "");

    /*
     * Disable the timeout, and prevent SIGTERM/SIGQUIT again.
     */
    disable_timeout(STARTUP_PACKET_TIMEOUT, false);
    PG_SETMASK(&BlockSig);
}

static void BackendRun ( Port port  )  [static]

Definition at line 3920 of file postmaster.c.

References Assert, av, Port::database_name, DEBUG3, ereport, errmsg_internal(), ExtraOptions, MemoryContextAlloc(), MemoryContextSwitchTo(), MyProcPid, pg_split_opts(), PostgresMain(), progname, random_seed, random_start_time, Port::SessionStartTime, srandom(), TimestampDifference(), TopMemoryContext, and Port::user_name.

Referenced by BackendStartup().

{
    char      **av;
    int         maxac;
    int         ac;
    long        secs;
    int         usecs;
    int         i;

    /*
     * Don't want backend to be able to see the postmaster random number
     * generator state.  We have to clobber the static random_seed *and* start
     * a new random sequence in the random() library function.
     */
    random_seed = 0;
    random_start_time.tv_usec = 0;
    /* slightly hacky way to get integer microseconds part of timestamptz */
    TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
    srandom((unsigned int) (MyProcPid ^ usecs));

    /*
     * Now, build the argv vector that will be given to PostgresMain.
     *
     * The maximum possible number of commandline arguments that could come
     * from ExtraOptions is (strlen(ExtraOptions) + 1) / 2; see
     * pg_split_opts().
     */
    maxac = 2;                  /* for fixed args supplied below */
    maxac += (strlen(ExtraOptions) + 1) / 2;

    av = (char **) MemoryContextAlloc(TopMemoryContext,
                                      maxac * sizeof(char *));
    ac = 0;

    av[ac++] = "postgres";

    /*
     * Pass any backend switches specified with -o on the postmaster's own
     * command line.  We assume these are secure.  (It's OK to mangle
     * ExtraOptions now, since we're safely inside a subprocess.)
     */
    pg_split_opts(av, &ac, ExtraOptions);

    av[ac] = NULL;

    Assert(ac < maxac);

    /*
     * Debug: print arguments being passed to backend
     */
    ereport(DEBUG3,
            (errmsg_internal("%s child[%d]: starting with (",
                             progname, (int) getpid())));
    for (i = 0; i < ac; ++i)
        ereport(DEBUG3,
                (errmsg_internal("\t%s", av[i])));
    ereport(DEBUG3,
            (errmsg_internal(")")));

    /*
     * Make sure we aren't in PostmasterContext anymore.  (We can't delete it
     * just yet, though, because InitPostgres will need the HBA data.)
     */
    MemoryContextSwitchTo(TopMemoryContext);

    PostgresMain(ac, av, port->database_name, port->user_name);
}

static int BackendStartup ( Port port  )  [static]

Definition at line 3606 of file postmaster.c.

References AssignPostmasterChildSlot(), BackendInitialize(), BackendRun(), bkend::bkend_type, CAC_OK, canAcceptConnections(), Port::canAcceptConnections, bkend::cancel_key, bkend::child_slot, ClosePostmasterPorts(), bkend::dead_end, DEBUG2, dlist_push_head(), bkend::elem, ereport, errcode(), errmsg(), errmsg_internal(), fork_process(), free, IsUnderPostmaster, LOG, malloc, MyCancelKey, MyPMChildSlot, MyProcPid, MyStartTime, NULL, on_exit_reset(), bkend::pid, PostmasterRandom(), ReleasePostmasterChildSlot(), report_fork_failure_to_client(), and Port::sock.

Referenced by ServerLoop().

{
    Backend    *bn;             /* for backend cleanup */
    pid_t       pid;

    /*
     * Create backend data structure.  Better before the fork() so we can
     * handle failure cleanly.
     */
    bn = (Backend *) malloc(sizeof(Backend));
    if (!bn)
    {
        ereport(LOG,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of memory")));
        return STATUS_ERROR;
    }

    /*
     * Compute the cancel key that will be assigned to this backend. The
     * backend will have its own copy in the forked-off process' value of
     * MyCancelKey, so that it can transmit the key to the frontend.
     */
    MyCancelKey = PostmasterRandom();
    bn->cancel_key = MyCancelKey;

    /* Pass down canAcceptConnections state */
    port->canAcceptConnections = canAcceptConnections();
    bn->dead_end = (port->canAcceptConnections != CAC_OK &&
                    port->canAcceptConnections != CAC_WAITBACKUP);

    /*
     * Unless it's a dead_end child, assign it a child slot number
     */
    if (!bn->dead_end)
        bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
    else
        bn->child_slot = 0;

#ifdef EXEC_BACKEND
    pid = backend_forkexec(port);
#else                           /* !EXEC_BACKEND */
    pid = fork_process();
    if (pid == 0)               /* child */
    {
        free(bn);

        /*
         * Let's clean up ourselves as the postmaster child, and close the
         * postmaster's listen sockets.  (In EXEC_BACKEND case this is all
         * done in SubPostmasterMain.)
         */
        IsUnderPostmaster = true;       /* we are a postmaster subprocess now */

        MyProcPid = getpid();   /* reset MyProcPid */

        MyStartTime = time(NULL);

        /* We don't want the postmaster's proc_exit() handlers */
        on_exit_reset();

        /* Close the postmaster's sockets */
        ClosePostmasterPorts(false);

        /* Perform additional initialization and collect startup packet */
        BackendInitialize(port);

        /* And run the backend */
        BackendRun(port);
    }
#endif   /* EXEC_BACKEND */

    if (pid < 0)
    {
        /* in parent, fork failed */
        int         save_errno = errno;

        if (!bn->dead_end)
            (void) ReleasePostmasterChildSlot(bn->child_slot);
        free(bn);
        errno = save_errno;
        ereport(LOG,
                (errmsg("could not fork new process for connection: %m")));
        report_fork_failure_to_client(port, save_errno);
        return STATUS_ERROR;
    }

    /* in parent, successful fork */
    ereport(DEBUG2,
            (errmsg_internal("forked new backend, pid=%d socket=%d",
                             (int) pid, (int) port->sock)));

    /*
     * Everything's been successful, it's safe to add this backend to our list
     * of backends.
     */
    bn->pid = pid;
    bn->bkend_type = BACKEND_TYPE_NORMAL;       /* Can change later to WALSND */
    dlist_push_head(&BackendList, &bn->elem);

#ifdef EXEC_BACKEND
    if (!bn->dead_end)
        ShmemBackendArrayAdd(bn);
#endif

    return STATUS_OK;
}

void BackgroundWorkerBlockSignals ( void   ) 

Definition at line 5287 of file postmaster.c.

References BlockSig, and PG_SETMASK.

void BackgroundWorkerInitializeConnection ( char *  dbname,
char *  username 
)

Definition at line 5264 of file postmaster.c.

References BackgroundWorker::bgw_flags, BGWORKER_BACKEND_DATABASE_CONNECTION, ereport, errcode(), errmsg(), ERROR, FATAL, InitPostgres(), InvalidOid, IsInitProcessingMode, NormalProcessing, NULL, and SetProcessingMode.

Referenced by worker_spi_main().

{
    BackgroundWorker *worker = MyBgworkerEntry;

    /* XXX is this the right errcode? */
    if (!(worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION))
        ereport(FATAL,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("database connection requirement not indicated during registration")));

    InitPostgres(dbname, InvalidOid, username, NULL);

    /* it had better not gotten out of "init" mode yet */
    if (!IsInitProcessingMode())
        ereport(ERROR,
                (errmsg("invalid processing mode in bgworker")));
    SetProcessingMode(NormalProcessing);
}

void BackgroundWorkerUnblockSignals ( void   ) 

Definition at line 5293 of file postmaster.c.

References PG_SETMASK, and UnBlockSig.

Referenced by worker_spi_main().

static void bgworker_die ( SIGNAL_ARGS   )  [static]

Definition at line 5347 of file postmaster.c.

References BackgroundWorker::bgw_name, BlockSig, ereport, errcode(), errmsg(), FATAL, and PG_SETMASK.

Referenced by do_start_bgworker().

{
    PG_SETMASK(&BlockSig);

    ereport(FATAL,
            (errcode(ERRCODE_ADMIN_SHUTDOWN),
             errmsg("terminating background worker \"%s\" due to administrator command",
                    MyBgworkerEntry->bgw_name)));
}

static void bgworker_quickdie ( SIGNAL_ARGS   )  [static]

Definition at line 5318 of file postmaster.c.

References BlockSig, on_exit_reset(), PG_SETMASK, sigaddset, and SIGQUIT.

Referenced by do_start_bgworker().

{
    sigaddset(&BlockSig, SIGQUIT);      /* prevent nested calls */
    PG_SETMASK(&BlockSig);

    /*
     * We DO NOT want to run proc_exit() callbacks -- we're here because
     * shared memory may be corrupted, so we don't want to try to clean up our
     * transaction.  Just nail the windows shut and get out of town.  Now that
     * there's an atexit callback to prevent third-party code from breaking
     * things by calling exit() directly, we have to reset the callbacks
     * explicitly to make this work as intended.
     */
    on_exit_reset();

    /*
     * Note we do exit(0) here, not exit(2) like quickdie.  The reason is that
     * we don't want to be seen this worker as independently crashed, because
     * then postmaster would delay restarting it again afterwards.  If some
     * idiot DBA manually sends SIGQUIT to a random bgworker, the "dead man
     * switch" will ensure that postmaster sees this as a crash.
     */
    exit(0);
}

static bool bgworker_should_start_now ( BgWorkerStartTime  start_time  )  [static]
static void bgworker_sigusr1_handler ( SIGNAL_ARGS   )  [static]

Definition at line 5364 of file postmaster.c.

References latch_sigusr1_handler().

Referenced by do_start_bgworker().

{
    int         save_errno = errno;

    latch_sigusr1_handler();

    errno = save_errno;
}

static CAC_state canAcceptConnections ( void   )  [static]

Definition at line 2068 of file postmaster.c.

References BACKEND_TYPE_ALL, CountChildren(), FatalError, MaxLivePostmasterChildren(), NoShutdown, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_STARTUP, PM_WAIT_BACKUP, pmState, and Shutdown.

Referenced by BackendStartup(), and StartAutovacuumWorker().

{
    CAC_state   result = CAC_OK;

    /*
     * Can't start backends when in startup/shutdown/inconsistent recovery
     * state.
     *
     * In state PM_WAIT_BACKUP only superusers can connect (this must be
     * allowed so that a superuser can end online backup mode); we return
     * CAC_WAITBACKUP code to indicate that this must be checked later. Note
     * that neither CAC_OK nor CAC_WAITBACKUP can safely be returned until we
     * have checked for too many children.
     */
    if (pmState != PM_RUN)
    {
        if (pmState == PM_WAIT_BACKUP)
            result = CAC_WAITBACKUP;    /* allow superusers only */
        else if (Shutdown > NoShutdown)
            return CAC_SHUTDOWN;    /* shutdown is pending */
        else if (!FatalError &&
                 (pmState == PM_STARTUP ||
                  pmState == PM_RECOVERY))
            return CAC_STARTUP; /* normal startup */
        else if (!FatalError &&
                 pmState == PM_HOT_STANDBY)
            result = CAC_OK;    /* connection OK during hot standby */
        else
            return CAC_RECOVERY;    /* else must be crash recovery */
    }

    /*
     * Don't start too many children.
     *
     * We allow more connections than we can have backends here because some
     * might still be authenticating; they might fail auth, or some existing
     * backend might exit before the auth cycle is completed. The exact
     * MaxBackends limit is enforced when a new backend tries to join the
     * shared-inval backend array.
     *
     * The limit here must match the sizes of the per-child-process arrays;
     * see comments for MaxLivePostmasterChildren().
     */
    if (CountChildren(BACKEND_TYPE_ALL) >= MaxLivePostmasterChildren())
        result = CAC_TOOMANY;

    return result;
}

static void checkDataDir ( void   )  [static]

Definition at line 1322 of file postmaster.c.

References AllocateFile(), Assert, DataDir, ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), ExitPostmaster(), FATAL, FreeFile(), NULL, PG_BINARY_R, progname, S_IRWXG, S_IRWXO, snprintf(), strerror(), ValidatePgVersion(), and write_stderr.

Referenced by PostmasterMain().

{
    char        path[MAXPGPATH];
    FILE       *fp;
    struct stat stat_buf;

    Assert(DataDir);

    if (stat(DataDir, &stat_buf) != 0)
    {
        if (errno == ENOENT)
            ereport(FATAL,
                    (errcode_for_file_access(),
                     errmsg("data directory \"%s\" does not exist",
                            DataDir)));
        else
            ereport(FATAL,
                    (errcode_for_file_access(),
                 errmsg("could not read permissions of directory \"%s\": %m",
                        DataDir)));
    }

    /* eventual chdir would fail anyway, but let's test ... */
    if (!S_ISDIR(stat_buf.st_mode))
        ereport(FATAL,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("specified data directory \"%s\" is not a directory",
                        DataDir)));

    /*
     * Check that the directory belongs to my userid; if not, reject.
     *
     * This check is an essential part of the interlock that prevents two
     * postmasters from starting in the same directory (see CreateLockFile()).
     * Do not remove or weaken it.
     *
     * XXX can we safely enable this check on Windows?
     */
#if !defined(WIN32) && !defined(__CYGWIN__)
    if (stat_buf.st_uid != geteuid())
        ereport(FATAL,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("data directory \"%s\" has wrong ownership",
                        DataDir),
                 errhint("The server must be started by the user that owns the data directory.")));
#endif

    /*
     * Check if the directory has group or world access.  If so, reject.
     *
     * It would be possible to allow weaker constraints (for example, allow
     * group access) but we cannot make a general assumption that that is
     * okay; for example there are platforms where nearly all users
     * customarily belong to the same group.  Perhaps this test should be
     * configurable.
     *
     * XXX temporarily suppress check when on Windows, because there may not
     * be proper support for Unix-y file permissions.  Need to think of a
     * reasonable check to apply on Windows.
     */
#if !defined(WIN32) && !defined(__CYGWIN__)
    if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
        ereport(FATAL,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("data directory \"%s\" has group or world access",
                        DataDir),
                 errdetail("Permissions should be u=rwx (0700).")));
#endif

    /* Look for PG_VERSION before looking for pg_control */
    ValidatePgVersion(DataDir);

    snprintf(path, sizeof(path), "%s/global/pg_control", DataDir);

    fp = AllocateFile(path, PG_BINARY_R);
    if (fp == NULL)
    {
        write_stderr("%s: could not find the database system\n"
                     "Expected to find it in the directory \"%s\",\n"
                     "but could not open file \"%s\": %s\n",
                     progname, DataDir, path, strerror(errno));
        ExitPostmaster(2);
    }
    FreeFile(fp);
}

static void CleanupBackend ( int  pid,
int  exitstatus 
) [static]

Definition at line 2877 of file postmaster.c.

References _, bkend::child_slot, dlist_mutable_iter::cur, bkend::dead_end, DEBUG2, dlist_container, dlist_delete(), dlist_foreach_modify, EXIT_STATUS_0, EXIT_STATUS_1, free, HandleChildCrash(), LOG, LogChildExit(), bkend::pid, and ReleasePostmasterChildSlot().

Referenced by reaper().

{
    dlist_mutable_iter iter;

    LogChildExit(DEBUG2, _("server process"), pid, exitstatus);

    /*
     * If a backend dies in an ugly way then we must signal all other backends
     * to quickdie.  If exit status is zero (normal) or one (FATAL exit), we
     * assume everything is all right and proceed to remove the backend from
     * the active backend list.
     */
#ifdef WIN32

    /*
     * On win32, also treat ERROR_WAIT_NO_CHILDREN (128) as nonfatal case,
     * since that sometimes happens under load when the process fails to start
     * properly (long before it starts using shared memory). Microsoft reports
     * it is related to mutex failure:
     * http://archives.postgresql.org/pgsql-hackers/2010-09/msg00790.php
     */
    if (exitstatus == ERROR_WAIT_NO_CHILDREN)
    {
        LogChildExit(LOG, _("server process"), pid, exitstatus);
        exitstatus = 0;
    }
#endif

    if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus))
    {
        HandleChildCrash(pid, exitstatus, _("server process"));
        return;
    }

    dlist_foreach_modify(iter, &BackendList)
    {
        Backend    *bp = dlist_container(Backend, elem, iter.cur);

        if (bp->pid == pid)
        {
            if (!bp->dead_end)
            {
                if (!ReleasePostmasterChildSlot(bp->child_slot))
                {
                    /*
                     * Uh-oh, the child failed to clean itself up.  Treat as a
                     * crash after all.
                     */
                    HandleChildCrash(pid, exitstatus, _("server process"));
                    return;
                }
#ifdef EXEC_BACKEND
                ShmemBackendArrayRemove(bp);
#endif
            }
            dlist_delete(iter.cur);
            free(bp);
            break;
        }
    }
}

static bool CleanupBackgroundWorker ( int  pid,
int  exitstatus 
) [static]

Definition at line 2791 of file postmaster.c.

References _, Assert, BackgroundWorker::bgw_flags, BackgroundWorker::bgw_name, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, slist_iter::cur, dlist_delete(), bkend::elem, EXIT_STATUS_0, EXIT_STATUS_1, free, GetCurrentTimestamp(), HandleChildCrash(), LOG, LogChildExit(), MAXPGPATH, ReleasePostmasterChildSlot(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_pid, RegisteredBgWorker::rw_worker, slist_container, slist_foreach, and snprintf().

Referenced by reaper().

{
    char        namebuf[MAXPGPATH];
    slist_iter  iter;

    slist_foreach(iter, &BackgroundWorkerList)
    {
        RegisteredBgWorker *rw;

        rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);

        if (rw->rw_pid != pid)
            continue;

#ifdef WIN32
        /* see CleanupBackend */
        if (exitstatus == ERROR_WAIT_NO_CHILDREN)
            exitstatus = 0;
#endif

        snprintf(namebuf, MAXPGPATH, "%s: %s", _("worker process"),
                 rw->rw_worker.bgw_name);

        /* Delay restarting any bgworker that exits with a nonzero status. */
        if (!EXIT_STATUS_0(exitstatus))
            rw->rw_crashed_at = GetCurrentTimestamp();
        else
            rw->rw_crashed_at = 0;

        /*
         * Additionally, for shared-memory-connected workers, just like a
         * backend, any exit status other than 0 or 1 is considered a crash
         * and causes a system-wide restart.
         */
        if (rw->rw_worker.bgw_flags & BGWORKER_SHMEM_ACCESS)
        {
            if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus))
            {
                rw->rw_crashed_at = GetCurrentTimestamp();
                HandleChildCrash(pid, exitstatus, namebuf);
                return true;
            }
        }

        if (!ReleasePostmasterChildSlot(rw->rw_child_slot))
        {
            /*
             * Uh-oh, the child failed to clean itself up.  Treat as a crash
             * after all.
             */
            rw->rw_crashed_at = GetCurrentTimestamp();
            HandleChildCrash(pid, exitstatus, namebuf);
            return true;
        }

        /* Get it out of the BackendList and clear out remaining data */
        if (rw->rw_backend)
        {
            Assert(rw->rw_worker.bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION);
            dlist_delete(&rw->rw_backend->elem);
#ifdef EXEC_BACKEND
            ShmemBackendArrayRemove(rw->rw_backend);
#endif
            free(rw->rw_backend);
            rw->rw_backend = NULL;
        }
        rw->rw_pid = 0;
        rw->rw_child_slot = 0;

        LogChildExit(LOG, namebuf, pid, exitstatus);

        return true;
    }

    return false;
}

void ClosePostmasterPorts ( bool  am_syslogger  ) 

Definition at line 2199 of file postmaster.c.

References close, ereport, errcode_for_file_access(), errmsg_internal(), FATAL, ListenSocket, PGINVALID_SOCKET, POSTMASTER_FD_OWN, StreamClose(), and syslogPipe.

Referenced by BackendStartup(), pgarch_start(), pgstat_start(), start_bgworker(), StartAutoVacLauncher(), StartAutoVacWorker(), StartChildProcess(), and SysLogger_Start().

{
    int         i;

#ifndef WIN32

    /*
     * Close the write end of postmaster death watch pipe. It's important to
     * do this as early as possible, so that if postmaster dies, others won't
     * think that it's still running because we're holding the pipe open.
     */
    if (close(postmaster_alive_fds[POSTMASTER_FD_OWN]))
        ereport(FATAL,
                (errcode_for_file_access(),
                 errmsg_internal("could not close postmaster death monitoring pipe in child process: %m")));
    postmaster_alive_fds[POSTMASTER_FD_OWN] = -1;
#endif

    /* Close the listen sockets */
    for (i = 0; i < MAXLISTEN; i++)
    {
        if (ListenSocket[i] != PGINVALID_SOCKET)
        {
            StreamClose(ListenSocket[i]);
            ListenSocket[i] = PGINVALID_SOCKET;
        }
    }

    /* If using syslogger, close the read side of the pipe */
    if (!am_syslogger)
    {
#ifndef WIN32
        if (syslogPipe[0] >= 0)
            close(syslogPipe[0]);
        syslogPipe[0] = -1;
#else
        if (syslogPipe[0])
            CloseHandle(syslogPipe[0]);
        syslogPipe[0] = 0;
#endif
    }

#ifdef USE_BONJOUR
    /* If using Bonjour, close the connection to the mDNS daemon */
    if (bonjour_sdref)
        close(DNSServiceRefSockFD(bonjour_sdref));
#endif
}

static Port * ConnCreate ( int  serverFd  )  [static]

Definition at line 2124 of file postmaster.c.

References calloc, ConnFree(), ereport, errcode(), errmsg(), ExitPostmaster(), Port::gss, LOG, Port::md5Salt, RandomSalt(), Port::sock, STATUS_OK, StreamClose(), and StreamConnection().

Referenced by ServerLoop().

{
    Port       *port;

    if (!(port = (Port *) calloc(1, sizeof(Port))))
    {
        ereport(LOG,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of memory")));
        ExitPostmaster(1);
    }

    if (StreamConnection(serverFd, port) != STATUS_OK)
    {
        if (port->sock >= 0)
            StreamClose(port->sock);
        ConnFree(port);
        return NULL;
    }

    /*
     * Precompute password salt values to use for this connection. It's
     * slightly annoying to do this long in advance of knowing whether we'll
     * need 'em or not, but we must do the random() calls before we fork, not
     * after.  Else the postmaster's random sequence won't get advanced, and
     * all backends would end up using the same salt...
     */
    RandomSalt(port->md5Salt);

    /*
     * Allocate GSSAPI specific state struct
     */
#ifndef EXEC_BACKEND
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
    port->gss = (pg_gssinfo *) calloc(1, sizeof(pg_gssinfo));
    if (!port->gss)
    {
        ereport(LOG,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of memory")));
        ExitPostmaster(1);
    }
#endif
#endif

    return port;
}

static void ConnFree ( Port port  )  [static]

Definition at line 2177 of file postmaster.c.

References free, Port::gss, and secure_close().

Referenced by ConnCreate(), and ServerLoop().

{
#ifdef USE_SSL
    secure_close(conn);
#endif
    if (conn->gss)
        free(conn->gss);
    free(conn);
}

static int CountChildren ( int  target  )  [static]

Definition at line 4863 of file postmaster.c.

References BACKEND_TYPE_ALL, BACKEND_TYPE_NORMAL, bkend::bkend_type, bkend::child_slot, dlist_iter::cur, bkend::dead_end, dlist_container, dlist_foreach, and IsPostmasterChildWalSender().

Referenced by canAcceptConnections(), and PostmasterStateMachine().

{
    dlist_iter  iter;
    int         cnt = 0;

    dlist_foreach(iter, &BackendList)
    {
        Backend    *bp = dlist_container(Backend, elem, iter.cur);

        if (bp->dead_end)
            continue;

        /*
         * Since target == BACKEND_TYPE_ALL is the most common case, we test
         * it first and avoid touching shared memory for every child.
         */
        if (target != BACKEND_TYPE_ALL)
        {
            /*
             * Assign bkend_type for any recently announced WAL Sender
             * processes.
             */
            if (bp->bkend_type == BACKEND_TYPE_NORMAL &&
                IsPostmasterChildWalSender(bp->child_slot))
                bp->bkend_type = BACKEND_TYPE_WALSND;

            if (!(target & bp->bkend_type))
                continue;
        }

        cnt++;
    }
    return cnt;
}

static int CountUnconnectedWorkers ( void   )  [static]

Definition at line 4836 of file postmaster.c.

References slist_iter::cur, NULL, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_pid, slist_container, and slist_foreach.

Referenced by PostmasterStateMachine().

{
    slist_iter  iter;
    int         cnt = 0;

    slist_foreach(iter, &BackgroundWorkerList)
    {
        RegisteredBgWorker *rw;

        rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);

        if (rw->rw_pid == 0)
            continue;
        /* ignore connected workers */
        if (rw->rw_backend != NULL)
            continue;

        cnt++;
    }
    return cnt;
}

static bool CreateOptsFile ( int  argc,
char *  argv[],
char *  fullprogname 
) [static]

Definition at line 5090 of file postmaster.c.

References elog, LOG, NULL, and OPTS_FILE.

Referenced by PostmasterMain().

{
    FILE       *fp;
    int         i;

#define OPTS_FILE   "postmaster.opts"

    if ((fp = fopen(OPTS_FILE, "w")) == NULL)
    {
        elog(LOG, "could not create file \"%s\": %m", OPTS_FILE);
        return false;
    }

    fprintf(fp, "%s", fullprogname);
    for (i = 1; i < argc; i++)
        fprintf(fp, " \"%s\"", argv[i]);
    fputs("\n", fp);

    if (fclose(fp))
    {
        elog(LOG, "could not write file \"%s\": %m", OPTS_FILE);
        return false;
    }

    return true;
}

static void DetermineSleepTime ( struct timeval *  timeout  )  [static]

Definition at line 1417 of file postmaster.c.

References BGW_NEVER_RESTART, BackgroundWorker::bgw_restart_time, slist_iter::cur, GetCurrentTimestamp(), HaveCrashedWorker, NoShutdown, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_worker, Shutdown, slist_container, slist_foreach, StartWorkerNeeded, TimestampDifference(), and TimestampTzPlusMilliseconds.

Referenced by ServerLoop().

{
    TimestampTz next_wakeup = 0;

    /*
     * Normal case: either there are no background workers at all, or we're in
     * a shutdown sequence (during which we ignore bgworkers altogether).
     */
    if (Shutdown > NoShutdown ||
        (!StartWorkerNeeded && !HaveCrashedWorker))
    {
        timeout->tv_sec = 60;
        timeout->tv_usec = 0;
        return;
    }

    if (StartWorkerNeeded)
    {
        timeout->tv_sec = 0;
        timeout->tv_usec = 0;
        return;
    }

    if (HaveCrashedWorker)
    {
        slist_iter  siter;

        /*
         * When there are crashed bgworkers, we sleep just long enough that
         * they are restarted when they request to be.  Scan the list to
         * determine the minimum of all wakeup times according to most recent
         * crash time and requested restart interval.
         */
        slist_foreach(siter, &BackgroundWorkerList)
        {
            RegisteredBgWorker *rw;
            TimestampTz this_wakeup;

            rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur);

            if (rw->rw_crashed_at == 0)
                continue;

            if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART)
                continue;

            this_wakeup = TimestampTzPlusMilliseconds(rw->rw_crashed_at,
                                     1000L * rw->rw_worker.bgw_restart_time);
            if (next_wakeup == 0 || this_wakeup < next_wakeup)
                next_wakeup = this_wakeup;
        }
    }

    if (next_wakeup != 0)
    {
        int         microsecs;

        TimestampDifference(GetCurrentTimestamp(), next_wakeup,
                            &timeout->tv_sec, &microsecs);
        timeout->tv_usec = microsecs;

        /* Ensure we don't exceed one minute */
        if (timeout->tv_sec > 60)
        {
            timeout->tv_sec = 60;
            timeout->tv_usec = 0;
        }
    }
    else
    {
        timeout->tv_sec = 60;
        timeout->tv_usec = 0;
    }
}

static void do_start_bgworker ( void   )  [static]

Definition at line 5374 of file postmaster.c.

References BaseInit(), BackgroundWorker::bgw_flags, BackgroundWorker::bgw_main, BackgroundWorker::bgw_main_arg, BackgroundWorker::bgw_name, BackgroundWorker::bgw_sighup, BackgroundWorker::bgw_sigterm, BGWORKER_BACKEND_DATABASE_CONNECTION, bgworker_die(), bgworker_quickdie(), BGWORKER_SHMEM_ACCESS, bgworker_sigusr1_handler(), buf, elog, EmitErrorReport(), error_context_stack, FATAL, FloatExceptionHandler(), HOLD_INTERRUPTS, init_ps_display(), InitializeTimeouts(), InitProcess(), InitProcessing, IsBackgroundWorker, IsUnderPostmaster, MAXPGPATH, MyProcPid, MyStartTime, NULL, PG_exception_stack, pg_usleep(), PostAuthDelay, pqsignal(), proc_exit(), procsignal_sigusr1_handler(), SetProcessingMode, SIG_DFL, SIG_IGN, SIGCHLD, SIGHUP, sigjmp_buf, SIGPIPE, SIGQUIT, sigsetjmp, SIGUSR1, SIGUSR2, snprintf(), and StatementCancelHandler().

Referenced by start_bgworker().

{
    sigjmp_buf  local_sigjmp_buf;
    char        buf[MAXPGPATH];
    BackgroundWorker *worker = MyBgworkerEntry;

    if (worker == NULL)
        elog(FATAL, "unable to find bgworker entry");

    /* we are a postmaster subprocess now */
    IsUnderPostmaster = true;
    IsBackgroundWorker = true;

    /* reset MyProcPid */
    MyProcPid = getpid();

    /* record Start Time for logging */
    MyStartTime = time(NULL);

    /* Identify myself via ps */
    snprintf(buf, MAXPGPATH, "bgworker: %s", worker->bgw_name);
    init_ps_display(buf, "", "", "");

    SetProcessingMode(InitProcessing);

    /* Apply PostAuthDelay */
    if (PostAuthDelay > 0)
        pg_usleep(PostAuthDelay * 1000000L);

    /*
     * If possible, make this process a group leader, so that the postmaster
     * can signal any child processes too.
     */
#ifdef HAVE_SETSID
    if (setsid() < 0)
        elog(FATAL, "setsid() failed: %m");
#endif

    /*
     * Set up signal handlers.
     */
    if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
    {
        /*
         * SIGINT is used to signal canceling the current action
         */
        pqsignal(SIGINT, StatementCancelHandler);
        pqsignal(SIGUSR1, procsignal_sigusr1_handler);
        pqsignal(SIGFPE, FloatExceptionHandler);

        /* XXX Any other handlers needed here? */
    }
    else
    {
        pqsignal(SIGINT, SIG_IGN);
        pqsignal(SIGUSR1, bgworker_sigusr1_handler);
        pqsignal(SIGFPE, SIG_IGN);
    }

    /* SIGTERM and SIGHUP are configurable */
    if (worker->bgw_sigterm)
        pqsignal(SIGTERM, worker->bgw_sigterm);
    else
        pqsignal(SIGTERM, bgworker_die);

    if (worker->bgw_sighup)
        pqsignal(SIGHUP, worker->bgw_sighup);
    else
        pqsignal(SIGHUP, SIG_IGN);

    pqsignal(SIGQUIT, bgworker_quickdie);
    InitializeTimeouts();       /* establishes SIGALRM handler */

    pqsignal(SIGPIPE, SIG_IGN);
    pqsignal(SIGUSR2, SIG_IGN);
    pqsignal(SIGCHLD, SIG_DFL);

    /*
     * If an exception is encountered, processing resumes here.
     *
     * See notes in postgres.c about the design of this coding.
     */
    if (sigsetjmp(local_sigjmp_buf, 1) != 0)
    {
        /* Since not using PG_TRY, must reset error stack by hand */
        error_context_stack = NULL;

        /* Prevent interrupts while cleaning up */
        HOLD_INTERRUPTS();

        /* Report the error to the server log */
        EmitErrorReport();

        /*
         * Do we need more cleanup here?  For shmem-connected bgworkers, we
         * will call InitProcess below, which will install ProcKill as exit
         * callback.  That will take care of releasing locks, etc.
         */

        /* and go away */
        proc_exit(1);
    }

    /* We can now handle ereport(ERROR) */
    PG_exception_stack = &local_sigjmp_buf;

    /* Early initialization */
    BaseInit();

    /*
     * If necessary, create a per-backend PGPROC struct in shared memory,
     * except in the EXEC_BACKEND case where this was done in
     * SubPostmasterMain. We must do this before we can use LWLocks (and in
     * the EXEC_BACKEND case we already had to do some stuff with LWLocks).
     */
#ifndef EXEC_BACKEND
    if (worker->bgw_flags & BGWORKER_SHMEM_ACCESS)
        InitProcess();
#endif

    /*
     * Note that in normal processes, we would call InitPostgres here.  For a
     * worker, however, we don't know what database to connect to, yet; so we
     * need to wait until the user code does it via
     * BackgroundWorkerInitializeConnection().
     */

    /*
     * Now invoke the user-defined worker code
     */
    worker->bgw_main(worker->bgw_main_arg);

    /* ... and if it returns, we're done */
    proc_exit(0);
}

static void dummy_handler ( SIGNAL_ARGS   )  [static]

Definition at line 4758 of file postmaster.c.

Referenced by PostmasterMain().

{
}

static void ExitPostmaster ( int  status  )  [static]

Definition at line 4599 of file postmaster.c.

References proc_exit().

Referenced by checkDataDir(), ConnCreate(), pmdie(), PostmasterMain(), PostmasterStateMachine(), reaper(), and StartChildProcess().

{
    /* should cleanup shared memory and kill all backends */

    /*
     * Not sure of the semantics here.  When the Postmaster dies, should the
     * backends all be killed? probably not.
     *
     * MUST     -- vadim 05-10-1999
     */

    proc_exit(status);
}

static void getInstallationPaths ( const char *  argv0  )  [static]

Definition at line 1271 of file postmaster.c.

References AllocateDir(), elog, ereport, errcode_for_file_access(), errhint(), errmsg(), ERROR, FATAL, find_my_exec(), find_other_exec(), FreeDir(), get_pkglib_path(), my_exec_path, NULL, PG_BACKEND_VERSIONSTR, and pkglib_path.

Referenced by PostmasterMain().

{
    DIR        *pdir;

    /* Locate the postgres executable itself */
    if (find_my_exec(argv0, my_exec_path) < 0)
        elog(FATAL, "%s: could not locate my own executable path", argv0);

#ifdef EXEC_BACKEND
    /* Locate executable backend before we change working directory */
    if (find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
                        postgres_exec_path) < 0)
        ereport(FATAL,
                (errmsg("%s: could not locate matching postgres executable",
                        argv0)));
#endif

    /*
     * Locate the pkglib directory --- this has to be set early in case we try
     * to load any modules from it in response to postgresql.conf entries.
     */
    get_pkglib_path(my_exec_path, pkglib_path);

    /*
     * Verify that there's a readable directory there; otherwise the Postgres
     * installation is incomplete or corrupt.  (A typical cause of this
     * failure is that the postgres executable has been moved or hardlinked to
     * some directory that's not a sibling of the installation lib/
     * directory.)
     */
    pdir = AllocateDir(pkglib_path);
    if (pdir == NULL)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not open directory \"%s\": %m",
                        pkglib_path),
                 errhint("This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location.",
                         my_exec_path)));
    FreeDir(pdir);

    /*
     * XXX is it worth similarly checking the share/ directory?  If the lib/
     * directory is there, then share/ probably is too.
     */
}

static int GetNumRegisteredBackgroundWorkers ( int  flags  )  [static]

Definition at line 5515 of file postmaster.c.

References BackgroundWorker::bgw_flags, slist_iter::cur, RegisteredBgWorker::rw_worker, slist_container, and slist_foreach.

Referenced by GetNumShmemAttachedBgworkers(), and MaxLivePostmasterChildren().

{
    slist_iter  iter;
    int         count = 0;

    slist_foreach(iter, &BackgroundWorkerList)
    {
        RegisteredBgWorker *rw;

        rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);

        if (flags != 0 &&
            !(rw->rw_worker.bgw_flags & flags))
            continue;

        count++;
    }

    return count;
}

int GetNumShmemAttachedBgworkers ( void   ) 
static void HandleChildCrash ( int  pid,
int  exitstatus,
const char *  procname 
) [static]

Definition at line 2948 of file postmaster.c.

References allow_immediate_pgstat_restart(), AutoVacPID, BACKEND_TYPE_BGWORKER, BgWriterPID, bkend::bkend_type, CheckpointerPID, bkend::child_slot, dlist_mutable_iter::cur, slist_iter::cur, bkend::dead_end, DEBUG2, dlist_container, dlist_delete(), dlist_foreach_modify, bkend::elem, ereport, errmsg(), errmsg_internal(), FatalError, free, LOG, LogChildExit(), PgArchPID, PgStatPID, bkend::pid, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_SHUTDOWN, PM_WAIT_BACKUP, PM_WAIT_READONLY, pmState, ReleasePostmasterChildSlot(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_pid, SendStop, signal_child(), SIGQUIT, SIGSTOP, slist_container, slist_foreach, StartupPID, WalReceiverPID, and WalWriterPID.

Referenced by CleanupBackend(), CleanupBackgroundWorker(), and reaper().

{
    dlist_mutable_iter iter;
    slist_iter  siter;
    Backend    *bp;

    /*
     * Make log entry unless there was a previous crash (if so, nonzero exit
     * status is to be expected in SIGQUIT response; don't clutter log)
     */
    if (!FatalError)
    {
        LogChildExit(LOG, procname, pid, exitstatus);
        ereport(LOG,
                (errmsg("terminating any other active server processes")));
    }

    /* Process background workers. */
    slist_foreach(siter, &BackgroundWorkerList)
    {
        RegisteredBgWorker *rw;

        rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur);
        if (rw->rw_pid == 0)
            continue;       /* not running */
        if (rw->rw_pid == pid)
        {
            /*
             * Found entry for freshly-dead worker, so remove it.
             */
            (void) ReleasePostmasterChildSlot(rw->rw_child_slot);
            if (rw->rw_backend)
            {
                dlist_delete(&rw->rw_backend->elem);
#ifdef EXEC_BACKEND
                ShmemBackendArrayRemove(rw->rw_backend);
#endif
                free(rw->rw_backend);
                rw->rw_backend = NULL;
            }
            rw->rw_pid = 0;
            rw->rw_child_slot = 0;
            /* don't reset crashed_at */
            /* Keep looping so we can signal remaining workers */
        }
        else
        {
            /*
             * This worker is still alive.  Unless we did so already, tell it
             * to commit hara-kiri.
             *
             * SIGQUIT is the special signal that says exit without proc_exit
             * and let the user know what's going on. But if SendStop is set
             * (-s on command line), then we send SIGSTOP instead, so that we
             * can get core dumps from all backends by hand.
             */
            if (!FatalError)
            {
                ereport(DEBUG2,
                        (errmsg_internal("sending %s to process %d",
                                         (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                         (int) rw->rw_pid)));
                signal_child(rw->rw_pid, (SendStop ? SIGSTOP : SIGQUIT));
            }
        }
    }

    /* Process regular backends */
    dlist_foreach_modify(iter, &BackendList)
    {
        bp = dlist_container(Backend, elem, iter.cur);

        if (bp->pid == pid)
        {
            /*
             * Found entry for freshly-dead backend, so remove it.
             */
            if (!bp->dead_end)
            {
                (void) ReleasePostmasterChildSlot(bp->child_slot);
#ifdef EXEC_BACKEND
                ShmemBackendArrayRemove(bp);
#endif
            }
            dlist_delete(iter.cur);
            free(bp);
            /* Keep looping so we can signal remaining backends */
        }
        else
        {
            /*
             * This backend is still alive.  Unless we did so already, tell it
             * to commit hara-kiri.
             *
             * SIGQUIT is the special signal that says exit without proc_exit
             * and let the user know what's going on. But if SendStop is set
             * (-s on command line), then we send SIGSTOP instead, so that we
             * can get core dumps from all backends by hand.
             *
             * We could exclude dead_end children here, but at least in the
             * SIGSTOP case it seems better to include them.
             *
             * Background workers were already processed above; ignore them
             * here.
             */
            if (bp->bkend_type == BACKEND_TYPE_BGWORKER)
                continue;

            if (!FatalError)
            {
                ereport(DEBUG2,
                        (errmsg_internal("sending %s to process %d",
                                         (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                         (int) bp->pid)));
                signal_child(bp->pid, (SendStop ? SIGSTOP : SIGQUIT));
            }
        }
    }

    /* Take care of the startup process too */
    if (pid == StartupPID)
        StartupPID = 0;
    else if (StartupPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                 (int) StartupPID)));
        signal_child(StartupPID, (SendStop ? SIGSTOP : SIGQUIT));
    }

    /* Take care of the bgwriter too */
    if (pid == BgWriterPID)
        BgWriterPID = 0;
    else if (BgWriterPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                 (int) BgWriterPID)));
        signal_child(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
    }

    /* Take care of the checkpointer too */
    if (pid == CheckpointerPID)
        CheckpointerPID = 0;
    else if (CheckpointerPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                 (int) CheckpointerPID)));
        signal_child(CheckpointerPID, (SendStop ? SIGSTOP : SIGQUIT));
    }

    /* Take care of the walwriter too */
    if (pid == WalWriterPID)
        WalWriterPID = 0;
    else if (WalWriterPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                 (int) WalWriterPID)));
        signal_child(WalWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
    }

    /* Take care of the walreceiver too */
    if (pid == WalReceiverPID)
        WalReceiverPID = 0;
    else if (WalReceiverPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                 (int) WalReceiverPID)));
        signal_child(WalReceiverPID, (SendStop ? SIGSTOP : SIGQUIT));
    }

    /* Take care of the autovacuum launcher too */
    if (pid == AutoVacPID)
        AutoVacPID = 0;
    else if (AutoVacPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 (SendStop ? "SIGSTOP" : "SIGQUIT"),
                                 (int) AutoVacPID)));
        signal_child(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
    }

    /*
     * Force a power-cycle of the pgarch process too.  (This isn't absolutely
     * necessary, but it seems like a good idea for robustness, and it
     * simplifies the state-machine logic in the case where a shutdown request
     * arrives during crash processing.)
     */
    if (PgArchPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 "SIGQUIT",
                                 (int) PgArchPID)));
        signal_child(PgArchPID, SIGQUIT);
    }

    /*
     * Force a power-cycle of the pgstat process too.  (This isn't absolutely
     * necessary, but it seems like a good idea for robustness, and it
     * simplifies the state-machine logic in the case where a shutdown request
     * arrives during crash processing.)
     */
    if (PgStatPID != 0 && !FatalError)
    {
        ereport(DEBUG2,
                (errmsg_internal("sending %s to process %d",
                                 "SIGQUIT",
                                 (int) PgStatPID)));
        signal_child(PgStatPID, SIGQUIT);
        allow_immediate_pgstat_restart();
    }

    /* We do NOT restart the syslogger */

    FatalError = true;
    /* We now transit into a state of waiting for children to die */
    if (pmState == PM_RECOVERY ||
        pmState == PM_HOT_STANDBY ||
        pmState == PM_RUN ||
        pmState == PM_WAIT_BACKUP ||
        pmState == PM_WAIT_READONLY ||
        pmState == PM_SHUTDOWN)
        pmState = PM_WAIT_BACKENDS;
}

static int initMasks ( fd_set *  rmask  )  [static]

Definition at line 1669 of file postmaster.c.

References fd(), i, ListenSocket, and PGINVALID_SOCKET.

Referenced by ServerLoop().

{
    int         maxsock = -1;
    int         i;

    FD_ZERO(rmask);

    for (i = 0; i < MAXLISTEN; i++)
    {
        int         fd = ListenSocket[i];

        if (fd == PGINVALID_SOCKET)
            break;
        FD_SET(fd, rmask);

        if (fd > maxsock)
            maxsock = fd;
    }

    return maxsock + 1;
}

static void InitPostmasterDeathWatchHandle ( void   )  [static]

Definition at line 6238 of file postmaster.c.

References Assert, ereport, errcode_for_file_access(), errcode_for_socket_access(), errmsg_internal(), FATAL, MyProcPid, POSTMASTER_FD_WATCH, PostmasterPid, and TRUE.

Referenced by PostmasterMain().

{
#ifndef WIN32

    /*
     * Create a pipe. Postmaster holds the write end of the pipe open
     * (POSTMASTER_FD_OWN), and children hold the read end. Children can pass
     * the read file descriptor to select() to wake up in case postmaster
     * dies, or check for postmaster death with a (read() == 0). Children must
     * close the write end as soon as possible after forking, because EOF
     * won't be signaled in the read end until all processes have closed the
     * write fd. That is taken care of in ClosePostmasterPorts().
     */
    Assert(MyProcPid == PostmasterPid);
    if (pipe(postmaster_alive_fds))
        ereport(FATAL,
                (errcode_for_file_access(),
                 errmsg_internal("could not create pipe to monitor postmaster death: %m")));

    /*
     * Set O_NONBLOCK to allow testing for the fd's presence with a read()
     * call.
     */
    if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETFL, O_NONBLOCK))
        ereport(FATAL,
                (errcode_for_socket_access(),
                 errmsg_internal("could not set postmaster death monitoring pipe to nonblocking mode: %m")));
#else

    /*
     * On Windows, we use a process handle for the same purpose.
     */
    if (DuplicateHandle(GetCurrentProcess(),
                        GetCurrentProcess(),
                        GetCurrentProcess(),
                        &PostmasterHandle,
                        0,
                        TRUE,
                        DUPLICATE_SAME_ACCESS) == 0)
        ereport(FATAL,
                (errmsg_internal("could not duplicate postmaster handle: error code %lu",
                                 GetLastError())));
#endif   /* WIN32 */
}

static void LogChildExit ( int  lev,
const char *  procname,
int  pid,
int  exitstatus 
) [static]

Definition at line 3187 of file postmaster.c.

References ereport, errdetail(), errhint(), errmsg(), EXIT_STATUS_0, pgstat_get_crashed_backend_activity(), WEXITSTATUS, WIFEXITED, WIFSIGNALED, and WTERMSIG.

Referenced by CleanupBackend(), CleanupBackgroundWorker(), HandleChildCrash(), and reaper().

{
    /*
     * size of activity_buffer is arbitrary, but set equal to default
     * track_activity_query_size
     */
    char        activity_buffer[1024];
    const char *activity = NULL;

    if (!EXIT_STATUS_0(exitstatus))
        activity = pgstat_get_crashed_backend_activity(pid,
                                                       activity_buffer,
                                                    sizeof(activity_buffer));

    if (WIFEXITED(exitstatus))
        ereport(lev,

        /*------
          translator: %s is a noun phrase describing a child process, such as
          "server process" */
                (errmsg("%s (PID %d) exited with exit code %d",
                        procname, pid, WEXITSTATUS(exitstatus)),
                 activity ? errdetail("Failed process was running: %s", activity) : 0));
    else if (WIFSIGNALED(exitstatus))
#if defined(WIN32)
        ereport(lev,

        /*------
          translator: %s is a noun phrase describing a child process, such as
          "server process" */
                (errmsg("%s (PID %d) was terminated by exception 0x%X",
                        procname, pid, WTERMSIG(exitstatus)),
                 errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
                 activity ? errdetail("Failed process was running: %s", activity) : 0));
#elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
    ereport(lev,

    /*------
      translator: %s is a noun phrase describing a child process, such as
      "server process" */
            (errmsg("%s (PID %d) was terminated by signal %d: %s",
                    procname, pid, WTERMSIG(exitstatus),
                    WTERMSIG(exitstatus) < NSIG ?
                    sys_siglist[WTERMSIG(exitstatus)] : "(unknown)"),
      activity ? errdetail("Failed process was running: %s", activity) : 0));
#else
        ereport(lev,

        /*------
          translator: %s is a noun phrase describing a child process, such as
          "server process" */
                (errmsg("%s (PID %d) was terminated by signal %d",
                        procname, pid, WTERMSIG(exitstatus)),
                 activity ? errdetail("Failed process was running: %s", activity) : 0));
#endif
    else
        ereport(lev,

        /*------
          translator: %s is a noun phrase describing a child process, such as
          "server process" */
                (errmsg("%s (PID %d) exited with unrecognized status %d",
                        procname, pid, exitstatus),
                 activity ? errdetail("Failed process was running: %s", activity) : 0));
}

int MaxLivePostmasterChildren ( void   ) 
static void pmdie ( SIGNAL_ARGS   )  [static]

Definition at line 2328 of file postmaster.c.

References AutoVacPID, BACKEND_TYPE_AUTOVAC, BACKEND_TYPE_BGWORKER, BACKEND_TYPE_NORMAL, BgWriterPID, BlockSig, CheckpointerPID, DEBUG2, ereport, errmsg(), errmsg_internal(), ExitPostmaster(), FastShutdown, LOG, PG_SETMASK, PgArchPID, PgStatPID, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_STARTUP, PM_WAIT_BACKENDS, PM_WAIT_BACKUP, PM_WAIT_READONLY, pmState, PostmasterStateMachine(), Shutdown, signal_child(), SignalChildren, SignalSomeChildren(), SignalUnconnectedWorkers(), SIGQUIT, SmartShutdown, StartupPID, UnBlockSig, WalReceiverPID, and WalWriterPID.

Referenced by PostmasterMain().

{
    int         save_errno = errno;

    PG_SETMASK(&BlockSig);

    ereport(DEBUG2,
            (errmsg_internal("postmaster received signal %d",
                             postgres_signal_arg)));

    switch (postgres_signal_arg)
    {
        case SIGTERM:

            /*
             * Smart Shutdown:
             *
             * Wait for children to end their work, then shut down.
             */
            if (Shutdown >= SmartShutdown)
                break;
            Shutdown = SmartShutdown;
            ereport(LOG,
                    (errmsg("received smart shutdown request")));

            if (pmState == PM_RUN || pmState == PM_RECOVERY ||
                pmState == PM_HOT_STANDBY || pmState == PM_STARTUP)
            {
                /* autovac workers are told to shut down immediately */
                /* and bgworkers too; does this need tweaking? */
                SignalSomeChildren(SIGTERM,
                               BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER);
                SignalUnconnectedWorkers(SIGTERM);
                /* and the autovac launcher too */
                if (AutoVacPID != 0)
                    signal_child(AutoVacPID, SIGTERM);
                /* and the bgwriter too */
                if (BgWriterPID != 0)
                    signal_child(BgWriterPID, SIGTERM);
                /* and the walwriter too */
                if (WalWriterPID != 0)
                    signal_child(WalWriterPID, SIGTERM);

                /*
                 * If we're in recovery, we can't kill the startup process
                 * right away, because at present doing so does not release
                 * its locks.  We might want to change this in a future
                 * release.  For the time being, the PM_WAIT_READONLY state
                 * indicates that we're waiting for the regular (read only)
                 * backends to die off; once they do, we'll kill the startup
                 * and walreceiver processes.
                 */
                pmState = (pmState == PM_RUN) ?
                    PM_WAIT_BACKUP : PM_WAIT_READONLY;
            }

            /*
             * Now wait for online backup mode to end and backends to exit. If
             * that is already the case, PostmasterStateMachine will take the
             * next step.
             */
            PostmasterStateMachine();
            break;

        case SIGINT:

            /*
             * Fast Shutdown:
             *
             * Abort all children with SIGTERM (rollback active transactions
             * and exit) and shut down when they are gone.
             */
            if (Shutdown >= FastShutdown)
                break;
            Shutdown = FastShutdown;
            ereport(LOG,
                    (errmsg("received fast shutdown request")));

            if (StartupPID != 0)
                signal_child(StartupPID, SIGTERM);
            if (BgWriterPID != 0)
                signal_child(BgWriterPID, SIGTERM);
            if (WalReceiverPID != 0)
                signal_child(WalReceiverPID, SIGTERM);
            SignalUnconnectedWorkers(SIGTERM);
            if (pmState == PM_RECOVERY)
            {
                /*
                 * Only startup, bgwriter, walreceiver, unconnected bgworkers,
                 * and/or checkpointer should be active in this state; we just
                 * signaled the first four, and we don't want to kill
                 * checkpointer yet.
                 */
                pmState = PM_WAIT_BACKENDS;
            }
            else if (pmState == PM_RUN ||
                     pmState == PM_WAIT_BACKUP ||
                     pmState == PM_WAIT_READONLY ||
                     pmState == PM_WAIT_BACKENDS ||
                     pmState == PM_HOT_STANDBY)
            {
                ereport(LOG,
                        (errmsg("aborting any active transactions")));
                /* shut down all backends and workers */
                SignalSomeChildren(SIGTERM,
                                 BACKEND_TYPE_NORMAL | BACKEND_TYPE_AUTOVAC |
                                   BACKEND_TYPE_BGWORKER);
                /* and the autovac launcher too */
                if (AutoVacPID != 0)
                    signal_child(AutoVacPID, SIGTERM);
                /* and the walwriter too */
                if (WalWriterPID != 0)
                    signal_child(WalWriterPID, SIGTERM);
                pmState = PM_WAIT_BACKENDS;
            }

            /*
             * Now wait for backends to exit.  If there are none,
             * PostmasterStateMachine will take the next step.
             */
            PostmasterStateMachine();
            break;

        case SIGQUIT:

            /*
             * Immediate Shutdown:
             *
             * abort all children with SIGQUIT and exit without attempt to
             * properly shut down data base system.
             */
            ereport(LOG,
                    (errmsg("received immediate shutdown request")));
            SignalChildren(SIGQUIT);
            if (StartupPID != 0)
                signal_child(StartupPID, SIGQUIT);
            if (BgWriterPID != 0)
                signal_child(BgWriterPID, SIGQUIT);
            if (CheckpointerPID != 0)
                signal_child(CheckpointerPID, SIGQUIT);
            if (WalWriterPID != 0)
                signal_child(WalWriterPID, SIGQUIT);
            if (WalReceiverPID != 0)
                signal_child(WalReceiverPID, SIGQUIT);
            if (AutoVacPID != 0)
                signal_child(AutoVacPID, SIGQUIT);
            if (PgArchPID != 0)
                signal_child(PgArchPID, SIGQUIT);
            if (PgStatPID != 0)
                signal_child(PgStatPID, SIGQUIT);
            SignalUnconnectedWorkers(SIGQUIT);
            ExitPostmaster(0);
            break;
    }

    PG_SETMASK(&UnBlockSig);

    errno = save_errno;
}

void PostmasterMain ( int  argc,
char *  argv[] 
)

Definition at line 557 of file postmaster.c.

References AddToDataDirLockFile(), ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, autovac_init(), BlockSig, bonjour_name, ChangeToDataDir(), checkDataDir(), CheckDateTokenTables(), CreateDataDirLockFile(), CreateOptsFile(), DEBUG3, dummy_handler(), elog, enable_bonjour, EnableSSL, environ, ereport, errcode(), errmsg(), errmsg_internal(), ERROR, ExitPostmaster(), external_pid_file, ExtraOptions, FATAL, free, get_stats_option_name(), GetConfigOption(), GetCurrentTimestamp(), getInstallationPaths(), getopt(), gettimeofday(), i, InitializeGUCOptions(), InitializeMaxBackends(), InitPostmasterDeathWatchHandle(), IsBinaryUpgrade, IsPostmasterEnvironment, lfirst, list_free(), list_free_deep(), ListenAddresses, ListenSocket, load_hba(), load_ident(), LOCK_FILE_LINE_LISTEN_ADDR, LOCK_FILE_LINE_SOCKET_DIR, LOG, max_wal_senders, MaxConnections, MemoryContextInit(), MemoryContextSwitchTo(), my_exec_path, MyProcPid, MyStartTime, name, NIL, NULL, on_proc_exit(), optarg, opterr, optind, output_config_variable, ParseLongOption(), pfree(), PG_SETMASK, PGC_POSTMASTER, PGC_S_ARGV, PGINVALID_SOCKET, PgStartTime, pgstat_init(), pmdie(), pmState, PostmasterContext, PostmasterPid, PostPortNumber, pqinitmask(), pqsignal(), process_shared_preload_libraries(), progname, pstrdup(), random_start_time, reaper(), Reinit, RemovePgTempFiles(), ReservedBackends, reset_shared(), S_IRGRP, S_IROTH, S_IRWXG, S_IRWXO, secure_initialize(), SelectConfigFiles(), SendStop, ServerLoop(), set_debug_options(), set_max_safe_fds(), set_plan_disabling_options(), set_stack_base(), SetConfigOption(), SIG_IGN, SIGALRM, SIGCHLD, SIGHUP, SIGHUP_handler(), SIGPIPE, SIGQUIT, SIGTTIN, SIGTTOU, SIGUSR1, sigusr1_handler(), SIGUSR2, snprintf(), SplitDirectoriesString(), SplitIdentifierString(), StartOneBackgroundWorker(), StartupDataBase, StartupPID, STATUS_OK, StreamServerPort(), strerror(), SysLogger_Start(), SysLoggerPID, TopMemoryContext, Unix_socket_directories, unlink_external_pid_file(), userDoption, value, wal_level, WAL_LEVEL_MINIMAL, WARNING, whereToSendOutput, write_stderr, and XLogArchiveMode.

Referenced by main().

{
    int         opt;
    int         status;
    char       *userDoption = NULL;
    bool        listen_addr_saved = false;
    int         i;

    MyProcPid = PostmasterPid = getpid();

    MyStartTime = time(NULL);

    IsPostmasterEnvironment = true;

    /*
     * for security, no dir or file created can be group or other accessible
     */
    umask(S_IRWXG | S_IRWXO);

    /*
     * Fire up essential subsystems: memory management
     */
    MemoryContextInit();

    /*
     * By default, palloc() requests in the postmaster will be allocated in
     * the PostmasterContext, which is space that can be recycled by backends.
     * Allocated data that needs to be available to backends should be
     * allocated in TopMemoryContext.
     */
    PostmasterContext = AllocSetContextCreate(TopMemoryContext,
                                              "Postmaster",
                                              ALLOCSET_DEFAULT_MINSIZE,
                                              ALLOCSET_DEFAULT_INITSIZE,
                                              ALLOCSET_DEFAULT_MAXSIZE);
    MemoryContextSwitchTo(PostmasterContext);

    /* Initialize paths to installation files */
    getInstallationPaths(argv[0]);

    /*
     * Options setup
     */
    InitializeGUCOptions();

    opterr = 1;

    /*
     * Parse command-line options.  CAUTION: keep this in sync with
     * tcop/postgres.c (the option sets should not conflict) and with the
     * common help() function in main/main.c.
     */
    while ((opt = getopt(argc, argv, "A:B:bc:C:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:W:-:")) != -1)
    {
        switch (opt)
        {
            case 'A':
                SetConfigOption("debug_assertions", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'B':
                SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'b':
                /* Undocumented flag used for binary upgrades */
                IsBinaryUpgrade = true;
                break;

            case 'C':
                output_config_variable = strdup(optarg);
                break;

            case 'D':
                userDoption = strdup(optarg);
                break;

            case 'd':
                set_debug_options(atoi(optarg), PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'E':
                SetConfigOption("log_statement", "all", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'e':
                SetConfigOption("datestyle", "euro", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'F':
                SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'f':
                if (!set_plan_disabling_options(optarg, PGC_POSTMASTER, PGC_S_ARGV))
                {
                    write_stderr("%s: invalid argument for option -f: \"%s\"\n",
                                 progname, optarg);
                    ExitPostmaster(1);
                }
                break;

            case 'h':
                SetConfigOption("listen_addresses", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'i':
                SetConfigOption("listen_addresses", "*", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'j':
                /* only used by interactive backend */
                break;

            case 'k':
                SetConfigOption("unix_socket_directories", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'l':
                SetConfigOption("ssl", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'N':
                SetConfigOption("max_connections", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'n':
                /* Don't reinit shared mem after abnormal exit */
                Reinit = false;
                break;

            case 'O':
                SetConfigOption("allow_system_table_mods", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'o':
                /* Other options to pass to the backend on the command line */
                snprintf(ExtraOptions + strlen(ExtraOptions),
                         sizeof(ExtraOptions) - strlen(ExtraOptions),
                         " %s", optarg);
                break;

            case 'P':
                SetConfigOption("ignore_system_indexes", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'p':
                SetConfigOption("port", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'r':
                /* only used by single-user backend */
                break;

            case 'S':
                SetConfigOption("work_mem", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 's':
                SetConfigOption("log_statement_stats", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'T':

                /*
                 * In the event that some backend dumps core, send SIGSTOP,
                 * rather than SIGQUIT, to all its peers.  This lets the wily
                 * post_hacker collect core dumps from everyone.
                 */
                SendStop = true;
                break;

            case 't':
                {
                    const char *tmp = get_stats_option_name(optarg);

                    if (tmp)
                    {
                        SetConfigOption(tmp, "true", PGC_POSTMASTER, PGC_S_ARGV);
                    }
                    else
                    {
                        write_stderr("%s: invalid argument for option -t: \"%s\"\n",
                                     progname, optarg);
                        ExitPostmaster(1);
                    }
                    break;
                }

            case 'W':
                SetConfigOption("post_auth_delay", optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'c':
            case '-':
                {
                    char       *name,
                               *value;

                    ParseLongOption(optarg, &name, &value);
                    if (!value)
                    {
                        if (opt == '-')
                            ereport(ERROR,
                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                     errmsg("--%s requires a value",
                                            optarg)));
                        else
                            ereport(ERROR,
                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                     errmsg("-c %s requires a value",
                                            optarg)));
                    }

                    SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
                    free(name);
                    if (value)
                        free(value);
                    break;
                }

            default:
                write_stderr("Try \"%s --help\" for more information.\n",
                             progname);
                ExitPostmaster(1);
        }
    }

    /*
     * Postmaster accepts no non-option switch arguments.
     */
    if (optind < argc)
    {
        write_stderr("%s: invalid argument: \"%s\"\n",
                     progname, argv[optind]);
        write_stderr("Try \"%s --help\" for more information.\n",
                     progname);
        ExitPostmaster(1);
    }

    /*
     * Locate the proper configuration files and data directory, and read
     * postgresql.conf for the first time.
     */
    if (!SelectConfigFiles(userDoption, progname))
        ExitPostmaster(2);

    if (output_config_variable != NULL)
    {
        /*
         * permission is handled because the user is reading inside the data
         * dir
         */
        puts(GetConfigOption(output_config_variable, false, false));
        ExitPostmaster(0);
    }

    /* Verify that DataDir looks reasonable */
    checkDataDir();

    /* And switch working directory into it */
    ChangeToDataDir();

    /*
     * Check for invalid combinations of GUC settings.
     */
    if (ReservedBackends >= MaxConnections)
    {
        write_stderr("%s: superuser_reserved_connections must be less than max_connections\n", progname);
        ExitPostmaster(1);
    }
    if (max_wal_senders >= MaxConnections)
    {
        write_stderr("%s: max_wal_senders must be less than max_connections\n", progname);
        ExitPostmaster(1);
    }
    if (XLogArchiveMode && wal_level == WAL_LEVEL_MINIMAL)
        ereport(ERROR,
                (errmsg("WAL archival (archive_mode=on) requires wal_level \"archive\" or \"hot_standby\"")));
    if (max_wal_senders > 0 && wal_level == WAL_LEVEL_MINIMAL)
        ereport(ERROR,
                (errmsg("WAL streaming (max_wal_senders > 0) requires wal_level \"archive\" or \"hot_standby\"")));

    /*
     * Other one-time internal sanity checks can go here, if they are fast.
     * (Put any slow processing further down, after postmaster.pid creation.)
     */
    if (!CheckDateTokenTables())
    {
        write_stderr("%s: invalid datetoken tables, please fix\n", progname);
        ExitPostmaster(1);
    }

    /*
     * Now that we are done processing the postmaster arguments, reset
     * getopt(3) library so that it will work correctly in subprocesses.
     */
    optind = 1;
#ifdef HAVE_INT_OPTRESET
    optreset = 1;               /* some systems need this too */
#endif

    /* For debugging: display postmaster environment */
    {
        extern char **environ;
        char      **p;

        ereport(DEBUG3,
            (errmsg_internal("%s: PostmasterMain: initial environment dump:",
                             progname)));
        ereport(DEBUG3,
             (errmsg_internal("-----------------------------------------")));
        for (p = environ; *p; ++p)
            ereport(DEBUG3,
                    (errmsg_internal("\t%s", *p)));
        ereport(DEBUG3,
             (errmsg_internal("-----------------------------------------")));
    }

    /*
     * Create lockfile for data directory.
     *
     * We want to do this before we try to grab the input sockets, because the
     * data directory interlock is more reliable than the socket-file
     * interlock (thanks to whoever decided to put socket files in /tmp :-().
     * For the same reason, it's best to grab the TCP socket(s) before the
     * Unix socket(s).
     */
    CreateDataDirLockFile(true);

    /*
     * Initialize SSL library, if specified.
     */
#ifdef USE_SSL
    if (EnableSSL)
        secure_initialize();
#endif

    /*
     * process any libraries that should be preloaded at postmaster start
     */
    process_shared_preload_libraries();

    /*
     * Now that loadable modules have had their chance to register background
     * workers, calculate MaxBackends.
     */
    InitializeMaxBackends();

    /*
     * Establish input sockets.
     */
    for (i = 0; i < MAXLISTEN; i++)
        ListenSocket[i] = PGINVALID_SOCKET;

    if (ListenAddresses)
    {
        char       *rawstring;
        List       *elemlist;
        ListCell   *l;
        int         success = 0;

        /* Need a modifiable copy of ListenAddresses */
        rawstring = pstrdup(ListenAddresses);

        /* Parse string into list of hostnames */
        if (!SplitIdentifierString(rawstring, ',', &elemlist))
        {
            /* syntax error in list */
            ereport(FATAL,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("invalid list syntax for \"listen_addresses\"")));
        }

        foreach(l, elemlist)
        {
            char       *curhost = (char *) lfirst(l);

            if (strcmp(curhost, "*") == 0)
                status = StreamServerPort(AF_UNSPEC, NULL,
                                          (unsigned short) PostPortNumber,
                                          NULL,
                                          ListenSocket, MAXLISTEN);
            else
                status = StreamServerPort(AF_UNSPEC, curhost,
                                          (unsigned short) PostPortNumber,
                                          NULL,
                                          ListenSocket, MAXLISTEN);

            if (status == STATUS_OK)
            {
                success++;
                /* record the first successful host addr in lockfile */
                if (!listen_addr_saved)
                {
                    AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, curhost);
                    listen_addr_saved = true;
                }
            }
            else
                ereport(WARNING,
                        (errmsg("could not create listen socket for \"%s\"",
                                curhost)));
        }

        if (!success && elemlist != NIL)
            ereport(FATAL,
                    (errmsg("could not create any TCP/IP sockets")));

        list_free(elemlist);
        pfree(rawstring);
    }

#ifdef USE_BONJOUR
    /* Register for Bonjour only if we opened TCP socket(s) */
    if (enable_bonjour && ListenSocket[0] != PGINVALID_SOCKET)
    {
        DNSServiceErrorType err;

        /*
         * We pass 0 for interface_index, which will result in registering on
         * all "applicable" interfaces.  It's not entirely clear from the
         * DNS-SD docs whether this would be appropriate if we have bound to
         * just a subset of the available network interfaces.
         */
        err = DNSServiceRegister(&bonjour_sdref,
                                 0,
                                 0,
                                 bonjour_name,
                                 "_postgresql._tcp.",
                                 NULL,
                                 NULL,
                                 htons(PostPortNumber),
                                 0,
                                 NULL,
                                 NULL,
                                 NULL);
        if (err != kDNSServiceErr_NoError)
            elog(LOG, "DNSServiceRegister() failed: error code %ld",
                 (long) err);

        /*
         * We don't bother to read the mDNS daemon's reply, and we expect that
         * it will automatically terminate our registration when the socket is
         * closed at postmaster termination.  So there's nothing more to be
         * done here.  However, the bonjour_sdref is kept around so that
         * forked children can close their copies of the socket.
         */
    }
#endif

#ifdef HAVE_UNIX_SOCKETS
    if (Unix_socket_directories)
    {
        char       *rawstring;
        List       *elemlist;
        ListCell   *l;
        int         success = 0;

        /* Need a modifiable copy of Unix_socket_directories */
        rawstring = pstrdup(Unix_socket_directories);

        /* Parse string into list of directories */
        if (!SplitDirectoriesString(rawstring, ',', &elemlist))
        {
            /* syntax error in list */
            ereport(FATAL,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("invalid list syntax for \"unix_socket_directories\"")));
        }

        foreach(l, elemlist)
        {
            char       *socketdir = (char *) lfirst(l);

            status = StreamServerPort(AF_UNIX, NULL,
                                      (unsigned short) PostPortNumber,
                                      socketdir,
                                      ListenSocket, MAXLISTEN);

            if (status == STATUS_OK)
            {
                success++;
                /* record the first successful Unix socket in lockfile */
                if (success == 1)
                    AddToDataDirLockFile(LOCK_FILE_LINE_SOCKET_DIR, socketdir);
            }
            else
                ereport(WARNING,
                        (errmsg("could not create Unix-domain socket in directory \"%s\"",
                                socketdir)));
        }

        if (!success && elemlist != NIL)
            ereport(FATAL,
                    (errmsg("could not create any Unix-domain sockets")));

        list_free_deep(elemlist);
        pfree(rawstring);
    }
#endif

    /*
     * check that we have some socket to listen on
     */
    if (ListenSocket[0] == PGINVALID_SOCKET)
        ereport(FATAL,
                (errmsg("no socket created for listening")));

    /*
     * If no valid TCP ports, write an empty line for listen address,
     * indicating the Unix socket must be used.  Note that this line is not
     * added to the lock file until there is a socket backing it.
     */
    if (!listen_addr_saved)
        AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, "");

    /*
     * Set up shared memory and semaphores.
     */
    reset_shared(PostPortNumber);

    /*
     * Estimate number of openable files.  This must happen after setting up
     * semaphores, because on some platforms semaphores count as open files.
     */
    set_max_safe_fds();

    /*
     * Set reference point for stack-depth checking.
     */
    set_stack_base();

    /*
     * Initialize pipe (or process handle on Windows) that allows children to
     * wake up from sleep on postmaster death.
     */
    InitPostmasterDeathWatchHandle();

#ifdef WIN32

    /*
     * Initialize I/O completion port used to deliver list of dead children.
     */
    win32ChildQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
    if (win32ChildQueue == NULL)
        ereport(FATAL,
           (errmsg("could not create I/O completion port for child queue")));
#endif

    /*
     * Record postmaster options.  We delay this till now to avoid recording
     * bogus options (eg, NBuffers too high for available memory).
     */
    if (!CreateOptsFile(argc, argv, my_exec_path))
        ExitPostmaster(1);

#ifdef EXEC_BACKEND
    /* Write out nondefault GUC settings for child processes to use */
    write_nondefault_variables(PGC_POSTMASTER);
#endif

    /*
     * Write the external PID file if requested
     */
    if (external_pid_file)
    {
        FILE       *fpidfile = fopen(external_pid_file, "w");

        if (fpidfile)
        {
            fprintf(fpidfile, "%d\n", MyProcPid);
            fclose(fpidfile);

            /* Make PID file world readable */
            if (chmod(external_pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0)
                write_stderr("%s: could not change permissions of external PID file \"%s\": %s\n",
                             progname, external_pid_file, strerror(errno));
        }
        else
            write_stderr("%s: could not write external PID file \"%s\": %s\n",
                         progname, external_pid_file, strerror(errno));

        on_proc_exit(unlink_external_pid_file, 0);
    }

    /*
     * Set up signal handlers for the postmaster process.
     *
     * CAUTION: when changing this list, check for side-effects on the signal
     * handling setup of child processes.  See tcop/postgres.c,
     * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/walwriter.c,
     * postmaster/autovacuum.c, postmaster/pgarch.c, postmaster/pgstat.c,
     * postmaster/syslogger.c, postmaster/bgworker.c and
     * postmaster/checkpointer.c.
     */
    pqinitmask();
    PG_SETMASK(&BlockSig);

    pqsignal(SIGHUP, SIGHUP_handler);   /* reread config file and have
                                         * children do same */
    pqsignal(SIGINT, pmdie);    /* send SIGTERM and shut down */
    pqsignal(SIGQUIT, pmdie);   /* send SIGQUIT and die */
    pqsignal(SIGTERM, pmdie);   /* wait for children and shut down */
    pqsignal(SIGALRM, SIG_IGN); /* ignored */
    pqsignal(SIGPIPE, SIG_IGN); /* ignored */
    pqsignal(SIGUSR1, sigusr1_handler); /* message from child process */
    pqsignal(SIGUSR2, dummy_handler);   /* unused, reserve for children */
    pqsignal(SIGCHLD, reaper);  /* handle child termination */
    pqsignal(SIGTTIN, SIG_IGN); /* ignored */
    pqsignal(SIGTTOU, SIG_IGN); /* ignored */
    /* ignore SIGXFSZ, so that ulimit violations work like disk full */
#ifdef SIGXFSZ
    pqsignal(SIGXFSZ, SIG_IGN); /* ignored */
#endif

    /*
     * If enabled, start up syslogger collection subprocess
     */
    SysLoggerPID = SysLogger_Start();

    /*
     * Reset whereToSendOutput from DestDebug (its starting state) to
     * DestNone. This stops ereport from sending log messages to stderr unless
     * Log_destination permits.  We don't do this until the postmaster is
     * fully launched, since startup failures may as well be reported to
     * stderr.
     */
    whereToSendOutput = DestNone;

    /*
     * Initialize stats collection subsystem (this does NOT start the
     * collector process!)
     */
    pgstat_init();

    /*
     * Initialize the autovacuum subsystem (again, no process start yet)
     */
    autovac_init();

    /*
     * Load configuration files for client authentication.
     */
    if (!load_hba())
    {
        /*
         * It makes no sense to continue if we fail to load the HBA file,
         * since there is no way to connect to the database in this case.
         */
        ereport(FATAL,
                (errmsg("could not load pg_hba.conf")));
    }
    if (!load_ident())
    {
        /*
         * We can start up without the IDENT file, although it means that you
         * cannot log in using any of the authentication methods that need a
         * user name mapping. load_ident() already logged the details of
         * error to the log.
         */
    }


    /*
     * Remove old temporary files.  At this point there can be no other
     * Postgres processes running in this directory, so this should be safe.
     */
    RemovePgTempFiles();

    /*
     * Remember postmaster startup time
     */
    PgStartTime = GetCurrentTimestamp();
    /* PostmasterRandom wants its own copy */
    gettimeofday(&random_start_time, NULL);

    /*
     * We're ready to rock and roll...
     */
    StartupPID = StartupDataBase();
    Assert(StartupPID != 0);
    pmState = PM_STARTUP;

    /* Some workers may be scheduled to start now */
    StartOneBackgroundWorker();

    status = ServerLoop();

    /*
     * ServerLoop probably shouldn't ever return, but if it does, close down.
     */
    ExitPostmaster(status != STATUS_OK);

    abort();                    /* not reached */
}

static long PostmasterRandom ( void   )  [static]

Definition at line 4800 of file postmaster.c.

References gettimeofday(), NULL, random(), random_seed, random_start_time, and srandom().

Referenced by assign_backendlist_entry(), BackendStartup(), RandomSalt(), and StartAutovacuumWorker().

{
    /*
     * Select a random seed at the time of first receiving a request.
     */
    if (random_seed == 0)
    {
        do
        {
            struct timeval random_stop_time;

            gettimeofday(&random_stop_time, NULL);

            /*
             * We are not sure how much precision is in tv_usec, so we swap
             * the high and low 16 bits of 'random_stop_time' and XOR them
             * with 'random_start_time'. On the off chance that the result is
             * 0, we loop until it isn't.
             */
            random_seed = random_start_time.tv_usec ^
                ((random_stop_time.tv_usec << 16) |
                 ((random_stop_time.tv_usec >> 16) & 0xffff));
        }
        while (random_seed == 0);

        srandom(random_seed);
    }

    return random();
}

static void PostmasterStateMachine ( void   )  [static]

Definition at line 3260 of file postmaster.c.

References Assert, AutoVacPID, BACKEND_TYPE_ALL, BACKEND_TYPE_NORMAL, BACKEND_TYPE_WORKER, BackupInProgress(), BgWriterPID, CancelBackup(), CheckpointerPID, CountChildren(), CountUnconnectedWorkers(), dlist_is_empty(), ereport, errmsg(), ExitPostmaster(), FatalError, LOG, NoShutdown, PgArchPID, PgStatPID, PM_NO_CHILDREN, PM_SHUTDOWN_2, PM_WAIT_BACKENDS, PM_WAIT_BACKUP, PM_WAIT_DEAD_END, PM_WAIT_READONLY, pmState, PostPortNumber, ReachedNormalRunning, RecoveryError, reset_shared(), restart_after_crash, shmem_exit(), Shutdown, signal_child(), SignalChildren, SIGQUIT, SIGUSR2, StartCheckpointer, StartupDataBase, StartupPID, WalReceiverPID, and WalWriterPID.

Referenced by pmdie(), reaper(), and sigusr1_handler().

{
    if (pmState == PM_WAIT_BACKUP)
    {
        /*
         * PM_WAIT_BACKUP state ends when online backup mode is not active.
         */
        if (!BackupInProgress())
            pmState = PM_WAIT_BACKENDS;
    }

    if (pmState == PM_WAIT_READONLY)
    {
        /*
         * PM_WAIT_READONLY state ends when we have no regular backends that
         * have been started during recovery.  We kill the startup and
         * walreceiver processes and transition to PM_WAIT_BACKENDS.  Ideally,
         * we might like to kill these processes first and then wait for
         * backends to die off, but that doesn't work at present because
         * killing the startup process doesn't release its locks.
         */
        if (CountChildren(BACKEND_TYPE_NORMAL) == 0)
        {
            if (StartupPID != 0)
                signal_child(StartupPID, SIGTERM);
            if (WalReceiverPID != 0)
                signal_child(WalReceiverPID, SIGTERM);
            pmState = PM_WAIT_BACKENDS;
        }
    }

    /*
     * If we are in a state-machine state that implies waiting for backends to
     * exit, see if they're all gone, and change state if so.
     */
    if (pmState == PM_WAIT_BACKENDS)
    {
        /*
         * PM_WAIT_BACKENDS state ends when we have no regular backends
         * (including autovac workers), no bgworkers (including unconnected
         * ones), and no walwriter, autovac launcher or bgwriter.  If we are
         * doing crash recovery then we expect the checkpointer to exit as
         * well, otherwise not. The archiver, stats, and syslogger processes
         * are disregarded since they are not connected to shared memory; we
         * also disregard dead_end children here. Walsenders are also
         * disregarded, they will be terminated later after writing the
         * checkpoint record, like the archiver process.
         */
        if (CountChildren(BACKEND_TYPE_NORMAL | BACKEND_TYPE_WORKER) == 0 &&
            CountUnconnectedWorkers() == 0 &&
            StartupPID == 0 &&
            WalReceiverPID == 0 &&
            BgWriterPID == 0 &&
            (CheckpointerPID == 0 || !FatalError) &&
            WalWriterPID == 0 &&
            AutoVacPID == 0)
        {
            if (FatalError)
            {
                /*
                 * Start waiting for dead_end children to die.  This state
                 * change causes ServerLoop to stop creating new ones.
                 */
                pmState = PM_WAIT_DEAD_END;

                /*
                 * We already SIGQUIT'd the archiver and stats processes, if
                 * any, when we entered FatalError state.
                 */
            }
            else
            {
                /*
                 * If we get here, we are proceeding with normal shutdown. All
                 * the regular children are gone, and it's time to tell the
                 * checkpointer to do a shutdown checkpoint.
                 */
                Assert(Shutdown > NoShutdown);
                /* Start the checkpointer if not running */
                if (CheckpointerPID == 0)
                    CheckpointerPID = StartCheckpointer();
                /* And tell it to shut down */
                if (CheckpointerPID != 0)
                {
                    signal_child(CheckpointerPID, SIGUSR2);
                    pmState = PM_SHUTDOWN;
                }
                else
                {
                    /*
                     * If we failed to fork a checkpointer, just shut down.
                     * Any required cleanup will happen at next restart. We
                     * set FatalError so that an "abnormal shutdown" message
                     * gets logged when we exit.
                     */
                    FatalError = true;
                    pmState = PM_WAIT_DEAD_END;

                    /* Kill the walsenders, archiver and stats collector too */
                    SignalChildren(SIGQUIT);
                    if (PgArchPID != 0)
                        signal_child(PgArchPID, SIGQUIT);
                    if (PgStatPID != 0)
                        signal_child(PgStatPID, SIGQUIT);
                }
            }
        }
    }

    if (pmState == PM_SHUTDOWN_2)
    {
        /*
         * PM_SHUTDOWN_2 state ends when there's no other children than
         * dead_end children left. There shouldn't be any regular backends
         * left by now anyway; what we're really waiting for is walsenders and
         * archiver.
         *
         * Walreceiver should normally be dead by now, but not when a fast
         * shutdown is performed during recovery.
         */
        if (PgArchPID == 0 && CountChildren(BACKEND_TYPE_ALL) == 0 &&
            WalReceiverPID == 0)
        {
            pmState = PM_WAIT_DEAD_END;
        }
    }

    if (pmState == PM_WAIT_DEAD_END)
    {
        /*
         * PM_WAIT_DEAD_END state ends when the BackendList is entirely empty
         * (ie, no dead_end children remain), and the archiver and stats
         * collector are gone too.
         *
         * The reason we wait for those two is to protect them against a new
         * postmaster starting conflicting subprocesses; this isn't an
         * ironclad protection, but it at least helps in the
         * shutdown-and-immediately-restart scenario.  Note that they have
         * already been sent appropriate shutdown signals, either during a
         * normal state transition leading up to PM_WAIT_DEAD_END, or during
         * FatalError processing.
         */
        if (dlist_is_empty(&BackendList) &&
            PgArchPID == 0 && PgStatPID == 0)
        {
            /* These other guys should be dead already */
            Assert(StartupPID == 0);
            Assert(WalReceiverPID == 0);
            Assert(BgWriterPID == 0);
            Assert(CheckpointerPID == 0);
            Assert(WalWriterPID == 0);
            Assert(AutoVacPID == 0);
            /* syslogger is not considered here */
            pmState = PM_NO_CHILDREN;
        }
    }

    /*
     * If we've been told to shut down, we exit as soon as there are no
     * remaining children.  If there was a crash, cleanup will occur at the
     * next startup.  (Before PostgreSQL 8.3, we tried to recover from the
     * crash before exiting, but that seems unwise if we are quitting because
     * we got SIGTERM from init --- there may well not be time for recovery
     * before init decides to SIGKILL us.)
     *
     * Note that the syslogger continues to run.  It will exit when it sees
     * EOF on its input pipe, which happens when there are no more upstream
     * processes.
     */
    if (Shutdown > NoShutdown && pmState == PM_NO_CHILDREN)
    {
        if (FatalError)
        {
            ereport(LOG, (errmsg("abnormal database system shutdown")));
            ExitPostmaster(1);
        }
        else
        {
            /*
             * Terminate exclusive backup mode to avoid recovery after a clean
             * fast shutdown.  Since an exclusive backup can only be taken
             * during normal running (and not, for example, while running
             * under Hot Standby) it only makes sense to do this if we reached
             * normal running. If we're still in recovery, the backup file is
             * one we're recovering *from*, and we must keep it around so that
             * recovery restarts from the right place.
             */
            if (ReachedNormalRunning)
                CancelBackup();

            /* Normal exit from the postmaster is here */
            ExitPostmaster(0);
        }
    }

    /*
     * If recovery failed, or the user does not want an automatic restart
     * after backend crashes, wait for all non-syslogger children to exit, and
     * then exit postmaster. We don't try to reinitialize when recovery fails,
     * because more than likely it will just fail again and we will keep
     * trying forever.
     */
    if (pmState == PM_NO_CHILDREN && (RecoveryError || !restart_after_crash))
        ExitPostmaster(1);

    /*
     * If we need to recover from a crash, wait for all non-syslogger children
     * to exit, then reset shmem and StartupDataBase.
     */
    if (FatalError && pmState == PM_NO_CHILDREN)
    {
        ereport(LOG,
                (errmsg("all server processes terminated; reinitializing")));

        shmem_exit(1);
        reset_shared(PostPortNumber);

        StartupPID = StartupDataBase();
        Assert(StartupPID != 0);
        pmState = PM_STARTUP;
    }
}

static void processCancelRequest ( Port port,
void *  pkt 
) [static]

Definition at line 2009 of file postmaster.c.

References CancelRequestPacket::backendPID, bkend::cancel_key, CancelRequestPacket::cancelAuthCode, dlist_iter::cur, DEBUG2, dlist_container, dlist_foreach, ereport, errmsg(), errmsg_internal(), i, LOG, MaxLivePostmasterChildren(), bkend::pid, and signal_child().

Referenced by ProcessStartupPacket().

{
    CancelRequestPacket *canc = (CancelRequestPacket *) pkt;
    int         backendPID;
    long        cancelAuthCode;
    Backend    *bp;

#ifndef EXEC_BACKEND
    dlist_iter  iter;
#else
    int         i;
#endif

    backendPID = (int) ntohl(canc->backendPID);
    cancelAuthCode = (long) ntohl(canc->cancelAuthCode);

    /*
     * See if we have a matching backend.  In the EXEC_BACKEND case, we can no
     * longer access the postmaster's own backend list, and must rely on the
     * duplicate array in shared memory.
     */
#ifndef EXEC_BACKEND
    dlist_foreach(iter, &BackendList)
    {
        bp = dlist_container(Backend, elem, iter.cur);
#else
    for (i = MaxLivePostmasterChildren() - 1; i >= 0; i--)
    {
        bp = (Backend *) &ShmemBackendArray[i];
#endif
        if (bp->pid == backendPID)
        {
            if (bp->cancel_key == cancelAuthCode)
            {
                /* Found a match; signal that backend to cancel current op */
                ereport(DEBUG2,
                        (errmsg_internal("processing cancel request: sending SIGINT to process %d",
                                         backendPID)));
                signal_child(bp->pid, SIGINT);
            }
            else
                /* Right PID, wrong key: no way, Jose */
                ereport(LOG,
                        (errmsg("wrong key in cancel request for process %d",
                                backendPID)));
            return;
        }
    }

    /* No matching backend */
    ereport(LOG,
            (errmsg("PID %d in cancel request did not match any process",
                    backendPID)));
}

static int ProcessStartupPacket ( Port port,
bool  SSLdone 
) [static]

Definition at line 1704 of file postmaster.c.

References SockAddr::addr, am_walsender, buf, CAC_OK, CAC_RECOVERY, CAC_SHUTDOWN, CAC_STARTUP, CAC_TOOMANY, CAC_WAITBACKUP, Port::canAcceptConnections, CANCEL_REQUEST_CODE, Port::cmdline_options, COMMERROR, StartupPacket::database, Port::database_name, Db_user_namespace, EINTR, EnableSSL, ereport, errcode(), ERRCODE_CANNOT_CONNECT_NOW, errcode_for_socket_access(), errmsg(), FATAL, FrontendProtocol, Port::guc_options, IS_AF_UNIX, Port::laddr, lappend(), MAX_STARTUP_PACKET_LENGTH, MemoryContextSwitchTo(), NAMEDATALEN, NEGOTIATE_SSL_CODE, NULL, StartupPacket::options, palloc(), palloc0(), parse_bool(), PG_PROTOCOL_EARLIEST, PG_PROTOCOL_LATEST, PG_PROTOCOL_MAJOR, PG_PROTOCOL_MINOR, pq_getbytes(), processCancelRequest(), Port::proto, pstrdup(), secure_open_server(), send, Port::sock, TopMemoryContext, StartupPacket::user, and Port::user_name.

Referenced by BackendInitialize().

{
    int32       len;
    void       *buf;
    ProtocolVersion proto;
    MemoryContext oldcontext;

    if (pq_getbytes((char *) &len, 4) == EOF)
    {
        /*
         * EOF after SSLdone probably means the client didn't like our
         * response to NEGOTIATE_SSL_CODE.  That's not an error condition, so
         * don't clutter the log with a complaint.
         */
        if (!SSLdone)
            ereport(COMMERROR,
                    (errcode(ERRCODE_PROTOCOL_VIOLATION),
                     errmsg("incomplete startup packet")));
        return STATUS_ERROR;
    }

    len = ntohl(len);
    len -= 4;

    if (len < (int32) sizeof(ProtocolVersion) ||
        len > MAX_STARTUP_PACKET_LENGTH)
    {
        ereport(COMMERROR,
                (errcode(ERRCODE_PROTOCOL_VIOLATION),
                 errmsg("invalid length of startup packet")));
        return STATUS_ERROR;
    }

    /*
     * Allocate at least the size of an old-style startup packet, plus one
     * extra byte, and make sure all are zeroes.  This ensures we will have
     * null termination of all strings, in both fixed- and variable-length
     * packet layouts.
     */
    if (len <= (int32) sizeof(StartupPacket))
        buf = palloc0(sizeof(StartupPacket) + 1);
    else
        buf = palloc0(len + 1);

    if (pq_getbytes(buf, len) == EOF)
    {
        ereport(COMMERROR,
                (errcode(ERRCODE_PROTOCOL_VIOLATION),
                 errmsg("incomplete startup packet")));
        return STATUS_ERROR;
    }

    /*
     * The first field is either a protocol version number or a special
     * request code.
     */
    port->proto = proto = ntohl(*((ProtocolVersion *) buf));

    if (proto == CANCEL_REQUEST_CODE)
    {
        processCancelRequest(port, buf);
        /* Not really an error, but we don't want to proceed further */
        return STATUS_ERROR;
    }

    if (proto == NEGOTIATE_SSL_CODE && !SSLdone)
    {
        char        SSLok;

#ifdef USE_SSL
        /* No SSL when disabled or on Unix sockets */
        if (!EnableSSL || IS_AF_UNIX(port->laddr.addr.ss_family))
            SSLok = 'N';
        else
            SSLok = 'S';        /* Support for SSL */
#else
        SSLok = 'N';            /* No support for SSL */
#endif

retry1:
        if (send(port->sock, &SSLok, 1, 0) != 1)
        {
            if (errno == EINTR)
                goto retry1;    /* if interrupted, just retry */
            ereport(COMMERROR,
                    (errcode_for_socket_access(),
                     errmsg("failed to send SSL negotiation response: %m")));
            return STATUS_ERROR;    /* close the connection */
        }

#ifdef USE_SSL
        if (SSLok == 'S' && secure_open_server(port) == -1)
            return STATUS_ERROR;
#endif
        /* regular startup packet, cancel, etc packet should follow... */
        /* but not another SSL negotiation request */
        return ProcessStartupPacket(port, true);
    }

    /* Could add additional special packet types here */

    /*
     * Set FrontendProtocol now so that ereport() knows what format to send if
     * we fail during startup.
     */
    FrontendProtocol = proto;

    /* Check we can handle the protocol the frontend is using. */

    if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
        PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
        (PG_PROTOCOL_MAJOR(proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
         PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
        ereport(FATAL,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u",
                        PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto),
                        PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST),
                        PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST),
                        PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))));

    /*
     * Now fetch parameters out of startup packet and save them into the Port
     * structure.  All data structures attached to the Port struct must be
     * allocated in TopMemoryContext so that they will remain available in a
     * running backend (even after PostmasterContext is destroyed).  We need
     * not worry about leaking this storage on failure, since we aren't in the
     * postmaster process anymore.
     */
    oldcontext = MemoryContextSwitchTo(TopMemoryContext);

    if (PG_PROTOCOL_MAJOR(proto) >= 3)
    {
        int32       offset = sizeof(ProtocolVersion);

        /*
         * Scan packet body for name/option pairs.  We can assume any string
         * beginning within the packet body is null-terminated, thanks to
         * zeroing extra byte above.
         */
        port->guc_options = NIL;

        while (offset < len)
        {
            char       *nameptr = ((char *) buf) + offset;
            int32       valoffset;
            char       *valptr;

            if (*nameptr == '\0')
                break;          /* found packet terminator */
            valoffset = offset + strlen(nameptr) + 1;
            if (valoffset >= len)
                break;          /* missing value, will complain below */
            valptr = ((char *) buf) + valoffset;

            if (strcmp(nameptr, "database") == 0)
                port->database_name = pstrdup(valptr);
            else if (strcmp(nameptr, "user") == 0)
                port->user_name = pstrdup(valptr);
            else if (strcmp(nameptr, "options") == 0)
                port->cmdline_options = pstrdup(valptr);
            else if (strcmp(nameptr, "replication") == 0)
            {
                if (!parse_bool(valptr, &am_walsender))
                    ereport(FATAL,
                            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                             errmsg("invalid value for boolean option \"replication\"")));
            }
            else
            {
                /* Assume it's a generic GUC option */
                port->guc_options = lappend(port->guc_options,
                                            pstrdup(nameptr));
                port->guc_options = lappend(port->guc_options,
                                            pstrdup(valptr));
            }
            offset = valoffset + strlen(valptr) + 1;
        }

        /*
         * If we didn't find a packet terminator exactly at the end of the
         * given packet length, complain.
         */
        if (offset != len - 1)
            ereport(FATAL,
                    (errcode(ERRCODE_PROTOCOL_VIOLATION),
                     errmsg("invalid startup packet layout: expected terminator as last byte")));
    }
    else
    {
        /*
         * Get the parameters from the old-style, fixed-width-fields startup
         * packet as C strings.  The packet destination was cleared first so a
         * short packet has zeros silently added.  We have to be prepared to
         * truncate the pstrdup result for oversize fields, though.
         */
        StartupPacket *packet = (StartupPacket *) buf;

        port->database_name = pstrdup(packet->database);
        if (strlen(port->database_name) > sizeof(packet->database))
            port->database_name[sizeof(packet->database)] = '\0';
        port->user_name = pstrdup(packet->user);
        if (strlen(port->user_name) > sizeof(packet->user))
            port->user_name[sizeof(packet->user)] = '\0';
        port->cmdline_options = pstrdup(packet->options);
        if (strlen(port->cmdline_options) > sizeof(packet->options))
            port->cmdline_options[sizeof(packet->options)] = '\0';
        port->guc_options = NIL;
    }

    /* Check a user name was given. */
    if (port->user_name == NULL || port->user_name[0] == '\0')
        ereport(FATAL,
                (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
             errmsg("no PostgreSQL user name specified in startup packet")));

    /* The database defaults to the user name. */
    if (port->database_name == NULL || port->database_name[0] == '\0')
        port->database_name = pstrdup(port->user_name);

    if (Db_user_namespace)
    {
        /*
         * If user@, it is a global user, remove '@'. We only want to do this
         * if there is an '@' at the end and no earlier in the user string or
         * they may fake as a local user of another database attaching to this
         * database.
         */
        if (strchr(port->user_name, '@') ==
            port->user_name + strlen(port->user_name) - 1)
            *strchr(port->user_name, '@') = '\0';
        else
        {
            /* Append '@' and dbname */
            char       *db_user;

            db_user = palloc(strlen(port->user_name) +
                             strlen(port->database_name) + 2);
            sprintf(db_user, "%s@%s", port->user_name, port->database_name);
            port->user_name = db_user;
        }
    }

    /*
     * Truncate given database and user names to length of a Postgres name.
     * This avoids lookup failures when overlength names are given.
     */
    if (strlen(port->database_name) >= NAMEDATALEN)
        port->database_name[NAMEDATALEN - 1] = '\0';
    if (strlen(port->user_name) >= NAMEDATALEN)
        port->user_name[NAMEDATALEN - 1] = '\0';

    /* Walsender is not related to a particular database */
    if (am_walsender)
        port->database_name[0] = '\0';

    /*
     * Done putting stuff in TopMemoryContext.
     */
    MemoryContextSwitchTo(oldcontext);

    /*
     * If we're going to reject the connection due to database state, say so
     * now instead of wasting cycles on an authentication exchange. (This also
     * allows a pg_ping utility to be written.)
     */
    switch (port->canAcceptConnections)
    {
        case CAC_STARTUP:
            ereport(FATAL,
                    (errcode(ERRCODE_CANNOT_CONNECT_NOW),
                     errmsg("the database system is starting up")));
            break;
        case CAC_SHUTDOWN:
            ereport(FATAL,
                    (errcode(ERRCODE_CANNOT_CONNECT_NOW),
                     errmsg("the database system is shutting down")));
            break;
        case CAC_RECOVERY:
            ereport(FATAL,
                    (errcode(ERRCODE_CANNOT_CONNECT_NOW),
                     errmsg("the database system is in recovery mode")));
            break;
        case CAC_TOOMANY:
            ereport(FATAL,
                    (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
                     errmsg("sorry, too many clients already")));
            break;
        case CAC_WAITBACKUP:
            /* OK for now, will check in InitPostgres */
            break;
        case CAC_OK:
            break;
    }

    return STATUS_OK;
}

static void RandomSalt ( char *  md5Salt  )  [static]

Definition at line 4777 of file postmaster.c.

References PostmasterRandom().

Referenced by ConnCreate().

{
    long        rand;

    /*
     * We use % 255, sacrificing one possible byte value, so as to ensure that
     * all bits of the random() value participate in the result. While at it,
     * add one to avoid generating any null bytes.
     */
    rand = PostmasterRandom();
    md5Salt[0] = (rand % 255) + 1;
    rand = PostmasterRandom();
    md5Salt[1] = (rand % 255) + 1;
    rand = PostmasterRandom();
    md5Salt[2] = (rand % 255) + 1;
    rand = PostmasterRandom();
    md5Salt[3] = (rand % 255) + 1;
}

static void reaper ( SIGNAL_ARGS   )  [static]

Definition at line 2492 of file postmaster.c.

References _, Assert, AutoVacPID, AutoVacuumingActive(), BgWriterPID, BlockSig, CheckpointerPID, CleanupBackend(), CleanupBackgroundWorker(), DEBUG4, ereport, errmsg(), errmsg_internal(), EXIT_STATUS_0, EXIT_STATUS_1, ExitPostmaster(), FatalError, HandleChildCrash(), HaveCrashedWorker, IsBinaryUpgrade, LOG, LogChildExit(), NoShutdown, PG_SETMASK, pgarch_start(), PgArchPID, pgstat_start(), PgStatPID, PM_RUN, PM_SHUTDOWN, PM_STARTUP, pmState, PostmasterStateMachine(), ReachedNormalRunning, RecoveryError, Shutdown, signal_child(), SignalChildren, SIGQUIT, SIGUSR2, StartAutoVacLauncher(), StartBackgroundWriter, StartCheckpointer, StartOneBackgroundWorker(), StartupPID, StartWalWriter, SysLogger_Start(), SysLoggerPID, UnBlockSig, WalReceiverPID, WalWriterPID, and XLogArchivingActive.

Referenced by PostmasterMain().

{
    int         save_errno = errno;
    int         pid;            /* process id of dead child process */
    int         exitstatus;     /* its exit status */

    PG_SETMASK(&BlockSig);

    ereport(DEBUG4,
            (errmsg_internal("reaping dead processes")));

    while ((pid = waitpid(-1, &exitstatus, WNOHANG)) > 0)
    {
        /*
         * Check if this child was a startup process.
         */
        if (pid == StartupPID)
        {
            StartupPID = 0;

            /*
             * Startup process exited in response to a shutdown request (or it
             * completed normally regardless of the shutdown request).
             */
            if (Shutdown > NoShutdown &&
                (EXIT_STATUS_0(exitstatus) || EXIT_STATUS_1(exitstatus)))
            {
                pmState = PM_WAIT_BACKENDS;
                /* PostmasterStateMachine logic does the rest */
                continue;
            }

            /*
             * Unexpected exit of startup process (including FATAL exit)
             * during PM_STARTUP is treated as catastrophic. There are no
             * other processes running yet, so we can just exit.
             */
            if (pmState == PM_STARTUP && !EXIT_STATUS_0(exitstatus))
            {
                LogChildExit(LOG, _("startup process"),
                             pid, exitstatus);
                ereport(LOG,
                (errmsg("aborting startup due to startup process failure")));
                ExitPostmaster(1);
            }

            /*
             * After PM_STARTUP, any unexpected exit (including FATAL exit) of
             * the startup process is catastrophic, so kill other children,
             * and set RecoveryError so we don't try to reinitialize after
             * they're gone.  Exception: if FatalError is already set, that
             * implies we previously sent the startup process a SIGQUIT, so
             * that's probably the reason it died, and we do want to try to
             * restart in that case.
             */
            if (!EXIT_STATUS_0(exitstatus))
            {
                if (!FatalError)
                    RecoveryError = true;
                HandleChildCrash(pid, exitstatus,
                                 _("startup process"));
                continue;
            }

            /*
             * Startup succeeded, commence normal operations
             */
            FatalError = false;
            ReachedNormalRunning = true;
            pmState = PM_RUN;

            /*
             * Crank up the background tasks, if we didn't do that already
             * when we entered consistent recovery state.  It doesn't matter
             * if this fails, we'll just try again later.
             */
            if (CheckpointerPID == 0)
                CheckpointerPID = StartCheckpointer();
            if (BgWriterPID == 0)
                BgWriterPID = StartBackgroundWriter();
            if (WalWriterPID == 0)
                WalWriterPID = StartWalWriter();

            /*
             * Likewise, start other special children as needed.  In a restart
             * situation, some of them may be alive already.
             */
            if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0)
                AutoVacPID = StartAutoVacLauncher();
            if (XLogArchivingActive() && PgArchPID == 0)
                PgArchPID = pgarch_start();
            if (PgStatPID == 0)
                PgStatPID = pgstat_start();

            /* some workers may be scheduled to start now */
            StartOneBackgroundWorker();

            /* at this point we are really open for business */
            ereport(LOG,
                 (errmsg("database system is ready to accept connections")));

            continue;
        }

        /*
         * Was it the bgwriter?  Normal exit can be ignored; we'll start a new
         * one at the next iteration of the postmaster's main loop, if
         * necessary.  Any other exit condition is treated as a crash.
         */
        if (pid == BgWriterPID)
        {
            BgWriterPID = 0;
            if (!EXIT_STATUS_0(exitstatus))
                HandleChildCrash(pid, exitstatus,
                                 _("background writer process"));
            continue;
        }

        /*
         * Was it the checkpointer?
         */
        if (pid == CheckpointerPID)
        {
            CheckpointerPID = 0;
            if (EXIT_STATUS_0(exitstatus) && pmState == PM_SHUTDOWN)
            {
                /*
                 * OK, we saw normal exit of the checkpointer after it's been
                 * told to shut down.  We expect that it wrote a shutdown
                 * checkpoint.  (If for some reason it didn't, recovery will
                 * occur on next postmaster start.)
                 *
                 * At this point we should have no normal backend children
                 * left (else we'd not be in PM_SHUTDOWN state) but we might
                 * have dead_end children to wait for.
                 *
                 * If we have an archiver subprocess, tell it to do a last
                 * archive cycle and quit. Likewise, if we have walsender
                 * processes, tell them to send any remaining WAL and quit.
                 */
                Assert(Shutdown > NoShutdown);

                /* Waken archiver for the last time */
                if (PgArchPID != 0)
                    signal_child(PgArchPID, SIGUSR2);

                /*
                 * Waken walsenders for the last time. No regular backends
                 * should be around anymore.
                 */
                SignalChildren(SIGUSR2);

                pmState = PM_SHUTDOWN_2;

                /*
                 * We can also shut down the stats collector now; there's
                 * nothing left for it to do.
                 */
                if (PgStatPID != 0)
                    signal_child(PgStatPID, SIGQUIT);
            }
            else
            {
                /*
                 * Any unexpected exit of the checkpointer (including FATAL
                 * exit) is treated as a crash.
                 */
                HandleChildCrash(pid, exitstatus,
                                 _("checkpointer process"));
            }

            continue;
        }

        /*
         * Was it the wal writer?  Normal exit can be ignored; we'll start a
         * new one at the next iteration of the postmaster's main loop, if
         * necessary.  Any other exit condition is treated as a crash.
         */
        if (pid == WalWriterPID)
        {
            WalWriterPID = 0;
            if (!EXIT_STATUS_0(exitstatus))
                HandleChildCrash(pid, exitstatus,
                                 _("WAL writer process"));
            continue;
        }

        /*
         * Was it the wal receiver?  If exit status is zero (normal) or one
         * (FATAL exit), we assume everything is all right just like normal
         * backends.
         */
        if (pid == WalReceiverPID)
        {
            WalReceiverPID = 0;
            if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus))
                HandleChildCrash(pid, exitstatus,
                                 _("WAL receiver process"));
            continue;
        }

        /*
         * Was it the autovacuum launcher?  Normal exit can be ignored; we'll
         * start a new one at the next iteration of the postmaster's main
         * loop, if necessary.  Any other exit condition is treated as a
         * crash.
         */
        if (pid == AutoVacPID)
        {
            AutoVacPID = 0;
            if (!EXIT_STATUS_0(exitstatus))
                HandleChildCrash(pid, exitstatus,
                                 _("autovacuum launcher process"));
            continue;
        }

        /*
         * Was it the archiver?  If so, just try to start a new one; no need
         * to force reset of the rest of the system.  (If fail, we'll try
         * again in future cycles of the main loop.).  Unless we were waiting
         * for it to shut down; don't restart it in that case, and
         * PostmasterStateMachine() will advance to the next shutdown step.
         */
        if (pid == PgArchPID)
        {
            PgArchPID = 0;
            if (!EXIT_STATUS_0(exitstatus))
                LogChildExit(LOG, _("archiver process"),
                             pid, exitstatus);
            if (XLogArchivingActive() && pmState == PM_RUN)
                PgArchPID = pgarch_start();
            continue;
        }

        /*
         * Was it the statistics collector?  If so, just try to start a new
         * one; no need to force reset of the rest of the system.  (If fail,
         * we'll try again in future cycles of the main loop.)
         */
        if (pid == PgStatPID)
        {
            PgStatPID = 0;
            if (!EXIT_STATUS_0(exitstatus))
                LogChildExit(LOG, _("statistics collector process"),
                             pid, exitstatus);
            if (pmState == PM_RUN)
                PgStatPID = pgstat_start();
            continue;
        }

        /* Was it the system logger?  If so, try to start a new one */
        if (pid == SysLoggerPID)
        {
            SysLoggerPID = 0;
            /* for safety's sake, launch new logger *first* */
            SysLoggerPID = SysLogger_Start();
            if (!EXIT_STATUS_0(exitstatus))
                LogChildExit(LOG, _("system logger process"),
                             pid, exitstatus);
            continue;
        }

        /* Was it one of our background workers? */
        if (CleanupBackgroundWorker(pid, exitstatus))
        {
            /* have it be restarted */
            HaveCrashedWorker = true;
            continue;
        }

        /*
         * Else do standard backend child cleanup.
         */
        CleanupBackend(pid, exitstatus);
    }                           /* loop over pending child-death reports */

    /*
     * After cleaning out the SIGCHLD queue, see if we have any state changes
     * or actions to make.
     */
    PostmasterStateMachine();

    /* Done with signal handler */
    PG_SETMASK(&UnBlockSig);

    errno = save_errno;
}

void RegisterBackgroundWorker ( BackgroundWorker worker  ) 

Definition at line 5143 of file postmaster.c.

References autovacuum_max_workers, BackgroundWorker::bgw_flags, BackgroundWorker::bgw_name, BGW_NEVER_RESTART, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_start_time, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, BgWorkerStart_PostmasterStart, ereport, errcode(), errdetail(), errmsg(), IsUnderPostmaster, LOG, malloc, MAX_BACKENDS, MaxConnections, NULL, process_shared_preload_libraries_in_progress, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_lnode, RegisteredBgWorker::rw_pid, RegisteredBgWorker::rw_worker, slist_push_head(), strlcpy(), and USECS_PER_DAY.

Referenced by _PG_init().

{
    RegisteredBgWorker *rw;
    int         namelen = strlen(worker->bgw_name);
    static int  maxworkers;
    static int  numworkers = 0;

#ifdef EXEC_BACKEND

    /*
     * Use 1 here, not 0, to avoid confusing a possible bogus cookie read by
     * atoi() in SubPostmasterMain.
     */
    static int  BackgroundWorkerCookie = 1;
#endif

    /* initialize upper limit on first call */
    if (numworkers == 0)
        maxworkers = MAX_BACKENDS -
            (MaxConnections + autovacuum_max_workers + 1);

    if (!IsUnderPostmaster)
        ereport(LOG,
            (errmsg("registering background worker: %s", worker->bgw_name)));

    if (!process_shared_preload_libraries_in_progress)
    {
        if (!IsUnderPostmaster)
            ereport(LOG,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("background worker \"%s\": must be registered in shared_preload_libraries",
                            worker->bgw_name)));
        return;
    }

    /* sanity check for flags */
    if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
    {
        if (!(worker->bgw_flags & BGWORKER_SHMEM_ACCESS))
        {
            if (!IsUnderPostmaster)
                ereport(LOG,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("background worker \"%s\": must attach to shared memory in order to request a database connection",
                                worker->bgw_name)));
            return;
        }

        if (worker->bgw_start_time == BgWorkerStart_PostmasterStart)
        {
            if (!IsUnderPostmaster)
                ereport(LOG,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("background worker \"%s\": cannot request database access if starting at postmaster start",
                                worker->bgw_name)));
            return;
        }

        /* XXX other checks? */
    }

    if ((worker->bgw_restart_time < 0 &&
         worker->bgw_restart_time != BGW_NEVER_RESTART) ||
        (worker->bgw_restart_time > USECS_PER_DAY / 1000))
    {
        if (!IsUnderPostmaster)
            ereport(LOG,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("background worker \"%s\": invalid restart interval",
                        worker->bgw_name)));
        return;
    }

    /*
     * Enforce maximum number of workers.  Note this is overly restrictive:
     * we could allow more non-shmem-connected workers, because these don't
     * count towards the MAX_BACKENDS limit elsewhere.  This doesn't really
     * matter for practical purposes; several million processes would need to
     * run on a single server.
     */
    if (++numworkers > maxworkers)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
                 errmsg("too many background workers"),
                 errdetail("Up to %d background workers can be registered with the current settings.",
                           maxworkers)));
        return;
    }

    /*
     * Copy the registration data into the registered workers list.
     */
    rw = malloc(sizeof(RegisteredBgWorker) + namelen + 1);
    if (rw == NULL)
    {
        ereport(LOG,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of memory")));
        return;
    }

    rw->rw_worker = *worker;
    rw->rw_worker.bgw_name = ((char *) rw) + sizeof(RegisteredBgWorker);
    strlcpy(rw->rw_worker.bgw_name, worker->bgw_name, namelen + 1);

    rw->rw_backend = NULL;
    rw->rw_pid = 0;
    rw->rw_child_slot = 0;
    rw->rw_crashed_at = 0;
#ifdef EXEC_BACKEND
    rw->rw_cookie = BackgroundWorkerCookie++;
#endif

    slist_push_head(&BackgroundWorkerList, &rw->rw_lnode);
}

static void report_fork_failure_to_client ( Port port,
int  errnum 
) [static]

Definition at line 3723 of file postmaster.c.

References _, EINTR, pg_set_noblock(), send, snprintf(), Port::sock, and strerror().

Referenced by BackendStartup().

{
    char        buffer[1000];
    int         rc;

    /* Format the error message packet (always V2 protocol) */
    snprintf(buffer, sizeof(buffer), "E%s%s\n",
             _("could not fork new process for connection: "),
             strerror(errnum));

    /* Set port to non-blocking.  Don't do send() if this fails */
    if (!pg_set_noblock(port->sock))
        return;

    /* We'll retry after EINTR, but ignore all other failures */
    do
    {
        rc = send(port->sock, buffer, strlen(buffer) + 1, 0);
    } while (rc < 0 && errno == EINTR);
}

static void reset_shared ( int  port  )  [static]

Definition at line 2253 of file postmaster.c.

References CreateSharedMemoryAndSemaphores().

Referenced by PostmasterMain(), and PostmasterStateMachine().

{
    /*
     * Create or re-create shared memory and semaphores.
     *
     * Note: in each "cycle of life" we will normally assign the same IPC keys
     * (if using SysV shmem and/or semas), since the port number is used to
     * determine IPC keys.  This helps ensure that we will clean up dead IPC
     * objects if the postmaster crashes and is restarted.
     */
    CreateSharedMemoryAndSemaphores(false, port);
}

static int ServerLoop ( void   )  [static]

Definition at line 1496 of file postmaster.c.

References AutoVacPID, AutoVacuumingActive(), avlauncher_needs_signal, BackendStartup(), BgWriterPID, BlockSig, CheckpointerPID, ConnCreate(), ConnFree(), DetermineSleepTime(), EINTR, ereport, errcode_for_socket_access(), errmsg(), EWOULDBLOCK, HaveCrashedWorker, i, initMasks(), IsBinaryUpgrade, ListenSocket, LOG, Logging_collector, NULL, PG_SETMASK, pg_usleep(), pgarch_start(), PgArchPID, PGINVALID_SOCKET, pgstat_start(), PgStatPID, PM_HOT_STANDBY, PM_RECOVERY, PM_RUN, PM_WAIT_DEAD_END, pmState, port, SECS_PER_MINUTE, select, SIGUSR2, Port::sock, start_autovac_launcher, StartAutoVacLauncher(), StartBackgroundWriter, StartCheckpointer, StartOneBackgroundWorker(), StartWalWriter, StartWorkerNeeded, StreamClose(), SysLogger_Start(), SysLoggerPID, TouchSocketFiles(), TouchSocketLockFiles(), UnBlockSig, WalWriterPID, and XLogArchivingActive.

Referenced by PostmasterMain().

{
    fd_set      readmask;
    int         nSockets;
    time_t      now,
                last_touch_time;

    last_touch_time = time(NULL);

    nSockets = initMasks(&readmask);

    for (;;)
    {
        fd_set      rmask;
        int         selres;

        /*
         * Wait for a connection request to arrive.
         *
         * If we are in PM_WAIT_DEAD_END state, then we don't want to accept
         * any new connections, so we don't call select() at all; just sleep
         * for a little bit with signals unblocked.
         */
        memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));

        PG_SETMASK(&UnBlockSig);

        if (pmState == PM_WAIT_DEAD_END)
        {
            pg_usleep(100000L); /* 100 msec seems reasonable */
            selres = 0;
        }
        else
        {
            /* must set timeout each time; some OSes change it! */
            struct timeval timeout;

            DetermineSleepTime(&timeout);

            selres = select(nSockets, &rmask, NULL, NULL, &timeout);
        }

        /*
         * Block all signals until we wait again.  (This makes it safe for our
         * signal handlers to do nontrivial work.)
         */
        PG_SETMASK(&BlockSig);

        /* Now check the select() result */
        if (selres < 0)
        {
            if (errno != EINTR && errno != EWOULDBLOCK)
            {
                ereport(LOG,
                        (errcode_for_socket_access(),
                         errmsg("select() failed in postmaster: %m")));
                return STATUS_ERROR;
            }
        }

        /*
         * New connection pending on any of our sockets? If so, fork a child
         * process to deal with it.
         */
        if (selres > 0)
        {
            int         i;

            for (i = 0; i < MAXLISTEN; i++)
            {
                if (ListenSocket[i] == PGINVALID_SOCKET)
                    break;
                if (FD_ISSET(ListenSocket[i], &rmask))
                {
                    Port       *port;

                    port = ConnCreate(ListenSocket[i]);
                    if (port)
                    {
                        BackendStartup(port);

                        /*
                         * We no longer need the open socket or port structure
                         * in this process
                         */
                        StreamClose(port->sock);
                        ConnFree(port);
                    }
                }
            }
        }

        /* If we have lost the log collector, try to start a new one */
        if (SysLoggerPID == 0 && Logging_collector)
            SysLoggerPID = SysLogger_Start();

        /*
         * If no background writer process is running, and we are not in a
         * state that prevents it, start one.  It doesn't matter if this
         * fails, we'll just try again later.  Likewise for the checkpointer.
         */
        if (pmState == PM_RUN || pmState == PM_RECOVERY ||
            pmState == PM_HOT_STANDBY)
        {
            if (CheckpointerPID == 0)
                CheckpointerPID = StartCheckpointer();
            if (BgWriterPID == 0)
                BgWriterPID = StartBackgroundWriter();
        }

        /*
         * Likewise, if we have lost the walwriter process, try to start a new
         * one.  But this is needed only in normal operation (else we cannot
         * be writing any new WAL).
         */
        if (WalWriterPID == 0 && pmState == PM_RUN)
            WalWriterPID = StartWalWriter();

        /*
         * If we have lost the autovacuum launcher, try to start a new one. We
         * don't want autovacuum to run in binary upgrade mode because
         * autovacuum might update relfrozenxid for empty tables before the
         * physical files are put in place.
         */
        if (!IsBinaryUpgrade && AutoVacPID == 0 &&
            (AutoVacuumingActive() || start_autovac_launcher) &&
            pmState == PM_RUN)
        {
            AutoVacPID = StartAutoVacLauncher();
            if (AutoVacPID != 0)
                start_autovac_launcher = false; /* signal processed */
        }

        /* If we have lost the archiver, try to start a new one */
        if (XLogArchivingActive() && PgArchPID == 0 && pmState == PM_RUN)
            PgArchPID = pgarch_start();

        /* If we have lost the stats collector, try to start a new one */
        if (PgStatPID == 0 && pmState == PM_RUN)
            PgStatPID = pgstat_start();

        /* If we need to signal the autovacuum launcher, do so now */
        if (avlauncher_needs_signal)
        {
            avlauncher_needs_signal = false;
            if (AutoVacPID != 0)
                kill(AutoVacPID, SIGUSR2);
        }

        /* Get other worker processes running, if needed */
        if (StartWorkerNeeded || HaveCrashedWorker)
            StartOneBackgroundWorker();

        /*
         * Touch Unix socket and lock files every 58 minutes, to ensure that
         * they are not removed by overzealous /tmp-cleaning tasks.  We assume
         * no one runs cleaners with cutoff times of less than an hour ...
         */
        now = time(NULL);
        if (now - last_touch_time >= 58 * SECS_PER_MINUTE)
        {
            TouchSocketFiles();
            TouchSocketLockFiles();
            last_touch_time = now;
        }
    }
}

static void SIGHUP_handler ( SIGNAL_ARGS   )  [static]

Definition at line 2271 of file postmaster.c.

References AutoVacPID, BgWriterPID, BlockSig, CheckpointerPID, ereport, errmsg(), load_hba(), load_ident(), LOG, PG_SETMASK, PgArchPID, PGC_SIGHUP, PgStatPID, ProcessConfigFile(), Shutdown, SIGHUP, signal_child(), SignalChildren, SignalUnconnectedWorkers(), SmartShutdown, StartupPID, SysLoggerPID, UnBlockSig, WalReceiverPID, WalWriterPID, and WARNING.

Referenced by PostmasterMain().

{
    int         save_errno = errno;

    PG_SETMASK(&BlockSig);

    if (Shutdown <= SmartShutdown)
    {
        ereport(LOG,
                (errmsg("received SIGHUP, reloading configuration files")));
        ProcessConfigFile(PGC_SIGHUP);
        SignalChildren(SIGHUP);
        SignalUnconnectedWorkers(SIGHUP);
        if (StartupPID != 0)
            signal_child(StartupPID, SIGHUP);
        if (BgWriterPID != 0)
            signal_child(BgWriterPID, SIGHUP);
        if (CheckpointerPID != 0)
            signal_child(CheckpointerPID, SIGHUP);
        if (WalWriterPID != 0)
            signal_child(WalWriterPID, SIGHUP);
        if (WalReceiverPID != 0)
            signal_child(WalReceiverPID, SIGHUP);
        if (AutoVacPID != 0)
            signal_child(AutoVacPID, SIGHUP);
        if (PgArchPID != 0)
            signal_child(PgArchPID, SIGHUP);
        if (SysLoggerPID != 0)
            signal_child(SysLoggerPID, SIGHUP);
        if (PgStatPID != 0)
            signal_child(PgStatPID, SIGHUP);

        /* Reload authentication config files too */
        if (!load_hba())
            ereport(WARNING,
                    (errmsg("pg_hba.conf not reloaded")));

        if (!load_ident())
            ereport(WARNING,
                    (errmsg("pg_ident.conf not reloaded")));

#ifdef EXEC_BACKEND
        /* Update the starting-point file for future children */
        write_nondefault_variables(PGC_SIGHUP);
#endif
    }

    PG_SETMASK(&UnBlockSig);

    errno = save_errno;
}

static void signal_child ( pid_t  pid,
int  signal 
) [static]

Definition at line 3501 of file postmaster.c.

References DEBUG3, elog, SIGQUIT, and SIGSTOP.

Referenced by HandleChildCrash(), pmdie(), PostmasterStateMachine(), processCancelRequest(), reaper(), SIGHUP_handler(), SignalSomeChildren(), SignalUnconnectedWorkers(), and sigusr1_handler().

{
    if (kill(pid, signal) < 0)
        elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) pid, signal);
#ifdef HAVE_SETSID
    switch (signal)
    {
        case SIGINT:
        case SIGTERM:
        case SIGQUIT:
        case SIGSTOP:
            if (kill(-pid, signal) < 0)
                elog(DEBUG3, "kill(%ld,%d) failed: %m", (long) (-pid), signal);
            break;
        default:
            break;
    }
#endif
}

static bool SignalSomeChildren ( int  signal,
int  targets 
) [static]

Definition at line 3559 of file postmaster.c.

References BACKEND_TYPE_ALL, BACKEND_TYPE_NORMAL, bkend::bkend_type, bkend::child_slot, dlist_iter::cur, bkend::dead_end, DEBUG4, dlist_container, dlist_foreach, ereport, errmsg_internal(), IsPostmasterChildWalSender(), bkend::pid, signal_child(), and signaled.

Referenced by pmdie().

{
    dlist_iter  iter;
    bool        signaled = false;

    dlist_foreach(iter, &BackendList)
    {
        Backend    *bp = dlist_container(Backend, elem, iter.cur);

        if (bp->dead_end)
            continue;

        /*
         * Since target == BACKEND_TYPE_ALL is the most common case, we test
         * it first and avoid touching shared memory for every child.
         */
        if (target != BACKEND_TYPE_ALL)
        {
            /*
             * Assign bkend_type for any recently announced WAL Sender
             * processes.
             */
            if (bp->bkend_type == BACKEND_TYPE_NORMAL &&
                IsPostmasterChildWalSender(bp->child_slot))
                bp->bkend_type = BACKEND_TYPE_WALSND;

            if (!(target & bp->bkend_type))
                continue;
        }

        ereport(DEBUG4,
                (errmsg_internal("sending signal %d to process %d",
                                 signal, (int) bp->pid)));
        signal_child(bp->pid, signal);
        signaled = true;
    }
    return signaled;
}

static bool SignalUnconnectedWorkers ( int  signal  )  [static]

Definition at line 3528 of file postmaster.c.

References slist_iter::cur, DEBUG4, ereport, errmsg_internal(), NULL, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_pid, signal_child(), signaled, slist_container, and slist_foreach.

Referenced by pmdie(), and SIGHUP_handler().

{
    slist_iter  iter;
    bool        signaled = false;

    slist_foreach(iter, &BackgroundWorkerList)
    {
        RegisteredBgWorker *rw;

        rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);

        if (rw->rw_pid == 0)
            continue;
        /* ignore connected workers */
        if (rw->rw_backend != NULL)
            continue;

        ereport(DEBUG4,
                (errmsg_internal("sending signal %d to process %d",
                                 signal, (int) rw->rw_pid)));
        signal_child(rw->rw_pid, signal);
        signaled = true;
    }
    return signaled;
}

static void sigusr1_handler ( SIGNAL_ARGS   )  [static]

Definition at line 4617 of file postmaster.c.

References Assert, BgWriterPID, BlockSig, CheckpointerPID, CheckPostmasterSignal(), CheckPromoteSignal(), ereport, errmsg(), FatalError, LOG, NoShutdown, PG_SETMASK, PgArchPID, pgstat_start(), PgStatPID, PM_HOT_STANDBY, PM_RECOVERY, PM_STARTUP, PM_WAIT_BACKENDS, PM_WAIT_BACKUP, PM_WAIT_READONLY, PMSIGNAL_ADVANCE_STATE_MACHINE, PMSIGNAL_BEGIN_HOT_STANDBY, PMSIGNAL_RECOVERY_STARTED, PMSIGNAL_ROTATE_LOGFILE, PMSIGNAL_START_AUTOVAC_LAUNCHER, PMSIGNAL_START_AUTOVAC_WORKER, PMSIGNAL_START_WALRECEIVER, PMSIGNAL_WAKEN_ARCHIVER, pmState, PostmasterStateMachine(), Shutdown, signal_child(), SIGUSR1, SIGUSR2, start_autovac_launcher, StartAutovacuumWorker(), StartBackgroundWriter, StartCheckpointer, StartOneBackgroundWorker(), StartupPID, StartWalReceiver, SysLoggerPID, UnBlockSig, and WalReceiverPID.

Referenced by PostmasterMain().

{
    int         save_errno = errno;

    PG_SETMASK(&BlockSig);

    /*
     * RECOVERY_STARTED and BEGIN_HOT_STANDBY signals are ignored in
     * unexpected states. If the startup process quickly starts up, completes
     * recovery, exits, we might process the death of the startup process
     * first. We don't want to go back to recovery in that case.
     */
    if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_STARTED) &&
        pmState == PM_STARTUP && Shutdown == NoShutdown)
    {
        /* WAL redo has started. We're out of reinitialization. */
        FatalError = false;

        /*
         * Crank up the background tasks.  It doesn't matter if this fails,
         * we'll just try again later.
         */
        Assert(CheckpointerPID == 0);
        CheckpointerPID = StartCheckpointer();
        Assert(BgWriterPID == 0);
        BgWriterPID = StartBackgroundWriter();

        pmState = PM_RECOVERY;
    }
    if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
        pmState == PM_RECOVERY && Shutdown == NoShutdown)
    {
        /*
         * Likewise, start other special children as needed.
         */
        Assert(PgStatPID == 0);
        PgStatPID = pgstat_start();

        ereport(LOG,
        (errmsg("database system is ready to accept read only connections")));

        pmState = PM_HOT_STANDBY;

        /* Some workers may be scheduled to start now */
        StartOneBackgroundWorker();
    }

    if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) &&
        PgArchPID != 0)
    {
        /*
         * Send SIGUSR1 to archiver process, to wake it up and begin archiving
         * next transaction log file.
         */
        signal_child(PgArchPID, SIGUSR1);
    }

    if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) &&
        SysLoggerPID != 0)
    {
        /* Tell syslogger to rotate logfile */
        signal_child(SysLoggerPID, SIGUSR1);
    }

    if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER) &&
        Shutdown == NoShutdown)
    {
        /*
         * Start one iteration of the autovacuum daemon, even if autovacuuming
         * is nominally not enabled.  This is so we can have an active defense
         * against transaction ID wraparound.  We set a flag for the main loop
         * to do it rather than trying to do it here --- this is because the
         * autovac process itself may send the signal, and we want to handle
         * that by launching another iteration as soon as the current one
         * completes.
         */
        start_autovac_launcher = true;
    }

    if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER) &&
        Shutdown == NoShutdown)
    {
        /* The autovacuum launcher wants us to start a worker process. */
        StartAutovacuumWorker();
    }

    if (CheckPostmasterSignal(PMSIGNAL_START_WALRECEIVER) &&
        WalReceiverPID == 0 &&
        (pmState == PM_STARTUP || pmState == PM_RECOVERY ||
         pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY) &&
        Shutdown == NoShutdown)
    {
        /* Startup Process wants us to start the walreceiver process. */
        WalReceiverPID = StartWalReceiver();
    }

    if (CheckPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE) &&
        (pmState == PM_WAIT_BACKUP || pmState == PM_WAIT_BACKENDS))
    {
        /* Advance postmaster's state machine */
        PostmasterStateMachine();
    }

    if (CheckPromoteSignal() && StartupPID != 0 &&
        (pmState == PM_STARTUP || pmState == PM_RECOVERY ||
         pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY))
    {
        /* Tell startup process to finish recovery */
        signal_child(StartupPID, SIGUSR2);
    }

    PG_SETMASK(&UnBlockSig);

    errno = save_errno;
}

static void start_bgworker ( RegisteredBgWorker rw  )  [static]

Definition at line 5573 of file postmaster.c.

References BackgroundWorker::bgw_name, ClosePostmasterPorts(), do_start_bgworker(), ereport, errmsg(), fork_process(), LOG, on_exit_reset(), bkend::pid, RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_pid, and RegisteredBgWorker::rw_worker.

Referenced by StartOneBackgroundWorker().

{
    pid_t       worker_pid;

    ereport(LOG,
            (errmsg("starting background worker process \"%s\"",
                    rw->rw_worker.bgw_name)));

#ifdef EXEC_BACKEND
    switch ((worker_pid = bgworker_forkexec(rw->rw_cookie)))
#else
    switch ((worker_pid = fork_process()))
#endif
    {
        case -1:
            ereport(LOG,
                    (errmsg("could not fork worker process: %m")));
            return;

#ifndef EXEC_BACKEND
        case 0:
            /* in postmaster child ... */
            /* Close the postmaster's sockets */
            ClosePostmasterPorts(false);

            /* Lose the postmaster's on-exit routines */
            on_exit_reset();

            /* Do NOT release postmaster's working memory context */

            MyBgworkerEntry = &rw->rw_worker;
            do_start_bgworker();
            break;
#endif
        default:
            rw->rw_pid = worker_pid;
            if (rw->rw_backend)
                rw->rw_backend->pid = rw->rw_pid;
    }
}

static void StartAutovacuumWorker ( void   )  [static]

Definition at line 5016 of file postmaster.c.

References AssignPostmasterChildSlot(), AutoVacPID, AutoVacWorkerFailed(), avlauncher_needs_signal, bkend::bkend_type, CAC_OK, canAcceptConnections(), bkend::cancel_key, bkend::child_slot, bkend::dead_end, dlist_push_head(), bkend::elem, ereport, errcode(), errmsg(), free, LOG, malloc, MyCancelKey, MyPMChildSlot, bkend::pid, PostmasterRandom(), ReleasePostmasterChildSlot(), and StartAutoVacWorker().

Referenced by sigusr1_handler().

{
    Backend    *bn;

    /*
     * If not in condition to run a process, don't try, but handle it like a
     * fork failure.  This does not normally happen, since the signal is only
     * supposed to be sent by autovacuum launcher when it's OK to do it, but
     * we have to check to avoid race-condition problems during DB state
     * changes.
     */
    if (canAcceptConnections() == CAC_OK)
    {
        bn = (Backend *) malloc(sizeof(Backend));
        if (bn)
        {
            /*
             * Compute the cancel key that will be assigned to this session.
             * We probably don't need cancel keys for autovac workers, but
             * we'd better have something random in the field to prevent
             * unfriendly people from sending cancels to them.
             */
            MyCancelKey = PostmasterRandom();
            bn->cancel_key = MyCancelKey;

            /* Autovac workers are not dead_end and need a child slot */
            bn->dead_end = false;
            bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();

            bn->pid = StartAutoVacWorker();
            if (bn->pid > 0)
            {
                bn->bkend_type = BACKEND_TYPE_AUTOVAC;
                dlist_push_head(&BackendList, &bn->elem);
#ifdef EXEC_BACKEND
                ShmemBackendArrayAdd(bn);
#endif
                /* all OK */
                return;
            }

            /*
             * fork failed, fall through to report -- actual error message was
             * logged by StartAutoVacWorker
             */
            (void) ReleasePostmasterChildSlot(bn->child_slot);
            free(bn);
        }
        else
            ereport(LOG,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));
    }

    /*
     * Report the failure to the launcher, if it's running.  (If it's not, we
     * might not even be connected to shared memory, so don't try to call
     * AutoVacWorkerFailed.)  Note that we also need to signal it so that it
     * responds to the condition, but we don't do that here, instead waiting
     * for ServerLoop to do it.  This way we avoid a ping-pong signalling in
     * quick succession between the autovac launcher and postmaster in case
     * things get ugly.
     */
    if (AutoVacPID != 0)
    {
        AutoVacWorkerFailed();
        avlauncher_needs_signal = true;
    }
}

static pid_t StartChildProcess ( AuxProcType  type  )  [static]

Definition at line 4909 of file postmaster.c.

References Assert, AuxiliaryProcessMain(), BgWriterProcess, CheckpointerProcess, ClosePostmasterPorts(), ereport, errmsg(), ExitPostmaster(), fork_process(), IsUnderPostmaster, lengthof, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), on_exit_reset(), PostmasterContext, snprintf(), StartupProcess, TopMemoryContext, WalReceiverProcess, and WalWriterProcess.

{
    pid_t       pid;
    char       *av[10];
    int         ac = 0;
    char        typebuf[32];

    /*
     * Set up command-line arguments for subprocess
     */
    av[ac++] = "postgres";

#ifdef EXEC_BACKEND
    av[ac++] = "--forkboot";
    av[ac++] = NULL;            /* filled in by postmaster_forkexec */
#endif

    snprintf(typebuf, sizeof(typebuf), "-x%d", type);
    av[ac++] = typebuf;

    av[ac] = NULL;
    Assert(ac < lengthof(av));

#ifdef EXEC_BACKEND
    pid = postmaster_forkexec(ac, av);
#else                           /* !EXEC_BACKEND */
    pid = fork_process();

    if (pid == 0)               /* child */
    {
        IsUnderPostmaster = true;       /* we are a postmaster subprocess now */

        /* Close the postmaster's sockets */
        ClosePostmasterPorts(false);

        /* Lose the postmaster's on-exit routines and port connections */
        on_exit_reset();

        /* Release postmaster's working memory context */
        MemoryContextSwitchTo(TopMemoryContext);
        MemoryContextDelete(PostmasterContext);
        PostmasterContext = NULL;

        AuxiliaryProcessMain(ac, av);
        ExitPostmaster(0);
    }
#endif   /* EXEC_BACKEND */

    if (pid < 0)
    {
        /* in parent, fork failed */
        int         save_errno = errno;

        errno = save_errno;
        switch (type)
        {
            case StartupProcess:
                ereport(LOG,
                        (errmsg("could not fork startup process: %m")));
                break;
            case BgWriterProcess:
                ereport(LOG,
                   (errmsg("could not fork background writer process: %m")));
                break;
            case CheckpointerProcess:
                ereport(LOG,
                        (errmsg("could not fork checkpointer process: %m")));
                break;
            case WalWriterProcess:
                ereport(LOG,
                        (errmsg("could not fork WAL writer process: %m")));
                break;
            case WalReceiverProcess:
                ereport(LOG,
                        (errmsg("could not fork WAL receiver process: %m")));
                break;
            default:
                ereport(LOG,
                        (errmsg("could not fork process: %m")));
                break;
        }

        /*
         * fork failure is fatal during startup, but there's no need to choke
         * immediately if starting other child types fails.
         */
        if (type == StartupProcess)
            ExitPostmaster(1);
        return 0;
    }

    /*
     * in parent, successful fork
     */
    return pid;
}

static void StartOneBackgroundWorker ( void   )  [static]

Definition at line 5708 of file postmaster.c.

References assign_backendlist_entry(), AssignPostmasterChildSlot(), BackgroundWorker::bgw_flags, BGW_NEVER_RESTART, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_start_time, BGWORKER_BACKEND_DATABASE_CONNECTION, bgworker_should_start_now(), slist_iter::cur, dlist_push_head(), bkend::elem, FatalError, GetCurrentTimestamp(), HaveCrashedWorker, MyPMChildSlot, now(), RegisteredBgWorker::rw_backend, RegisteredBgWorker::rw_child_slot, RegisteredBgWorker::rw_crashed_at, RegisteredBgWorker::rw_pid, RegisteredBgWorker::rw_worker, slist_container, slist_foreach, start_bgworker(), StartWorkerNeeded, and TimestampDifferenceExceeds().

Referenced by PostmasterMain(), reaper(), ServerLoop(), and sigusr1_handler().

{
    slist_iter  iter;
    TimestampTz now = 0;

    if (FatalError)
    {
        StartWorkerNeeded = false;
        HaveCrashedWorker = false;
        return;                 /* not yet */
    }

    HaveCrashedWorker = false;

    slist_foreach(iter, &BackgroundWorkerList)
    {
        RegisteredBgWorker *rw;

        rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);

        /* already running? */
        if (rw->rw_pid != 0)
            continue;

        /*
         * If this worker has crashed previously, maybe it needs to be
         * restarted (unless on registration it specified it doesn't want to
         * be restarted at all).  Check how long ago did a crash last happen.
         * If the last crash is too recent, don't start it right away; let it
         * be restarted once enough time has passed.
         */
        if (rw->rw_crashed_at != 0)
        {
            if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART)
                continue;

            if (now == 0)
                now = GetCurrentTimestamp();

            if (!TimestampDifferenceExceeds(rw->rw_crashed_at, now,
                                      rw->rw_worker.bgw_restart_time * 1000))
            {
                HaveCrashedWorker = true;
                continue;
            }
        }

        if (bgworker_should_start_now(rw->rw_worker.bgw_start_time))
        {
            /* reset crash time before calling assign_backendlist_entry */
            rw->rw_crashed_at = 0;

            /*
             * If necessary, allocate and assign the Backend element.  Note we
             * must do this before forking, so that we can handle out of
             * memory properly.
             *
             * If not connected, we don't need a Backend element, but we still
             * need a PMChildSlot.
             */
            if (rw->rw_worker.bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
            {
                if (!assign_backendlist_entry(rw))
                    return;
            }
            else
                rw->rw_child_slot = MyPMChildSlot = AssignPostmasterChildSlot();

            start_bgworker(rw); /* sets rw->rw_pid */

            if (rw->rw_backend)
            {
                dlist_push_head(&BackendList, &rw->rw_backend->elem);
#ifdef EXEC_BACKEND
                ShmemBackendArrayAdd(rw->rw_backend);
#endif
            }

            /*
             * Have ServerLoop call us again.  Note that there might not
             * actually *be* another runnable worker, but we don't care all
             * that much; we will find out the next time we run.
             */
            StartWorkerNeeded = true;
            return;
        }
    }

    /* no runnable worker found */
    StartWorkerNeeded = false;
}

static void startup_die ( SIGNAL_ARGS   )  [static]

Definition at line 4743 of file postmaster.c.

References proc_exit().

Referenced by BackendInitialize().

{
    proc_exit(1);
}

static void StartupPacketTimeoutHandler ( void   )  [static]

Definition at line 4767 of file postmaster.c.

References proc_exit().

Referenced by BackendInitialize().

{
    proc_exit(1);
}

static void unlink_external_pid_file ( int  status,
Datum  arg 
) [static]

Definition at line 1259 of file postmaster.c.

References external_pid_file, and unlink().

Referenced by PostmasterMain().


Variable Documentation

Definition at line 249 of file postmaster.c.

Referenced by BackendInitialize(), and PerformAuthentication().

pid_t AutoVacPID = 0 [static]
volatile bool avlauncher_needs_signal = false [static]

Definition at line 357 of file postmaster.c.

Referenced by ServerLoop(), and StartAutovacuumWorker().

dlist_head BackendList = DLIST_STATIC_INIT(BackendList) [static]

Definition at line 175 of file postmaster.c.

slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList) [static]

Definition at line 202 of file postmaster.c.

pid_t BgWriterPID = 0 [static]
char* bonjour_name

Definition at line 256 of file postmaster.c.

Referenced by PostmasterMain().

pid_t CheckpointerPID = 0 [static]

Definition at line 253 of file postmaster.c.

Referenced by ClientAuthentication(), parse_hba_line(), and ProcessStartupPacket().

Definition at line 255 of file postmaster.c.

Referenced by PostmasterMain().

bool EnableSSL = false

Definition at line 246 of file postmaster.c.

Referenced by parse_hba_line(), PostmasterMain(), and ProcessStartupPacket().

char ExtraOptions[MAXPGPATH] [static]

Definition at line 233 of file postmaster.c.

Referenced by BackendRun(), and PostmasterMain().

bool FatalError = false [static]
volatile bool HaveCrashedWorker = false [static]

Definition at line 361 of file postmaster.c.

Referenced by DetermineSleepTime(), reaper(), ServerLoop(), and StartOneBackgroundWorker().

Definition at line 213 of file postmaster.c.

Referenced by PostmasterMain().

pgsocket ListenSocket[MAXLISTEN] [static]

Definition at line 228 of file postmaster.c.

Referenced by ClosePostmasterPorts(), initMasks(), PostmasterMain(), and ServerLoop().

Definition at line 252 of file postmaster.c.

Referenced by BackendInitialize(), and PerformAuthentication().

Definition at line 251 of file postmaster.c.

Referenced by BackendInitialize().

Definition at line 204 of file postmaster.c.

Referenced by worker_spi_main().

char* optarg

Definition at line 51 of file getopt.c.

int opterr

Definition at line 48 of file getopt.c.

int optind

Definition at line 49 of file getopt.c.

char* output_config_variable = NULL

Definition at line 259 of file postmaster.c.

Referenced by PostmasterMain().

pid_t PgArchPID = 0 [static]
pid_t PgStatPID = 0 [static]
PMState pmState = PM_INIT [static]
int postmaster_alive_fds[2] = {-1, -1}

Definition at line 547 of file postmaster.c.

Referenced by PostmasterIsAlive(), and WaitLatchOrSocket().

Definition at line 209 of file postmaster.c.

Referenced by CreateLockFile(), PostmasterMain(), and PostmasterStateMachine().

int PreAuthDelay = 0

Definition at line 248 of file postmaster.c.

Referenced by BackendInitialize().

unsigned int random_seed = 0 [static]

Definition at line 368 of file postmaster.c.

Referenced by BackendRun(), and PostmasterRandom().

struct timeval random_start_time [static]

Definition at line 369 of file postmaster.c.

Referenced by BackendRun(), PostmasterMain(), and PostmasterRandom().

bool ReachedNormalRunning = false [static]

Definition at line 346 of file postmaster.c.

Referenced by PostmasterStateMachine(), and reaper().

bool RecoveryError = false [static]

Definition at line 280 of file postmaster.c.

Referenced by PostmasterStateMachine(), and reaper().

Definition at line 351 of file postmaster.c.

Referenced by SysLogger_Start(), and SysLoggerMain().

bool Reinit = true [static]

Definition at line 242 of file postmaster.c.

Referenced by PostmasterMain().

Definition at line 224 of file postmaster.c.

Referenced by InitPostgres(), and PostmasterMain().

Definition at line 257 of file postmaster.c.

Referenced by PostmasterStateMachine().

int SendStop = false [static]

Definition at line 243 of file postmaster.c.

Referenced by HandleChildCrash(), and PostmasterMain().

int Shutdown = NoShutdown [static]
volatile sig_atomic_t start_autovac_launcher = false [static]

Definition at line 354 of file postmaster.c.

Referenced by ServerLoop(), and sigusr1_handler().

pid_t StartupPID = 0 [static]
volatile bool StartWorkerNeeded = true [static]

Definition at line 360 of file postmaster.c.

Referenced by DetermineSleepTime(), ServerLoop(), and StartOneBackgroundWorker().

pid_t SysLoggerPID = 0 [static]

Definition at line 270 of file postmaster.c.

Referenced by PostmasterMain(), reaper(), ServerLoop(), SIGHUP_handler(), and sigusr1_handler().

Definition at line 211 of file postmaster.c.

Referenced by PostmasterMain().

pid_t WalReceiverPID = 0 [static]
pid_t WalWriterPID = 0 [static]