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 writerPlus 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:
- Parse command line and read
postgresql.conf(andpg_hba.conf,pg_ident.conf). - Validate environment (
pg_controlexists, data directory permissions, etc.). - Create shared memory and semaphore arrays; set up locks; initialize the proc array and shared catalogs.
- Register signal handlers.
- If recovery is needed (or
recovery.signalexists), start the startup process and wait for it to reach a consistent state. - Once consistent, start the auxiliary processes (checkpointer, bgwriter, walwriter, autovacuum launcher, archiver, syslogger, ...).
- Open the listen sockets.
- 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:
- Logs the exit status.
- Marks the cluster as "needs reset."
- Sends
SIGQUITto every other backend (their data could be poisoned because the dead backend may have held a critical lock). - Waits for them all to exit.
- Reinitializes shared memory.
- Starts the startup process to perform crash recovery from WAL.
- 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) — runsStartupXLOG, 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) — scanspg_stat_all_tables, dispatches vacuum/analyze workers as needed. - Archiver (
pgarch.c) — copies completed WAL segments to long-term storage viaarchive_command/archive_library. - Syslogger (
syslogger.c) — captures stderr from all children and rotates log files. - WAL summarizer (
walsummarizer.c) — generates summary files used bypg_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_prewarmwarmup 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:
MemoryContextInit— set upTopMemoryContext.BaseInit— basic backend state.InitPostgres— attach to shared memory, the proc array, the database. Acquires the database-connection lock and runs catalog cache warmups.- Subsystem-specific init (e.g., autovacuum sets up scheduling tables).
- 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 inpostmaster.c::StartChildProcessand the appropriateMaybeStartXxxchecks; add it to the shutdown / crash sequences. - New custom bgworker: in an extension, call
RegisterBackgroundWorkerfrom_PG_init. UseRegisterDynamicBackgroundWorkerfrom a backend to spawn one on demand. - New signal:
procsignal.cdefinesProcSignalReasonenumerations; add one and route it viaProcSignalinfrastructure 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.