ipc.c 7.24 KB
Newer Older
1
/*-------------------------------------------------------------------------
2
 *
3
 * ipc.c
4
 *	  POSTGRES inter-process communication definitions.
5
 *
6
 * This file is misnamed, as it no longer has much of anything directly
Bruce Momjian's avatar
Bruce Momjian committed
7
 * to do with IPC.	The functionality here is concerned with managing
8 9 10
 * exit-time cleanup for either a postmaster or a backend.
 *
 *
11
 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
12
 * Portions Copyright (c) 1994, Regents of the University of California
13 14 15
 *
 *
 * IDENTIFICATION
16
 *	  $PostgreSQL: pgsql/src/backend/storage/ipc/ipc.c,v 1.98 2007/11/04 17:55:15 tgl Exp $
17 18 19
 *
 *-------------------------------------------------------------------------
 */
20 21
#include "postgres.h"

22
#include <signal.h>
23
#include <unistd.h>
24
#include <sys/stat.h>
25 26

#include "miscadmin.h"
27 28 29
#ifdef PROFILE_PID_DIR
#include "postmaster/autovacuum.h"
#endif
30
#include "storage/ipc.h"
31

32

33
/*
34 35
 * This flag is set during proc_exit() to change ereport()'s behavior,
 * so that an ereport() from an on_proc_exit routine cannot get us out
36 37
 * of the exit procedure.  We do NOT want to go back to the idle loop...
 */
38
bool		proc_exit_inprogress = false;
39

40

41
/* ----------------------------------------------------------------
42
 *						exit() handling stuff
43 44 45 46 47 48 49 50 51
 *
 * These functions are in generally the same spirit as atexit(2),
 * but provide some additional features we need --- in particular,
 * we want to register callbacks to invoke when we are disconnecting
 * from a broken shared-memory context but not exiting the postmaster.
 *
 * Callback functions can take zero, one, or two args: the first passed
 * arg is the integer exitcode, the second is the Datum supplied when
 * the callback was registered.
52 53 54 55 56
 * ----------------------------------------------------------------
 */

#define MAX_ON_EXITS 20

57 58
static struct ONEXIT
{
59
	void		(*function) (int code, Datum arg);
60
	Datum		arg;
61
}	on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];
62

63 64
static int	on_proc_exit_index,
			on_shmem_exit_index;
65 66 67


/* ----------------------------------------------------------------
68
 *		proc_exit
69
 *
70 71 72 73
 *		this function calls all the callbacks registered
 *		for it (to free resources) and then calls exit.
 *		This should be the only function to call exit().
 *		-cim 2/6/90
74 75 76
 * ----------------------------------------------------------------
 */
void
77
proc_exit(int code)
78
{
79
	/*
80 81
	 * Once we set this flag, we are committed to exit.  Any ereport() will
	 * NOT send control back to the main loop, but right back here.
82
	 */
83
	proc_exit_inprogress = true;
84

85
	/*
86 87 88
	 * Forget any pending cancel or die requests; we're doing our best to
	 * close up shop already.  Note that the signal handlers will not set
	 * these flags again, now that proc_exit_inprogress is set.
89
	 */
90
	InterruptPending = false;
91
	ProcDiePending = false;
92 93 94
	QueryCancelPending = false;
	/* And let's just make *sure* we're not interrupted ... */
	ImmediateInterruptOK = false;
95 96
	InterruptHoldoffCount = 1;
	CritSectionCount = 0;
97

98
	elog(DEBUG3, "proc_exit(%d)", code);
99

100 101
	/* do our shared memory exits first */
	shmem_exit(code);
102

103 104
	/*
	 * call all the callbacks registered before calling exit().
105
	 *
106 107 108 109 110
	 * Note that since we decrement on_proc_exit_index each time, if a
	 * callback calls ereport(ERROR) or ereport(FATAL) then it won't be
	 * invoked again when control comes back here (nor will the
	 * previously-completed callbacks).  So, an infinite loop should not be
	 * possible.
111
	 */
112 113
	while (--on_proc_exit_index >= 0)
		(*on_proc_exit_list[on_proc_exit_index].function) (code,
114
								  on_proc_exit_list[on_proc_exit_index].arg);
115

116
	elog(DEBUG3, "exit(%d)", code);
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131

#ifdef PROFILE_PID_DIR
	{
		/*
		 * If we are profiling ourself then gprof's mcleanup() is about
		 * to write out a profile to ./gmon.out.  Since mcleanup() always 
		 * uses a fixed file name, each backend will overwrite earlier
		 * profiles. To fix that, we create a separate subdirectory for
		 * each backend (./gprof/pid) and 'cd' to that subdirectory before
		 * we exit() - that forces mcleanup() to write each profile into
		 * its own directory.  We end up with something like:
		 *	$PGDATA/gprof/8829/gmon.out
		 *	$PGDATA/gprof/8845/gmon.out
		 *		...
		 *
132 133 134 135 136
		 * To avoid undesirable disk space bloat, autovacuum workers are
		 * discriminated against: all their gmon.out files go into the same
		 * subdirectory.  Without this, an installation that is "just sitting
		 * there" nonetheless eats megabytes of disk space every few seconds.
		 *
137 138 139 140 141 142 143
		 * Note that we do this here instead of in an on_proc_exit() 
		 * callback because we want to ensure that this code executes
		 * last - we don't want to interfere with any other on_proc_exit()
		 * callback.
		 */
		char gprofDirName[32];

144 145 146 147
		if (IsAutoVacuumWorkerProcess())
			snprintf(gprofDirName, 32, "gprof/avworker");
		else
			snprintf(gprofDirName, 32, "gprof/%d", (int) getpid());
148 149 150 151 152 153 154
	    
		mkdir("gprof", 0777);
		mkdir(gprofDirName, 0777);
		chdir(gprofDirName);
	}
#endif

155
	exit(code);
156 157 158
}

/* ------------------
159
 * Run all of the on_shmem_exit routines --- but don't actually exit.
160
 * This is used by the postmaster to re-initialize shared memory and
161
 * semaphores after a backend dies horribly.
162 163 164
 * ------------------
 */
void
165
shmem_exit(int code)
166
{
167
	elog(DEBUG3, "shmem_exit(%d)", code);
168

169 170
	/*
	 * call all the registered callbacks.
171
	 *
172 173
	 * As with proc_exit(), we remove each callback from the list before
	 * calling it, to avoid infinite loop in case of error.
174
	 */
175 176
	while (--on_shmem_exit_index >= 0)
		(*on_shmem_exit_list[on_shmem_exit_index].function) (code,
177
								on_shmem_exit_list[on_shmem_exit_index].arg);
178 179 180

	on_shmem_exit_index = 0;
}
181

182 183 184 185 186 187 188
/* ----------------------------------------------------------------
 *		on_proc_exit
 *
 *		this function adds a callback function to the list of
 *		functions invoked by proc_exit().	-cim 2/6/90
 * ----------------------------------------------------------------
 */
189
void
Bruce Momjian's avatar
Bruce Momjian committed
190
			on_proc_exit(void (*function) (int code, Datum arg), Datum arg)
191 192
{
	if (on_proc_exit_index >= MAX_ON_EXITS)
193 194 195
		ereport(FATAL,
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
				 errmsg_internal("out of on_proc_exit slots")));
196 197 198 199 200

	on_proc_exit_list[on_proc_exit_index].function = function;
	on_proc_exit_list[on_proc_exit_index].arg = arg;

	++on_proc_exit_index;
201 202 203
}

/* ----------------------------------------------------------------
204
 *		on_shmem_exit
205
 *
206
 *		this function adds a callback function to the list of
207
 *		functions invoked by shmem_exit().	-cim 2/6/90
208 209
 * ----------------------------------------------------------------
 */
210
void
Bruce Momjian's avatar
Bruce Momjian committed
211
			on_shmem_exit(void (*function) (int code, Datum arg), Datum arg)
212
{
213
	if (on_shmem_exit_index >= MAX_ON_EXITS)
214 215 216
		ereport(FATAL,
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
				 errmsg_internal("out of on_shmem_exit slots")));
217

218 219
	on_shmem_exit_list[on_shmem_exit_index].function = function;
	on_shmem_exit_list[on_shmem_exit_index].arg = arg;
220

221
	++on_shmem_exit_index;
222 223
}

224
/* ----------------------------------------------------------------
225
 *		on_exit_reset
226
 *
227 228 229 230
 *		this function clears all on_proc_exit() and on_shmem_exit()
 *		registered functions.  This is used just after forking a backend,
 *		so that the backend doesn't believe it should call the postmaster's
 *		on-exit routines when it exits...
231 232 233
 * ----------------------------------------------------------------
 */
void
234
on_exit_reset(void)
235
{
236
	on_shmem_exit_index = 0;
237
	on_proc_exit_index = 0;
238
}