1/*-------------------------------------------------------------------------
2 *
3 * startup.c
4 *
5 * The Startup process initialises the server and performs any recovery
6 * actions that have been specified. Notice that there is no "main loop"
7 * since the Startup process ends as soon as initialisation is complete.
8 * (in standby mode, one can think of the replay loop as a main loop,
9 * though.)
10 *
11 *
12 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
13 *
14 *
15 * IDENTIFICATION
16 * src/backend/postmaster/startup.c
17 *
18 *-------------------------------------------------------------------------
19 */
20#include "postgres.h"
21
22#include <signal.h>
23#include <unistd.h>
24
25#include "access/xlog.h"
26#include "libpq/pqsignal.h"
27#include "miscadmin.h"
28#include "pgstat.h"
29#include "postmaster/startup.h"
30#include "storage/ipc.h"
31#include "storage/latch.h"
32#include "storage/pmsignal.h"
33#include "storage/standby.h"
34#include "utils/guc.h"
35#include "utils/timeout.h"
36
37
38/*
39 * Flags set by interrupt handlers for later service in the redo loop.
40 */
41static volatile sig_atomic_t got_SIGHUP = false;
42static volatile sig_atomic_t shutdown_requested = false;
43static volatile sig_atomic_t promote_triggered = false;
44
45/*
46 * Flag set when executing a restore command, to tell SIGTERM signal handler
47 * that it's safe to just proc_exit.
48 */
49static volatile sig_atomic_t in_restore_command = false;
50
51/* Signal handlers */
52static void startupproc_quickdie(SIGNAL_ARGS);
53static void StartupProcSigUsr1Handler(SIGNAL_ARGS);
54static void StartupProcTriggerHandler(SIGNAL_ARGS);
55static void StartupProcSigHupHandler(SIGNAL_ARGS);
56
57
58/* --------------------------------
59 * signal handler routines
60 * --------------------------------
61 */
62
63/*
64 * startupproc_quickdie() occurs when signalled SIGQUIT by the postmaster.
65 *
66 * Some backend has bought the farm,
67 * so we need to stop what we're doing and exit.
68 */
69static void
70startupproc_quickdie(SIGNAL_ARGS)
71{
72 /*
73 * We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
74 * because shared memory may be corrupted, so we don't want to try to
75 * clean up our transaction. Just nail the windows shut and get out of
76 * town. The callbacks wouldn't be safe to run from a signal handler,
77 * anyway.
78 *
79 * Note we do _exit(2) not _exit(0). This is to force the postmaster into
80 * a system reset cycle if someone sends a manual SIGQUIT to a random
81 * backend. This is necessary precisely because we don't clean up our
82 * shared memory state. (The "dead man switch" mechanism in pmsignal.c
83 * should ensure the postmaster sees this as a crash, too, but no harm in
84 * being doubly sure.)
85 */
86 _exit(2);
87}
88
89
90/* SIGUSR1: let latch facility handle the signal */
91static void
92StartupProcSigUsr1Handler(SIGNAL_ARGS)
93{
94 int save_errno = errno;
95
96 latch_sigusr1_handler();
97
98 errno = save_errno;
99}
100
101/* SIGUSR2: set flag to finish recovery */
102static void
103StartupProcTriggerHandler(SIGNAL_ARGS)
104{
105 int save_errno = errno;
106
107 promote_triggered = true;
108 WakeupRecovery();
109
110 errno = save_errno;
111}
112
113/* SIGHUP: set flag to re-read config file at next convenient time */
114static void
115StartupProcSigHupHandler(SIGNAL_ARGS)
116{
117 int save_errno = errno;
118
119 got_SIGHUP = true;
120 WakeupRecovery();
121
122 errno = save_errno;
123}
124
125/* SIGTERM: set flag to abort redo and exit */
126static void
127StartupProcShutdownHandler(SIGNAL_ARGS)
128{
129 int save_errno = errno;
130
131 if (in_restore_command)
132 proc_exit(1);
133 else
134 shutdown_requested = true;
135 WakeupRecovery();
136
137 errno = save_errno;
138}
139
140/* Handle SIGHUP and SIGTERM signals of startup process */
141void
142HandleStartupProcInterrupts(void)
143{
144 /*
145 * Check if we were requested to re-read config file.
146 */
147 if (got_SIGHUP)
148 {
149 got_SIGHUP = false;
150 ProcessConfigFile(PGC_SIGHUP);
151 }
152
153 /*
154 * Check if we were requested to exit without finishing recovery.
155 */
156 if (shutdown_requested)
157 proc_exit(1);
158
159 /*
160 * Emergency bailout if postmaster has died. This is to avoid the
161 * necessity for manual cleanup of all postmaster children.
162 */
163 if (IsUnderPostmaster && !PostmasterIsAlive())
164 exit(1);
165}
166
167
168/* ----------------------------------
169 * Startup Process main entry point
170 * ----------------------------------
171 */
172void
173StartupProcessMain(void)
174{
175 /*
176 * Properly accept or ignore signals the postmaster might send us.
177 */
178 pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
179 pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */
180 pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
181 pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */
182 InitializeTimeouts(); /* establishes SIGALRM handler */
183 pqsignal(SIGPIPE, SIG_IGN);
184 pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
185 pqsignal(SIGUSR2, StartupProcTriggerHandler);
186
187 /*
188 * Reset some signals that are accepted by postmaster but not here
189 */
190 pqsignal(SIGCHLD, SIG_DFL);
191
192 /*
193 * Register timeouts needed for standby mode
194 */
195 RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler);
196 RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler);
197 RegisterTimeout(STANDBY_LOCK_TIMEOUT, StandbyLockTimeoutHandler);
198
199 /*
200 * Unblock signals (they were blocked when the postmaster forked us)
201 */
202 PG_SETMASK(&UnBlockSig);
203
204 /*
205 * Do what we came for.
206 */
207 StartupXLOG();
208
209 /*
210 * Exit normally. Exit code 0 tells postmaster that we completed recovery
211 * successfully.
212 */
213 proc_exit(0);
214}
215
216void
217PreRestoreCommand(void)
218{
219 /*
220 * Set in_restore_command to tell the signal handler that we should exit
221 * right away on SIGTERM. We know that we're at a safe point to do that.
222 * Check if we had already received the signal, so that we don't miss a
223 * shutdown request received just before this.
224 */
225 in_restore_command = true;
226 if (shutdown_requested)
227 proc_exit(1);
228}
229
230void
231PostRestoreCommand(void)
232{
233 in_restore_command = false;
234}
235
236bool
237IsPromoteTriggered(void)
238{
239 return promote_triggered;
240}
241
242void
243ResetPromoteTriggered(void)
244{
245 promote_triggered = false;
246}
247