diff options
Diffstat (limited to 'src/backend/storage/ipc/ipc.c')
-rw-r--r-- | src/backend/storage/ipc/ipc.c | 118 |
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; } |