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 | */ |
41 | static volatile sig_atomic_t got_SIGHUP = false; |
42 | static volatile sig_atomic_t shutdown_requested = false; |
43 | static 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 | */ |
49 | static volatile sig_atomic_t in_restore_command = false; |
50 | |
51 | /* Signal handlers */ |
52 | static void startupproc_quickdie(SIGNAL_ARGS); |
53 | static void StartupProcSigUsr1Handler(SIGNAL_ARGS); |
54 | static void StartupProcTriggerHandler(SIGNAL_ARGS); |
55 | static 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 | */ |
69 | static void |
70 | startupproc_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 */ |
91 | static void |
92 | StartupProcSigUsr1Handler(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 */ |
102 | static void |
103 | StartupProcTriggerHandler(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 */ |
114 | static void |
115 | StartupProcSigHupHandler(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 */ |
126 | static void |
127 | StartupProcShutdownHandler(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 */ |
141 | void |
142 | HandleStartupProcInterrupts(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 | */ |
172 | void |
173 | StartupProcessMain(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 | |
216 | void |
217 | PreRestoreCommand(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 | |
230 | void |
231 | PostRestoreCommand(void) |
232 | { |
233 | in_restore_command = false; |
234 | } |
235 | |
236 | bool |
237 | IsPromoteTriggered(void) |
238 | { |
239 | return promote_triggered; |
240 | } |
241 | |
242 | void |
243 | ResetPromoteTriggered(void) |
244 | { |
245 | promote_triggered = false; |
246 | } |
247 | |