aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/ipc/ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/ipc/ipc.c')
-rw-r--r--src/backend/storage/ipc/ipc.c118
1 files changed, 95 insertions, 23 deletions
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index c339e9c780b..9297292fc5e 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -27,6 +27,7 @@
#ifdef PROFILE_PID_DIR
#include "postmaster/autovacuum.h"
#endif
+#include "storage/dsm.h"
#include "storage/ipc.h"
#include "tcop/tcopprot.h"
@@ -64,14 +65,19 @@ static void proc_exit_prepare(int code);
#define MAX_ON_EXITS 20
-static struct ONEXIT
+struct ONEXIT
{
pg_on_exit_callback function;
Datum arg;
-} on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];
+};
+
+static struct ONEXIT on_proc_exit_list[MAX_ON_EXITS];
+static struct ONEXIT on_shmem_exit_list[MAX_ON_EXITS];
+static struct ONEXIT before_shmem_exit_list[MAX_ON_EXITS];
static int on_proc_exit_index,
- on_shmem_exit_index;
+ on_shmem_exit_index,
+ before_shmem_exit_index;
/* ----------------------------------------------------------------
@@ -202,25 +208,60 @@ proc_exit_prepare(int code)
/* ------------------
* Run all of the on_shmem_exit routines --- but don't actually exit.
* This is used by the postmaster to re-initialize shared memory and
- * semaphores after a backend dies horribly.
+ * semaphores after a backend dies horribly. As with proc_exit(), we
+ * remove each callback from the list before calling it, to avoid
+ * infinite loop in case of error.
* ------------------
*/
void
shmem_exit(int code)
{
- elog(DEBUG3, "shmem_exit(%d): %d callbacks to make",
- code, on_shmem_exit_index);
+ /*
+ * Call before_shmem_exit callbacks.
+ *
+ * These should be things that need most of the system to still be
+ * up and working, such as cleanup of temp relations, which requires
+ * catalog access; or things that need to be completed because later
+ * cleanup steps depend on them, such as releasing lwlocks.
+ */
+ elog(DEBUG3, "shmem_exit(%d): %d before_shmem_exit callbacks to make",
+ code, before_shmem_exit_index);
+ while (--before_shmem_exit_index >= 0)
+ (*before_shmem_exit_list[before_shmem_exit_index].function) (code,
+ before_shmem_exit_list[before_shmem_exit_index].arg);
+ before_shmem_exit_index = 0;
/*
- * call all the registered callbacks.
+ * Call dynamic shared memory callbacks.
+ *
+ * These serve the same purpose as late callbacks, but for dynamic shared
+ * memory segments rather than the main shared memory segment.
+ * dsm_backend_shutdown() has the same kind of progressive logic we use
+ * for the main shared memory segment; namely, it unregisters each
+ * callback before invoking it, so that we don't get stuck in an infinite
+ * loop if one of those callbacks itself throws an ERROR or FATAL.
+ *
+ * Note that explicitly calling this function here is quite different
+ * from registering it as an on_shmem_exit callback for precisely this
+ * reason: if one dynamic shared memory callback errors out, the remaining
+ * callbacks will still be invoked. Thus, hard-coding this call puts it
+ * equal footing with callbacks for the main shared memory segment.
+ */
+ dsm_backend_shutdown();
+
+ /*
+ * Call on_shmem_exit callbacks.
*
- * As with proc_exit(), we remove each callback from the list before
- * calling it, to avoid infinite loop in case of error.
+ * These are generally releasing low-level shared memory resources. In
+ * some cases, this is a backstop against the possibility that the early
+ * callbacks might themselves fail, leading to re-entry to this routine;
+ * in other cases, it's cleanup that only happens at process exit.
*/
+ elog(DEBUG3, "shmem_exit(%d): %d on_shmem_exit callbacks to make",
+ code, on_shmem_exit_index);
while (--on_shmem_exit_index >= 0)
(*on_shmem_exit_list[on_shmem_exit_index].function) (code,
- on_shmem_exit_list[on_shmem_exit_index].arg);
-
+ on_shmem_exit_list[on_shmem_exit_index].arg);
on_shmem_exit_index = 0;
}
@@ -270,10 +311,39 @@ on_proc_exit(pg_on_exit_callback function, Datum arg)
}
/* ----------------------------------------------------------------
+ * before_shmem_exit
+ *
+ * Register early callback to perform user-level cleanup,
+ * e.g. transaction abort, before we begin shutting down
+ * low-level subsystems.
+ * ----------------------------------------------------------------
+ */
+void
+before_shmem_exit(pg_on_exit_callback function, Datum arg)
+{
+ if (before_shmem_exit_index >= MAX_ON_EXITS)
+ ereport(FATAL,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg_internal("out of before_shmem_exit slots")));
+
+ before_shmem_exit_list[before_shmem_exit_index].function = function;
+ before_shmem_exit_list[before_shmem_exit_index].arg = arg;
+
+ ++before_shmem_exit_index;
+
+ if (!atexit_callback_setup)
+ {
+ atexit(atexit_callback);
+ atexit_callback_setup = true;
+ }
+}
+
+/* ----------------------------------------------------------------
* on_shmem_exit
*
- * this function adds a callback function to the list of
- * functions invoked by shmem_exit(). -cim 2/6/90
+ * Register ordinary callback to perform low-level shutdown
+ * (e.g. releasing our PGPROC); run after before_shmem_exit
+ * callbacks and before on_proc_exit callbacks.
* ----------------------------------------------------------------
*/
void
@@ -297,21 +367,22 @@ on_shmem_exit(pg_on_exit_callback function, Datum arg)
}
/* ----------------------------------------------------------------
- * cancel_shmem_exit
+ * cancel_before_shmem_exit
*
- * this function removes an entry, if present, from the list of
- * functions to be invoked by shmem_exit(). For simplicity,
- * only the latest entry can be removed. (We could work harder
- * but there is no need for current uses.)
+ * this function removes a previously-registed before_shmem_exit
+ * callback. For simplicity, only the latest entry can be
+ * removed. (We could work harder but there is no need for
+ * current uses.)
* ----------------------------------------------------------------
*/
void
-cancel_shmem_exit(pg_on_exit_callback function, Datum arg)
+cancel_before_shmem_exit(pg_on_exit_callback function, Datum arg)
{
- if (on_shmem_exit_index > 0 &&
- on_shmem_exit_list[on_shmem_exit_index - 1].function == function &&
- on_shmem_exit_list[on_shmem_exit_index - 1].arg == arg)
- --on_shmem_exit_index;
+ if (before_shmem_exit_index > 0 &&
+ before_shmem_exit_list[before_shmem_exit_index - 1].function
+ == function &&
+ before_shmem_exit_list[before_shmem_exit_index - 1].arg == arg)
+ --before_shmem_exit_index;
}
/* ----------------------------------------------------------------
@@ -326,6 +397,7 @@ cancel_shmem_exit(pg_on_exit_callback function, Datum arg)
void
on_exit_reset(void)
{
+ before_shmem_exit_index = 0;
on_shmem_exit_index = 0;
on_proc_exit_index = 0;
}