Open-Source Wikis

/

PostgreSQL

/

Systems

/

Postmaster and process model

postgres/postgres

Postmaster and process model

PostgreSQL is a process-per-connection server. A single supervisor — the postmaster — listens on a port and forks a child for every new connection plus a fixed set of helper processes that share the buffer pool. This page covers the supervisor, the children, and the IPC patterns that hold them together.

Source layout

src/backend/postmaster/
├── auxprocess.c          # generic "auxiliary backend" startup
├── autovacuum.c          # autovacuum launcher + workers
├── bgworker.c            # custom background-worker support
├── bgwriter.c            # background writer
├── checkpointer.c        # checkpointer
├── interrupt.c           # signal handling primitives
├── pgarch.c              # WAL archiver
├── postmaster.c          # the main file (~4000 lines)
├── startup.c             # startup process (recovery driver)
├── syslogger.c           # log file rotator
├── walsummarizer.c       # WAL summary file generator (incremental backup)
└── walwriter.c           # WAL writer

Plus src/backend/main/main.c, the int main entry point that all incarnations of postgres share.

Process taxonomy

Every PostgreSQL process is one of:

Role Source One per Lifetime
Postmaster postmaster.c cluster cluster
Backend tcop/postgres.c (started via BackendInitialize) client connection connection
Startup process startup.c cluster until recovery completes
Checkpointer checkpointer.c cluster cluster
Background writer bgwriter.c cluster cluster
WAL writer walwriter.c cluster cluster
Archiver pgarch.c cluster cluster (when archive_mode=on)
Autovacuum launcher autovacuum.c cluster cluster (when enabled)
Autovacuum worker autovacuum.c active vacuum per worker
WAL sender replication/walsender.c replication client per client
WAL receiver replication/walreceiver.c per standby continuous
Logical rep launcher replication/logical/launcher.c cluster cluster
Logical apply worker replication/logical/worker.c per active subscription per subscription
Parallel worker per query as needed per parallel query
Bgworker (custom) bgworker.c per registration per registration
Syslogger syslogger.c cluster cluster (when logging_collector=on)
WAL summarizer walsummarizer.c cluster cluster (when enabled)

All children share shared memory with the postmaster (and each other). All are forked from the postmaster — never from each other.

Postmaster startup

PostmasterMain (in postmaster.c) is the entry point after main() decides we're starting as a postmaster. The sequence:

  1. Parse command line and read postgresql.conf (and pg_hba.conf, pg_ident.conf).
  2. Validate environment (pg_control exists, data directory permissions, etc.).
  3. Create shared memory and semaphore arrays; set up locks; initialize the proc array and shared catalogs.
  4. Register signal handlers.
  5. If recovery is needed (or recovery.signal exists), start the startup process and wait for it to reach a consistent state.
  6. Once consistent, start the auxiliary processes (checkpointer, bgwriter, walwriter, autovacuum launcher, archiver, syslogger, ...).
  7. Open the listen sockets.
  8. Enter the main loop.

The main loop is a select() (now WaitEventSetWait) over the listen sockets and the postmaster's signal pipe. It accepts connections and forks backends for each, restarts auxiliary processes that died, and handles SIGTERM/SIGINT/SIGHUP.

Connection acceptance

sequenceDiagram
    participant Client
    participant Postmaster
    participant Backend

    Client->>Postmaster: TCP SYN, SSL/GSS option, StartupPacket
    Postmaster->>Postmaster: accept(); read StartupPacket
    Postmaster->>Backend: fork() into BackendStartup
    Postmaster-->>Postmaster: continue listening
    Backend->>Backend: BackendInitialize (read full startup packet)
    Backend->>Backend: ProcessStartupPacket
    Backend->>Client: AuthenticationXxxx (challenge/response)
    Client->>Backend: PasswordMessage / SASL response
    Backend->>Backend: ClientAuthentication
    Backend->>Client: AuthenticationOK + parameter status + ReadyForQuery
    Backend->>Backend: PostgresMain (main loop)

The fork is decided in BackendStartup in postmaster.c. The newly forked child inherits all of the postmaster's file descriptors, the shared-memory mapping, and the semaphore handles — sharing happens at fork time. The child re-attaches a PGPROC slot and announces itself in the proc array.

On Windows there is no fork; the postmaster CreateProcesses a fresh postgres.exe and serializes its startup state into a backend-init parameter file (backend_save_* / backend_read_*).

Backend main loop

A backend's life after authentication:

for (;;)
{
    /* Read a frontend protocol message */
    int qtype = ReadCommand(&input_message);
    switch (qtype)
    {
        case 'Q':  /* Simple query */
            exec_simple_query(...);
            break;
        case 'P':  /* Parse */
            exec_parse_message(...);
            break;
        case 'B':  /* Bind */ /* etc */
            ...
        case 'X':  /* Terminate */
            proc_exit(0);
        ...
    }
    /* Send ReadyForQuery and loop */
}

Source: src/backend/tcop/postgres.c::PostgresMain. This is the front door from the wire protocol to parser → planner → executor.

When the protocol message indicates idle, the backend WaitLatchOrSockets on its socket. Stress tests of an idle cluster spend most of their time inside this wait.

Signal handling

PostgreSQL uses traditional Unix signals for IPC:

Signal Meaning
SIGTERM Smart shutdown (postmaster) / cancel + exit (backend).
SIGQUIT Immediate shutdown / fatal exit.
SIGINT Cancel current statement.
SIGUSR1 Application-defined wake/notify. Many subsystems use it.
SIGUSR2 More application-defined wake.
SIGHUP Reload config.
SIGCHLD Postmaster: child exited; restart logic.
SIGALRM Timer fired; statement timeout, deadlock detector, etc.

Signal handlers do not run any meaningful work; they set a flag (InterruptPending, ConfigReloadPending, etc.) and SetLatch the process. The flag is processed at the next CHECK_FOR_INTERRUPTS() call, which is sprinkled through the executor and other long-running code paths. Source: src/backend/storage/ipc/procsignal.c, src/backend/storage/ipc/latch.c.

This deferred-interrupt model is what lets pg_cancel_backend() cancel a long-running query: send SIGINT, the backend's interrupt handler sets QueryCancelPending = true, the next CHECK_FOR_INTERRUPTS() raises an ERROR via longjmp.

Crash handling

When a backend dies of a fatal signal, the postmaster's SIGCHLD handler notices and:

  1. Logs the exit status.
  2. Marks the cluster as "needs reset."
  3. Sends SIGQUIT to every other backend (their data could be poisoned because the dead backend may have held a critical lock).
  4. Waits for them all to exit.
  5. Reinitializes shared memory.
  6. Starts the startup process to perform crash recovery from WAL.
  7. Resumes the main loop.

This is the crash recovery path. From the user's perspective, the entire cluster restarts in a few seconds; the data is intact because of WAL, but in-flight transactions are aborted.

Auxiliary processes

Each auxiliary has the same skeleton: a Main function that initializes its private state, attaches to shared memory, and runs a loop. They are forked off postmaster.c::StartChildProcess (or a friend) after the postmaster decides they are needed.

  • Startup process (startup.c) — runs StartupXLOG, replays WAL, and signals "ready" via shared memory. After consistency is reached, it can keep running in standby mode (continuously applying WAL); on the primary it exits.
  • Checkpointer (checkpointer.c) — periodically writes a checkpoint, schedules dirty-buffer writes.
  • Background writer (bgwriter.c) — proactively flushes some dirty buffers so that backends rarely have to.
  • WAL writer (walwriter.c) — flushes WAL buffers when no transaction has done so recently.
  • Autovacuum launcher (autovacuum.c) — scans pg_stat_all_tables, dispatches vacuum/analyze workers as needed.
  • Archiver (pgarch.c) — copies completed WAL segments to long-term storage via archive_command / archive_library.
  • Syslogger (syslogger.c) — captures stderr from all children and rotates log files.
  • WAL summarizer (walsummarizer.c) — generates summary files used by pg_basebackup --incremental.

Background workers

bgworker.c provides a generic mechanism for anyone (core code or extensions) to register a process with the postmaster. The registration includes:

  • A name and library/function to run.
  • Restart behavior (crash strategy: never, always, after N seconds).
  • Whether it needs a database connection.

Used by:

  • Autovacuum workers (one per active vacuum).
  • Logical replication apply workers.
  • Parallel-query workers.
  • pg_prewarm warmup worker, pg_partman, and other extensions.

RegisterBackgroundWorker (called from a shared library loaded via shared_preload_libraries) registers a static bgworker before the postmaster forks it. RegisterDynamicBackgroundWorker (called from a backend) requests a dynamic worker.

Per-process initialization order

When a child starts, it follows a careful sequence to attach to shared resources. Roughly:

  1. MemoryContextInit — set up TopMemoryContext.
  2. BaseInit — basic backend state.
  3. InitPostgres — attach to shared memory, the proc array, the database. Acquires the database-connection lock and runs catalog cache warmups.
  4. Subsystem-specific init (e.g., autovacuum sets up scheduling tables).
  5. Enter main loop.

Source: src/backend/utils/init/, postmaster.c::BackendInitialize. The order matters: trying to read a catalog before InitPostgres will crash because the relcache isn't bound to a database.

Latches and condition variables

For most "wake me when X happens" patterns, processes use Latch (src/backend/storage/ipc/latch.c) and ConditionVariable (src/backend/storage/lmgr/condition_variable.c). Latches are 1-bit; CVs are higher-level (sleep on a list, signal one or all). Used pervasively for replication wait, autovacuum signaling, parallel coordination, lock waits.

Entry points for modification

  • New auxiliary process: model it on an existing one (e.g., walwriter.c); register in postmaster.c::StartChildProcess and the appropriate MaybeStartXxx checks; add it to the shutdown / crash sequences.
  • New custom bgworker: in an extension, call RegisterBackgroundWorker from _PG_init. Use RegisterDynamicBackgroundWorker from a backend to spawn one on demand.
  • New signal: procsignal.c defines ProcSignalReason enumerations; add one and route it via ProcSignal infrastructure rather than raw signals when crossing process boundaries.

For the storage they all coordinate through, see Storage. For the WAL replay path of the startup process, see WAL and recovery. For replication processes specifically, see Replication.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Postmaster and process model – PostgreSQL wiki | Factory