2727#ifdef PROFILE_PID_DIR
2828#include "postmaster/autovacuum.h"
2929#endif
30+ #include "storage/dsm.h"
3031#include "storage/ipc.h"
3132#include "tcop/tcopprot.h"
3233
@@ -64,14 +65,19 @@ static void proc_exit_prepare(int code);
6465
6566#define MAX_ON_EXITS 20
6667
67- static struct ONEXIT
68+ struct ONEXIT
6869{
6970 pg_on_exit_callback function ;
7071 Datum arg ;
71- } on_proc_exit_list [MAX_ON_EXITS ], on_shmem_exit_list [MAX_ON_EXITS ];
72+ };
73+
74+ static struct ONEXIT on_proc_exit_list [MAX_ON_EXITS ];
75+ static struct ONEXIT on_shmem_exit_list [MAX_ON_EXITS ];
76+ static struct ONEXIT before_shmem_exit_list [MAX_ON_EXITS ];
7277
7378static int on_proc_exit_index ,
74- on_shmem_exit_index ;
79+ on_shmem_exit_index ,
80+ before_shmem_exit_index ;
7581
7682
7783/* ----------------------------------------------------------------
@@ -202,25 +208,60 @@ proc_exit_prepare(int code)
202208/* ------------------
203209 * Run all of the on_shmem_exit routines --- but don't actually exit.
204210 * This is used by the postmaster to re-initialize shared memory and
205- * semaphores after a backend dies horribly.
211+ * semaphores after a backend dies horribly. As with proc_exit(), we
212+ * remove each callback from the list before calling it, to avoid
213+ * infinite loop in case of error.
206214 * ------------------
207215 */
208216void
209217shmem_exit (int code )
210218{
211- elog (DEBUG3 , "shmem_exit(%d): %d callbacks to make" ,
212- code , on_shmem_exit_index );
219+ /*
220+ * Call before_shmem_exit callbacks.
221+ *
222+ * These should be things that need most of the system to still be
223+ * up and working, such as cleanup of temp relations, which requires
224+ * catalog access; or things that need to be completed because later
225+ * cleanup steps depend on them, such as releasing lwlocks.
226+ */
227+ elog (DEBUG3 , "shmem_exit(%d): %d before_shmem_exit callbacks to make" ,
228+ code , before_shmem_exit_index );
229+ while (-- before_shmem_exit_index >= 0 )
230+ (* before_shmem_exit_list [before_shmem_exit_index ].function ) (code ,
231+ before_shmem_exit_list [before_shmem_exit_index ].arg );
232+ before_shmem_exit_index = 0 ;
213233
214234 /*
215- * call all the registered callbacks.
235+ * Call dynamic shared memory callbacks.
236+ *
237+ * These serve the same purpose as late callbacks, but for dynamic shared
238+ * memory segments rather than the main shared memory segment.
239+ * dsm_backend_shutdown() has the same kind of progressive logic we use
240+ * for the main shared memory segment; namely, it unregisters each
241+ * callback before invoking it, so that we don't get stuck in an infinite
242+ * loop if one of those callbacks itself throws an ERROR or FATAL.
243+ *
244+ * Note that explicitly calling this function here is quite different
245+ * from registering it as an on_shmem_exit callback for precisely this
246+ * reason: if one dynamic shared memory callback errors out, the remaining
247+ * callbacks will still be invoked. Thus, hard-coding this call puts it
248+ * equal footing with callbacks for the main shared memory segment.
249+ */
250+ dsm_backend_shutdown ();
251+
252+ /*
253+ * Call on_shmem_exit callbacks.
216254 *
217- * As with proc_exit(), we remove each callback from the list before
218- * calling it, to avoid infinite loop in case of error.
255+ * These are generally releasing low-level shared memory resources. In
256+ * some cases, this is a backstop against the possibility that the early
257+ * callbacks might themselves fail, leading to re-entry to this routine;
258+ * in other cases, it's cleanup that only happens at process exit.
219259 */
260+ elog (DEBUG3 , "shmem_exit(%d): %d on_shmem_exit callbacks to make" ,
261+ code , on_shmem_exit_index );
220262 while (-- on_shmem_exit_index >= 0 )
221263 (* on_shmem_exit_list [on_shmem_exit_index ].function ) (code ,
222- on_shmem_exit_list [on_shmem_exit_index ].arg );
223-
264+ on_shmem_exit_list [on_shmem_exit_index ].arg );
224265 on_shmem_exit_index = 0 ;
225266}
226267
@@ -269,11 +310,40 @@ on_proc_exit(pg_on_exit_callback function, Datum arg)
269310 }
270311}
271312
313+ /* ----------------------------------------------------------------
314+ * before_shmem_exit
315+ *
316+ * Register early callback to perform user-level cleanup,
317+ * e.g. transaction abort, before we begin shutting down
318+ * low-level subsystems.
319+ * ----------------------------------------------------------------
320+ */
321+ void
322+ before_shmem_exit (pg_on_exit_callback function , Datum arg )
323+ {
324+ if (before_shmem_exit_index >= MAX_ON_EXITS )
325+ ereport (FATAL ,
326+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
327+ errmsg_internal ("out of before_shmem_exit slots" )));
328+
329+ before_shmem_exit_list [before_shmem_exit_index ].function = function ;
330+ before_shmem_exit_list [before_shmem_exit_index ].arg = arg ;
331+
332+ ++ before_shmem_exit_index ;
333+
334+ if (!atexit_callback_setup )
335+ {
336+ atexit (atexit_callback );
337+ atexit_callback_setup = true;
338+ }
339+ }
340+
272341/* ----------------------------------------------------------------
273342 * on_shmem_exit
274343 *
275- * this function adds a callback function to the list of
276- * functions invoked by shmem_exit(). -cim 2/6/90
344+ * Register ordinary callback to perform low-level shutdown
345+ * (e.g. releasing our PGPROC); run after before_shmem_exit
346+ * callbacks and before on_proc_exit callbacks.
277347 * ----------------------------------------------------------------
278348 */
279349void
@@ -297,21 +367,22 @@ on_shmem_exit(pg_on_exit_callback function, Datum arg)
297367}
298368
299369/* ----------------------------------------------------------------
300- * cancel_shmem_exit
370+ * cancel_before_shmem_exit
301371 *
302- * this function removes an entry, if present, from the list of
303- * functions to be invoked by shmem_exit(). For simplicity,
304- * only the latest entry can be removed. (We could work harder
305- * but there is no need for current uses.)
372+ * this function removes a previously-registed before_shmem_exit
373+ * callback. For simplicity, only the latest entry can be
374+ * removed. (We could work harder but there is no need for
375+ * current uses.)
306376 * ----------------------------------------------------------------
307377 */
308378void
309- cancel_shmem_exit (pg_on_exit_callback function , Datum arg )
379+ cancel_before_shmem_exit (pg_on_exit_callback function , Datum arg )
310380{
311- if (on_shmem_exit_index > 0 &&
312- on_shmem_exit_list [on_shmem_exit_index - 1 ].function == function &&
313- on_shmem_exit_list [on_shmem_exit_index - 1 ].arg == arg )
314- -- on_shmem_exit_index ;
381+ if (before_shmem_exit_index > 0 &&
382+ before_shmem_exit_list [before_shmem_exit_index - 1 ].function
383+ == function &&
384+ before_shmem_exit_list [before_shmem_exit_index - 1 ].arg == arg )
385+ -- before_shmem_exit_index ;
315386}
316387
317388/* ----------------------------------------------------------------
@@ -326,6 +397,7 @@ cancel_shmem_exit(pg_on_exit_callback function, Datum arg)
326397void
327398on_exit_reset (void )
328399{
400+ before_shmem_exit_index = 0 ;
329401 on_shmem_exit_index = 0 ;
330402 on_proc_exit_index = 0 ;
331403}
0 commit comments