aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/slru.c21
-rw-r--r--src/backend/access/transam/xlog.c4
-rw-r--r--src/backend/bootstrap/bootstrap.c97
-rw-r--r--src/backend/main/main.c52
-rw-r--r--src/backend/port/ipc_test.c4
-rw-r--r--src/backend/postmaster/pgstat.c248
-rw-r--r--src/backend/postmaster/postmaster.c923
-rw-r--r--src/backend/storage/buffer/buf_init.c24
-rw-r--r--src/backend/storage/ipc/ipci.c18
-rw-r--r--src/backend/storage/lmgr/lmgr.c9
-rw-r--r--src/backend/storage/lmgr/lock.c34
-rw-r--r--src/backend/tcop/postgres.c32
-rw-r--r--src/backend/utils/init/globals.c14
-rw-r--r--src/include/access/slru.h35
-rw-r--r--src/include/bootstrap/bootstrap.h4
-rw-r--r--src/include/miscadmin.h12
-rw-r--r--src/include/pgstat.h33
-rw-r--r--src/include/storage/lock.h9
-rw-r--r--src/include/utils/guc.h6
19 files changed, 780 insertions, 799 deletions
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index a12fe885563..dff221bf277 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.13 2004/02/23 23:03:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.14 2004/05/28 05:12:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -164,10 +164,9 @@ static bool SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions);
int
SimpleLruShmemSize(void)
{
- return MAXALIGN(sizeof(SlruSharedData)) + BLCKSZ * NUM_CLOG_BUFFERS
-#ifdef EXEC_BACKEND
+ return MAXALIGN(sizeof(SlruSharedData))
+ + BLCKSZ * NUM_CLOG_BUFFERS
+ MAXALIGN(sizeof(SlruLockData))
-#endif
;
}
@@ -181,21 +180,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
ptr = ShmemInitStruct(name, SimpleLruShmemSize(), &found);
shared = (SlruShared) ptr;
-
-#ifdef EXEC_BACKEND
- /*
- * Locks are in shared memory
- */
locks = (SlruLock) (ptr + MAXALIGN(sizeof(SlruSharedData)) +
BLCKSZ * NUM_CLOG_BUFFERS);
-#else
- /*
- * Locks are in private memory
- */
- Assert(!IsUnderPostmaster);
- locks = malloc(sizeof(SlruLockData));
- Assert(locks);
-#endif
if (!IsUnderPostmaster)
{
@@ -225,6 +211,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
else
Assert(found);
+ /* Initialize the unshared control struct */
ctl->locks = locks;
ctl->shared = shared;
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0af9d2910d4..348906ea4ac 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.143 2004/05/27 17:12:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.144 2004/05/28 05:12:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -397,7 +397,7 @@ static char ControlFilePath[MAXPGPATH];
* Private, possibly out-of-date copy of shared LogwrtResult.
* See discussion above.
*/
-NON_EXEC_STATIC XLogwrtResult LogwrtResult = {{0, 0}, {0, 0}};
+static XLogwrtResult LogwrtResult = {{0, 0}, {0, 0}};
/*
* openLogFile is -1 or a kernel FD for an open log file segment.
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 315c17e526a..ed42bf133c7 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.180 2004/05/27 17:12:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.181 2004/05/28 05:12:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,17 +43,12 @@
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
+#include "utils/ps_status.h"
#include "utils/relcache.h"
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
-#ifdef EXEC_BACKEND
-typedef struct Port Port;
-extern void SSDataBaseInit(int);
-extern void read_backend_variables(unsigned long, Port*);
-#endif
-
extern int Int_yyparse(void);
static hashnode *AddStr(char *str, int strlength, int mderef);
static Form_pg_attribute AllocateAttribute(void);
@@ -233,34 +228,29 @@ usage(void)
}
-
-int
-BootstrapMain(int argc, char *argv[])
-/* ----------------------------------------------------------------
- * The main loop for handling the backend in bootstrap mode
- * the bootstrap mode is used to initialize the template database
- * the bootstrap backend doesn't speak SQL, but instead expects
+/*
+ * The main loop for running the backend in bootstrap mode
+ *
+ * The bootstrap mode is used to initialize the template database.
+ * The bootstrap backend doesn't speak SQL, but instead expects
* commands in a special bootstrap language.
*
- * The arguments passed in to BootstrapMain are the run-time arguments
- * without the argument '-boot', the caller is required to have
- * removed -boot from the run-time args
- * ----------------------------------------------------------------
+ * For historical reasons, BootstrapMain is also used as the control
+ * routine for non-backend subprocesses launched by the postmaster,
+ * such as startup and shutdown.
*/
+int
+BootstrapMain(int argc, char *argv[])
{
int i;
char *dbname;
int flag;
int xlogop = BS_XLOG_NOP;
char *potential_DataDir = NULL;
-#ifdef EXEC_BACKEND
- unsigned long backendID = 0;
-#endif
/*
* initialize globals
*/
-
MyProcPid = getpid();
/*
@@ -268,7 +258,7 @@ BootstrapMain(int argc, char *argv[])
*
* If we are running under the postmaster, this is done already.
*/
- if (!IsUnderPostmaster || ExecBackend)
+ if (!IsUnderPostmaster)
MemoryContextInit();
/*
@@ -284,6 +274,13 @@ BootstrapMain(int argc, char *argv[])
* variable */
}
+ /* Ignore the initial -boot argument, if present */
+ if (argc > 1 && strcmp(argv[1], "-boot") == 0)
+ {
+ argv++;
+ argc--;
+ }
+
while ((flag = getopt(argc, argv, "B:c:d:D:Fo:p:x:-:")) != -1)
{
switch (flag)
@@ -315,14 +312,6 @@ BootstrapMain(int argc, char *argv[])
xlogop = atoi(optarg);
break;
case 'p':
-#ifdef EXEC_BACKEND
- {
- char buf[MAXPGPATH];
- IsUnderPostmaster = true;
- sscanf(optarg,"%lu,%s",&backendID,buf);
- dbname = strdup(buf);
- }
-#endif
dbname = strdup(optarg);
break;
case 'B':
@@ -369,7 +358,7 @@ BootstrapMain(int argc, char *argv[])
if (!dbname || argc != optind)
usage();
- if (!IsUnderPostmaster || ExecBackend)
+ if (!IsUnderPostmaster)
{
if (!potential_DataDir)
{
@@ -388,21 +377,43 @@ BootstrapMain(int argc, char *argv[])
Assert(DataDir);
ValidatePgVersion(DataDir);
- /* Acquire configuration parameters */
+ /*
+ * Identify myself via ps
+ */
if (IsUnderPostmaster)
{
-#ifdef EXEC_BACKEND
- read_backend_variables(backendID,NULL);
- read_nondefault_variables();
+ const char *statmsg;
- SSDataBaseInit(xlogop);
-#endif
+ switch (xlogop)
+ {
+ case BS_XLOG_STARTUP:
+ statmsg = "startup subprocess";
+ break;
+ case BS_XLOG_CHECKPOINT:
+ statmsg = "checkpoint subprocess";
+ break;
+ case BS_XLOG_BGWRITER:
+ statmsg = "bgwriter subprocess";
+ break;
+ case BS_XLOG_SHUTDOWN:
+ statmsg = "shutdown subprocess";
+ break;
+ default:
+ statmsg = "??? subprocess";
+ break;
+ }
+ init_ps_display(statmsg, "", "");
+ set_ps_display("");
}
- else
+
+ /* Acquire configuration parameters, unless inherited from postmaster */
+ if (!IsUnderPostmaster)
+ {
ProcessConfigFile(PGC_POSTMASTER);
- /* If timezone is not set, determine what the OS uses */
- pg_timezone_initialize();
+ /* If timezone is not set, determine what the OS uses */
+ pg_timezone_initialize();
+ }
if (IsUnderPostmaster)
{
@@ -450,10 +461,6 @@ BootstrapMain(int argc, char *argv[])
SetProcessingMode(BootstrapProcessing);
IgnoreSystemIndexes(true);
-#ifdef EXEC_BACKEND
- if (IsUnderPostmaster)
- CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
-#endif
XLOGPathInit();
BaseInit();
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index bbf3fc47ecd..272d4cc0d0a 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/main/main.c,v 1.83 2004/05/27 15:07:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/main/main.c,v 1.84 2004/05/28 05:12:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -242,9 +242,9 @@ main(int argc, char *argv[])
/*
* Now dispatch to one of PostmasterMain, PostgresMain, GucInfoMain,
- * SubPostmasterMain, pgstat_main, pgstat_mainChild or BootstrapMain
- * depending on the program name (and possibly first argument) we were
- * called with. The lack of consistency here is historical.
+ * SubPostmasterMain, or BootstrapMain depending on the program name
+ * (and possibly first argument) we were called with. The lack of
+ * consistency here is historical.
*/
len = strlen(argv[0]);
@@ -259,43 +259,21 @@ main(int argc, char *argv[])
}
/*
- * If the first argument is "-boot", then invoke bootstrap mode. Note
- * we remove "-boot" from the arguments passed on to BootstrapMain.
+ * If the first argument begins with "-fork", then invoke
+ * SubPostmasterMain. This is used for forking postmaster child
+ * processes on systems where we can't simply fork.
*/
- if (argc > 1 && strcmp(argv[1], "-boot") == 0)
- exit(BootstrapMain(argc - 1, argv + 1));
-
#ifdef EXEC_BACKEND
+ if (argc > 1 && strncmp(argv[1], "-fork", 5) == 0)
+ exit(SubPostmasterMain(argc, argv));
+#endif
/*
- * If the first argument is "-forkexec", then invoke
- * SubPostmasterMain. Note we remove "-forkexec" from the arguments
- * passed on to SubPostmasterMain.
- */
- if (argc > 1 && strcmp(argv[1], "-forkexec") == 0)
- {
- SubPostmasterMain(argc - 2, argv + 2);
- exit(0);
- }
-
- /*
- * If the first argument is "-statBuf", then invoke pgstat_main.
- */
- if (argc > 1 && strcmp(argv[1], "-statBuf") == 0)
- {
- pgstat_main(argc, argv);
- exit(0);
- }
-
- /*
- * If the first argument is "-statCol", then invoke pgstat_mainChild.
+ * If the first argument is "-boot", then invoke bootstrap mode.
+ * (This path is taken only for a standalone bootstrap process.)
*/
- if (argc > 1 && strcmp(argv[1], "-statCol") == 0)
- {
- pgstat_mainChild(argc, argv);
- exit(0);
- }
-#endif
+ if (argc > 1 && strcmp(argv[1], "-boot") == 0)
+ exit(BootstrapMain(argc, argv));
/*
* If the first argument is "--describe-config", then invoke runtime
@@ -331,7 +309,7 @@ main(int argc, char *argv[])
exit(1);
}
}
-#endif
+#endif /* WIN32 */
exit(PostgresMain(argc, argv, pw_name_persist));
}
diff --git a/src/backend/port/ipc_test.c b/src/backend/port/ipc_test.c
index fef9f282f30..0b4097c82e0 100644
--- a/src/backend/port/ipc_test.c
+++ b/src/backend/port/ipc_test.c
@@ -21,7 +21,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/port/ipc_test.c,v 1.12 2003/12/12 18:45:09 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/port/ipc_test.c,v 1.13 2004/05/28 05:12:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,8 +46,6 @@ volatile bool ImmediateInterruptOK = false;
volatile uint32 InterruptHoldoffCount = 0;
volatile uint32 CritSectionCount = 0;
-const bool ExecBackend = false;
-
bool IsUnderPostmaster = false;
int MaxBackends = 32;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 70924eb676e..a3a4e57c855 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -9,11 +9,11 @@
* - Add some automatic call for pgstat vacuuming.
*
* - Add a pgstat config column to pg_database, so this
- * entire thing can be enabled/disabled on a per db base.
+ * entire thing can be enabled/disabled on a per db basis.
*
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.71 2004/05/24 02:47:47 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.72 2004/05/28 05:12:58 tgl Exp $
* ----------
*/
#include "postgres.h"
@@ -51,13 +51,6 @@
#include "utils/ps_status.h"
#include "utils/syscache.h"
-#ifdef EXEC_BACKEND
-#include "utils/guc.h"
-#endif
-
-#ifdef WIN32
-extern pid_t win32_forkexec(const char* path, char *argv[]);
-#endif
/* ----------
* GUC parameters
@@ -107,8 +100,8 @@ static HTAB *pgStatBeDead = NULL;
static PgStat_StatBeEntry *pgStatBeTable = NULL;
static int pgStatNumBackends = 0;
-static char pgStat_tmpfname[MAXPGPATH];
static char pgStat_fname[MAXPGPATH];
+static char pgStat_tmpfname[MAXPGPATH];
/* ----------
@@ -116,12 +109,20 @@ static char pgStat_fname[MAXPGPATH];
* ----------
*/
#ifdef EXEC_BACKEND
+
+typedef enum STATS_PROCESS_TYPE
+{
+ STAT_PROC_BUFFER,
+ STAT_PROC_COLLECTOR
+} STATS_PROCESS_TYPE;
+
static pid_t pgstat_forkexec(STATS_PROCESS_TYPE procType);
-static void pgstat_parseArgs(PGSTAT_FORK_ARGS);
+static void pgstat_parseArgs(int argc, char *argv[]);
+
#endif
-NON_EXEC_STATIC void pgstat_main(PGSTAT_FORK_ARGS);
-NON_EXEC_STATIC void pgstat_mainChild(PGSTAT_FORK_ARGS);
-static void pgstat_mainInit(void);
+
+NON_EXEC_STATIC void PgstatBufferMain(int argc, char *argv[]);
+NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]);
static void pgstat_recvbuffer(void);
static void pgstat_die(SIGNAL_ARGS);
@@ -150,18 +151,6 @@ static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);
* ------------------------------------------------------------
*/
-#ifdef EXEC_BACKEND
-
-void
-pgstat_init_forkexec_backend(void)
-{
- Assert(DataDir != NULL);
- snprintf(pgStat_fname, MAXPGPATH,
- PGSTAT_STAT_FILENAME, DataDir);
-}
-
-#endif
-
/* ----------
* pgstat_init() -
*
@@ -195,12 +184,12 @@ pgstat_init(void)
pgstat_collect_startcollector = true;
/*
- * Initialize the filenames for the status reports.
+ * Initialize the filename for the status reports. (In the EXEC_BACKEND
+ * case, this only sets the value in the postmaster. The collector
+ * subprocess will recompute the value for itself, and individual
+ * backends must do so also if they want to access the file.)
*/
- snprintf(pgStat_tmpfname, MAXPGPATH,
- PGSTAT_STAT_TMPFILE, DataDir, getpid());
- snprintf(pgStat_fname, MAXPGPATH,
- PGSTAT_STAT_FILENAME, DataDir);
+ snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
/*
* If we don't have to start a collector or should reset the collected
@@ -441,112 +430,83 @@ startup_failed:
#ifdef EXEC_BACKEND
-/* ----------
+/*
* pgstat_forkexec() -
*
- * Used to format up the arglist for, then fork and exec, statistics
+ * Format up the arglist for, then fork and exec, statistics
* (buffer and collector) processes
- *
*/
static pid_t
pgstat_forkexec(STATS_PROCESS_TYPE procType)
{
- pid_t pid;
- char *av[15];
+ char *av[12];
int ac = 0, bufc = 0, i;
- char pgstatBuf[12][MAXPGPATH];
+ char pgstatBuf[7][32];
av[ac++] = "postgres";
+
switch (procType)
{
case STAT_PROC_BUFFER:
- av[ac++] = "-statBuf";
+ av[ac++] = "-forkbuf";
break;
case STAT_PROC_COLLECTOR:
- av[ac++] = "-statCol";
+ av[ac++] = "-forkcol";
break;
default:
Assert(false);
}
- /* Sockets + pipes */
- bufc = 0;
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatSock);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[0]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[1]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[0]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[1]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[0]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[1]);
-
- /* + misc */
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",MaxBackends);
-
- /* + the pstat file names, and postgres pathname */
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_tmpfname);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_fname);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",postgres_exec_path);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",DataDir);
+ av[ac++] = NULL; /* filled in by postmaster_forkexec */
+
+ /* postgres_exec_path is not passed by write_backend_variables */
+ av[ac++] = postgres_exec_path;
+
+ /* Sockets + pipes (those not passed by write_backend_variables) */
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[0]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[1]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[0]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[1]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[0]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[1]);
/* Add to the arg list */
Assert(bufc <= lengthof(pgstatBuf));
for (i = 0; i < bufc; i++)
av[ac++] = pgstatBuf[i];
- av[ac++] = NULL;
- Assert(ac <= lengthof(av));
+ av[ac] = NULL;
+ Assert(ac < lengthof(av));
- /* Fire off execv in child */
-#ifdef WIN32
- pid = win32_forkexec(postgres_exec_path, av);
-#else
- if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
- /* FIXME: [fork/exec] suggestions for what to do here? Can't call elog... */
- abort();
-#endif
- return pid; /* Parent returns pid */
+ return postmaster_forkexec(ac, av);
}
-/* ----------
+/*
* pgstat_parseArgs() -
*
- * Used to unformat the arglist for exec'ed statistics
+ * Extract data from the arglist for exec'ed statistics
* (buffer and collector) processes
- *
*/
static void
-pgstat_parseArgs(PGSTAT_FORK_ARGS)
+pgstat_parseArgs(int argc, char *argv[])
{
- Assert(argc == 14);
-
- if (find_my_exec(argv[0], my_exec_path) < 0)
- elog(FATAL,
- gettext("%s: could not locate my own executable path"),
- argv[0]);
-
- get_pkglib_path(my_exec_path, pkglib_path);
+ Assert(argc == 10);
- argc = 2;
- pgStatSock = atoi(argv[argc++]);
+ argc = 3;
+ StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
pgStatPmPipe[0] = atoi(argv[argc++]);
pgStatPmPipe[1] = atoi(argv[argc++]);
pgStatCollectorPmPipe[0] = atoi(argv[argc++]);
pgStatCollectorPmPipe[1] = atoi(argv[argc++]);
pgStatPipe[0] = atoi(argv[argc++]);
pgStatPipe[1] = atoi(argv[argc++]);
- MaxBackends = atoi(argv[argc++]);
- StrNCpy(pgStat_tmpfname,argv[argc++],MAXPGPATH);
- StrNCpy(pgStat_fname, argv[argc++],MAXPGPATH);
- StrNCpy(postgres_exec_path, argv[argc++],MAXPGPATH);
- DataDir = strdup(argv[argc++]);
-
- read_nondefault_variables();
}
-#endif
+#endif /* EXEC_BACKEND */
+
/* ----------
* pgstat_start() -
@@ -638,7 +598,7 @@ pgstat_start(void)
/* Drop our connection to postmaster's shared memory, as well */
PGSharedMemoryDetach();
- pgstat_main();
+ PgstatBufferMain(0, NULL);
break;
#endif
@@ -1443,26 +1403,20 @@ pgstat_send(void *msg, int len)
}
-/* ------------------------------------------------------------
- * Local functions implementing the statistics collector itself follow
- *------------------------------------------------------------
+/* ----------
+ * PgstatBufferMain() -
+ *
+ * Start up the statistics buffer process. This is the body of the
+ * postmaster child process.
+ *
+ * The argc/argv parameters are valid only in EXEC_BACKEND case.
+ * ----------
*/
-
-static void
-pgstat_mainInit(void)
+NON_EXEC_STATIC void
+PgstatBufferMain(int argc, char *argv[])
{
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
-#ifdef EXEC_BACKEND
- /* In EXEC case we will not have inherited these settings */
- IsPostmasterEnvironment = true;
- whereToSendOutput = None;
-
- /* Setup global context */
- MemoryContextInit(); /* before any elog'ing can occur */
- InitializeGUCOptions();
-#endif
-
MyProcPid = getpid(); /* reset MyProcPid */
/* Lose the postmaster's on-exit routines */
@@ -1485,20 +1439,8 @@ pgstat_mainInit(void)
pqsignal(SIGTTOU, SIG_DFL);
pqsignal(SIGCONT, SIG_DFL);
pqsignal(SIGWINCH, SIG_DFL);
-}
-
+ /* unblock will happen in pgstat_recvbuffer */
-/* ----------
- * pgstat_main() -
- *
- * Start up the statistics collector itself. This is the body of the
- * postmaster child process.
- * ----------
- */
-NON_EXEC_STATIC void
-pgstat_main(PGSTAT_FORK_ARGS)
-{
- pgstat_mainInit(); /* Note: for *both* EXEC_BACKEND and regular cases */
#ifdef EXEC_BACKEND
pgstat_parseArgs(argc,argv);
#endif
@@ -1547,7 +1489,7 @@ pgstat_main(PGSTAT_FORK_ARGS)
#ifndef EXEC_BACKEND
case 0:
/* child becomes collector process */
- pgstat_mainChild();
+ PgstatCollectorMain(0, NULL);
break;
#endif
@@ -1560,8 +1502,17 @@ pgstat_main(PGSTAT_FORK_ARGS)
}
+/* ----------
+ * PgstatCollectorMain() -
+ *
+ * Start up the statistics collector itself. This is the body of the
+ * postmaster grandchild process.
+ *
+ * The argc/argv parameters are valid only in EXEC_BACKEND case.
+ * ----------
+ */
NON_EXEC_STATIC void
-pgstat_mainChild(PGSTAT_FORK_ARGS)
+PgstatCollectorMain(int argc, char *argv[])
{
PgStat_Msg msg;
fd_set rfds;
@@ -1574,30 +1525,53 @@ pgstat_mainChild(PGSTAT_FORK_ARGS)
bool need_statwrite;
HASHCTL hash_ctl;
+ MyProcPid = getpid(); /* reset MyProcPid */
+
+ /*
+ * Reset signal handling. With the exception of restoring default
+ * SIGCHLD handling, this is a no-op in the non-EXEC_BACKEND case
+ * because we'll have inherited these settings from the buffer process;
+ * but it's not a no-op for EXEC_BACKEND.
+ */
+ pqsignal(SIGHUP, SIG_IGN);
+ pqsignal(SIGINT, SIG_IGN);
+ pqsignal(SIGTERM, SIG_IGN);
+ pqsignal(SIGQUIT, SIG_IGN);
+ pqsignal(SIGALRM, SIG_IGN);
+ pqsignal(SIGPIPE, SIG_IGN);
+ pqsignal(SIGUSR1, SIG_IGN);
+ pqsignal(SIGUSR2, SIG_IGN);
+ pqsignal(SIGCHLD, SIG_DFL);
+ pqsignal(SIGTTIN, SIG_DFL);
+ pqsignal(SIGTTOU, SIG_DFL);
+ pqsignal(SIGCONT, SIG_DFL);
+ pqsignal(SIGWINCH, SIG_DFL);
+ PG_SETMASK(&UnBlockSig);
+
#ifdef EXEC_BACKEND
- pgstat_mainInit(); /* Note: only in EXEC_BACKEND case */
pgstat_parseArgs(argc,argv);
-#else
- MyProcPid = getpid(); /* reset MyProcPid */
#endif
+ /* Close unwanted files */
closesocket(pgStatPipe[1]);
closesocket(pgStatSock);
pmPipe = pgStatCollectorPmPipe[0];
/*
- * In the child we can have default SIGCHLD handling (in case we want
- * to call system() here...)
- */
- pqsignal(SIGCHLD, SIG_DFL);
-
- /*
* Identify myself via ps
*/
init_ps_display("stats collector process", "", "");
set_ps_display("");
/*
+ * Initialize filenames needed for status reports.
+ */
+ snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
+ /* tmpfname need only be set correctly in this process */
+ snprintf(pgStat_tmpfname, MAXPGPATH, PGSTAT_STAT_TMPFILE,
+ DataDir, getpid());
+
+ /*
* Arrange to write the initial status file right away
*/
gettimeofday(&next_statwrite, NULL);
@@ -2550,6 +2524,18 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
*betab = NULL;
/*
+ * In EXEC_BACKEND case, we won't have inherited pgStat_fname from
+ * postmaster, so compute it first time through.
+ */
+#ifdef EXEC_BACKEND
+ if (pgStat_fname[0] == '\0')
+ {
+ Assert(DataDir != NULL);
+ snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
+ }
+#endif
+
+ /*
* Try to open the status file. If it doesn't exist, the backends
* simply return zero for anything and the collector simply starts
* from scratch with empty counters.
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 2679ea6bf9b..07812c7b310 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -7,10 +7,10 @@
* message to setup a backend process.
*
* The postmaster also manages system-wide operations such as
- * startup, shutdown, and periodic checkpoints. The postmaster
- * itself doesn't do those operations, mind you --- it just forks
- * off a subprocess to do them at the right times. It also takes
- * care of resetting the system if a backend crashes.
+ * startup and shutdown. The postmaster itself doesn't do those
+ * operations, mind you --- it just forks off a subprocess to do them
+ * at the right times. It also takes care of resetting the system
+ * if a backend crashes.
*
* The postmaster process creates the shared memory and semaphore
* pools during startup, but as a rule does not touch them itself.
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.397 2004/05/27 17:12:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.398 2004/05/28 05:12:58 tgl Exp $
*
* NOTES
*
@@ -113,8 +113,6 @@
#include "pgstat.h"
-#define INVALID_SOCK (-1)
-
#ifdef HAVE_SIGPROCMASK
sigset_t UnBlockSig,
BlockSig,
@@ -177,14 +175,6 @@ static const char *progname = NULL;
#define MAXLISTEN 10
static int ListenSocket[MAXLISTEN];
-/* Used to reduce macros tests */
-#ifdef EXEC_BACKEND
-const bool ExecBackend = true;
-
-#else
-const bool ExecBackend = false;
-#endif
-
/*
* Set by the -o option
*/
@@ -258,7 +248,12 @@ extern int optreset;
/*
* postmaster.c - function prototypes
*/
-static void pmdaemonize(int argc, char *argv[]);
+static void checkDataDir(const char *checkdir);
+#ifdef USE_RENDEZVOUS
+static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode,
+ void *context);
+#endif
+static void pmdaemonize(void);
static Port *ConnCreate(int serverFd);
static void ConnFree(Port *port);
static void reset_shared(unsigned short port);
@@ -270,7 +265,6 @@ static void dummy_handler(SIGNAL_ARGS);
static void CleanupProc(int pid, int exitstatus);
static void LogChildExit(int lev, const char *procname,
int pid, int exitstatus);
-static void BackendInit(Port *port);
static int BackendRun(Port *port);
static void ExitPostmaster(int status);
static void usage(const char *);
@@ -286,7 +280,6 @@ static void RandomSalt(char *cryptSalt, char *md5Salt);
static void SignalChildren(int signal);
static int CountChildren(void);
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
-NON_EXEC_STATIC void SSDataBaseInit(int xlop);
static pid_t SSDataBase(int xlop);
static void
postmaster_error(const char *fmt,...)
@@ -296,8 +289,7 @@ __attribute__((format(printf, 1, 2)));
#ifdef EXEC_BACKEND
#ifdef WIN32
-pid_t win32_forkexec(const char *path, char *argv[]);
-
+static pid_t win32_forkexec(const char *path, char *argv[]);
static void win32_AddChild(pid_t pid, HANDLE handle);
static void win32_RemoveChild(pid_t pid);
static pid_t win32_waitpid(int *exitstatus);
@@ -308,98 +300,26 @@ static HANDLE *win32_childHNDArray;
static unsigned long win32_numChildren = 0;
#endif
-static pid_t Backend_forkexec(Port *port);
+static pid_t backend_forkexec(Port *port);
+static pid_t internal_forkexec(int argc, char *argv[], Port *port);
-static unsigned long tmpBackendFileNum = 0;
-void read_backend_variables(unsigned long id, Port *port);
-static bool write_backend_variables(Port *port);
+static void read_backend_variables(char *filename, Port *port);
+static bool write_backend_variables(char *filename, Port *port);
static void ShmemBackendArrayAdd(Backend *bn);
static void ShmemBackendArrayRemove(pid_t pid);
-#endif
+
+#endif /* EXEC_BACKEND */
#define StartupDataBase() SSDataBase(BS_XLOG_STARTUP)
#define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)
#define StartBackgroundWriter() SSDataBase(BS_XLOG_BGWRITER)
#define ShutdownDataBase() SSDataBase(BS_XLOG_SHUTDOWN)
-static void
-checkDataDir(const char *checkdir)
-{
- char path[MAXPGPATH];
- FILE *fp;
- struct stat stat_buf;
-
- if (checkdir == NULL)
- {
- fprintf(stderr,
- gettext("%s does not know where to find the database system data.\n"
- "You must specify the directory that contains the database system\n"
- "either by specifying the -D invocation option or by setting the\n"
- "PGDATA environment variable.\n"),
- progname);
- ExitPostmaster(2);
- }
-
- if (stat(checkdir, &stat_buf) == -1)
- {
- if (errno == ENOENT)
- ereport(FATAL,
- (errcode_for_file_access(),
- errmsg("data directory \"%s\" does not exist",
- checkdir)));
- else
- ereport(FATAL,
- (errcode_for_file_access(),
- errmsg("could not read permissions of directory \"%s\": %m",
- checkdir)));
- }
-
- /*
- * Check if the directory has group or world access. If so, reject.
- *
- * XXX temporarily suppress check when on Windows, because there may not
- * be proper support for Unix-y file permissions. Need to think of a
- * reasonable check to apply on Windows.
- */
-#if !defined(__CYGWIN__) && !defined(WIN32)
- if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
- ereport(FATAL,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("data directory \"%s\" has group or world access",
- checkdir),
- errdetail("Permissions should be u=rwx (0700).")));
-#endif
-
- /* Look for PG_VERSION before looking for pg_control */
- ValidatePgVersion(checkdir);
-
- snprintf(path, sizeof(path), "%s/global/pg_control", checkdir);
-
- fp = AllocateFile(path, PG_BINARY_R);
- if (fp == NULL)
- {
- fprintf(stderr,
- gettext("%s: could not find the database system\n"
- "Expected to find it in the directory \"%s\",\n"
- "but could not open file \"%s\": %s\n"),
- progname, checkdir, path, strerror(errno));
- ExitPostmaster(2);
- }
- FreeFile(fp);
-}
-
-
-#ifdef USE_RENDEZVOUS
-
-/* reg_reply -- empty callback function for DNSServiceRegistrationCreate() */
-static void
-reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
-{
-
-}
-#endif
+/*
+ * Postmaster main entry point
+ */
int
PostmasterMain(int argc, char *argv[])
{
@@ -462,8 +382,7 @@ PostmasterMain(int argc, char *argv[])
IgnoreSystemIndexes(false);
if (find_my_exec(argv[0], my_exec_path) < 0)
- elog(FATAL,
- gettext("%s: could not locate my own executable path"),
+ elog(FATAL, "%s: could not locate my own executable path",
argv[0]);
get_pkglib_path(my_exec_path, pkglib_path);
@@ -700,9 +619,10 @@ PostmasterMain(int argc, char *argv[])
}
#ifdef EXEC_BACKEND
- if (find_other_exec(argv[0], "postgres", PG_VERSIONSTR, postgres_exec_path) < 0)
+ if (find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
+ postgres_exec_path) < 0)
ereport(FATAL,
- (errmsg("%s: could not locate postgres executable or non-matching version",
+ (errmsg("%s: could not locate matching postgres executable",
progname)));
#endif
@@ -728,7 +648,7 @@ PostmasterMain(int argc, char *argv[])
* will show the wrong PID.
*/
if (SilentMode)
- pmdaemonize(argc, argv);
+ pmdaemonize();
/*
* Create lockfile for data directory.
@@ -945,8 +865,96 @@ PostmasterMain(int argc, char *argv[])
return 0; /* not reached */
}
+
+/*
+ * Validate the proposed data directory
+ */
+static void
+checkDataDir(const char *checkdir)
+{
+ char path[MAXPGPATH];
+ FILE *fp;
+ struct stat stat_buf;
+
+ if (checkdir == NULL)
+ {
+ fprintf(stderr,
+ gettext("%s does not know where to find the database system data.\n"
+ "You must specify the directory that contains the database system\n"
+ "either by specifying the -D invocation option or by setting the\n"
+ "PGDATA environment variable.\n"),
+ progname);
+ ExitPostmaster(2);
+ }
+
+ if (stat(checkdir, &stat_buf) == -1)
+ {
+ if (errno == ENOENT)
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("data directory \"%s\" does not exist",
+ checkdir)));
+ else
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not read permissions of directory \"%s\": %m",
+ checkdir)));
+ }
+
+ /*
+ * Check if the directory has group or world access. If so, reject.
+ *
+ * XXX temporarily suppress check when on Windows, because there may not
+ * be proper support for Unix-y file permissions. Need to think of a
+ * reasonable check to apply on Windows.
+ */
+#if !defined(__CYGWIN__) && !defined(WIN32)
+ if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+ ereport(FATAL,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("data directory \"%s\" has group or world access",
+ checkdir),
+ errdetail("Permissions should be u=rwx (0700).")));
+#endif
+
+ /* Look for PG_VERSION before looking for pg_control */
+ ValidatePgVersion(checkdir);
+
+ snprintf(path, sizeof(path), "%s/global/pg_control", checkdir);
+
+ fp = AllocateFile(path, PG_BINARY_R);
+ if (fp == NULL)
+ {
+ fprintf(stderr,
+ gettext("%s: could not find the database system\n"
+ "Expected to find it in the directory \"%s\",\n"
+ "but could not open file \"%s\": %s\n"),
+ progname, checkdir, path, strerror(errno));
+ ExitPostmaster(2);
+ }
+ FreeFile(fp);
+}
+
+
+#ifdef USE_RENDEZVOUS
+
+/*
+ * empty callback function for DNSServiceRegistrationCreate()
+ */
+static void
+reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
+{
+
+}
+
+#endif /* USE_RENDEZVOUS */
+
+
+/*
+ * Fork away from the controlling terminal (-S option)
+ */
static void
-pmdaemonize(int argc, char *argv[])
+pmdaemonize(void)
{
#ifdef WIN32
/* not supported */
@@ -960,7 +968,7 @@ pmdaemonize(int argc, char *argv[])
#endif
#ifdef LINUX_PROFILE
- /* see comments in BackendRun */
+ /* see comments in BackendStartup */
getitimer(ITIMER_PROF, &prof_itimer);
#endif
@@ -1003,7 +1011,6 @@ pmdaemonize(int argc, char *argv[])
}
-
/*
* Print out help message
*/
@@ -1044,6 +1051,10 @@ usage(const char *progname)
"Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}
+
+/*
+ * Main loop of postmaster
+ */
static int
ServerLoop(void)
{
@@ -1194,7 +1205,6 @@ ServerLoop(void)
* Initialise the masks for select() for the ports
* we are listening on. Return the number of sockets to listen on.
*/
-
static int
initMasks(fd_set *rmask)
{
@@ -1524,10 +1534,8 @@ processCancelRequest(Port *port, void *pkt)
int backendPID;
long cancelAuthCode;
Backend *bp;
-
#ifndef EXEC_BACKEND
Dlelem *curr;
-
#else
int i;
#endif
@@ -1550,7 +1558,11 @@ processCancelRequest(Port *port, void *pkt)
return;
}
- /* See if we have a matching backend */
+ /*
+ * See if we have a matching backend. In the EXEC_BACKEND case, we
+ * can no longer access the postmaster's own backend list, and must
+ * rely on the backup array in shared memory.
+ */
#ifndef EXEC_BACKEND
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
{
@@ -1728,13 +1740,15 @@ SIGHUP_handler(SIGNAL_ARGS)
ereport(LOG,
(errmsg("received SIGHUP, reloading configuration files")));
ProcessConfigFile(PGC_SIGHUP);
-#ifdef EXEC_BACKEND
- write_nondefault_variables(PGC_SIGHUP);
-#endif
SignalChildren(SIGHUP);
load_hba();
load_ident();
+#ifdef EXEC_BACKEND
+ /* Update the starting-point file for future children */
+ write_nondefault_variables(PGC_SIGHUP);
+#endif
+
/*
* Tell the background writer to terminate so that we will start a
* new one with a possibly changed config
@@ -1749,7 +1763,6 @@ SIGHUP_handler(SIGNAL_ARGS)
}
-
/*
* pmdie -- signal handler for processing various postmaster signals.
*/
@@ -2249,6 +2262,9 @@ BackendStartup(Port *port)
return STATUS_ERROR;
}
+ /* Pass down canAcceptConnections state (kluge for EXEC_BACKEND case) */
+ port->canAcceptConnections = canAcceptConnections();
+
/*
* Flush stdio channels just before fork, to avoid double-output
* problems. Ideally we'd use fflush(NULL) here, but there are still a
@@ -2260,6 +2276,12 @@ BackendStartup(Port *port)
fflush(stdout);
fflush(stderr);
+#ifdef EXEC_BACKEND
+
+ pid = backend_forkexec(port);
+
+#else /* !EXEC_BACKEND */
+
#ifdef LINUX_PROFILE
/*
@@ -2277,10 +2299,6 @@ BackendStartup(Port *port)
beos_before_backend_startup();
#endif
- port->canAcceptConnections = canAcceptConnections();
-#ifdef EXEC_BACKEND
- pid = Backend_forkexec(port);
-#else
pid = fork();
if (pid == 0) /* child */
@@ -2297,11 +2315,12 @@ BackendStartup(Port *port)
proc_exit(BackendRun(port));
}
-#endif
- /* in parent, error */
+#endif /* EXEC_BACKEND */
+
if (pid < 0)
{
+ /* in parent, fork failed */
int save_errno = errno;
#ifdef __BEOS__
@@ -2316,7 +2335,7 @@ BackendStartup(Port *port)
return STATUS_ERROR;
}
- /* in parent, normal */
+ /* in parent, successful fork */
ereport(DEBUG2,
(errmsg_internal("forked new backend, pid=%d socket=%d",
(int) pid, port->sock)));
@@ -2392,16 +2411,15 @@ split_opts(char **argv, int *argcp, char *s)
/*
- * BackendInit/Run -- perform authentication [BackendInit], and if successful,
- * set up the backend's argument list [BackendRun] and invoke
- * backend main()
+ * BackendRun -- perform authentication, and if successful,
+ * set up the backend's argument list and invoke PostgresMain()
*
* returns:
* Shouldn't return at all.
* If PostgresMain() fails, return status.
*/
-static void
-BackendInit(Port *port)
+static int
+BackendRun(Port *port)
{
int status;
struct timeval now;
@@ -2409,10 +2427,20 @@ BackendInit(Port *port)
char remote_host[NI_MAXHOST];
char remote_port[NI_MAXSERV];
char remote_ps_data[NI_MAXHOST];
+ char **av;
+ int maxac;
+ int ac;
+ char debugbuf[32];
+ char protobuf[32];
+ int i;
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
- ClientAuthInProgress = true; /* limit visibility of log messages */
+ /*
+ * Let's clean up ourselves as the postmaster child, and close the
+ * postmaster's other sockets
+ */
+ ClosePostmasterPorts(true);
/* We don't want the postmaster's proc_exit() handlers */
on_exit_reset();
@@ -2421,6 +2449,24 @@ BackendInit(Port *port)
* Signal handlers setting is moved to tcop/postgres...
*/
+ /* Save port etc. for ps status */
+ MyProcPort = port;
+
+ /* Reset MyProcPid to new backend's pid */
+ MyProcPid = getpid();
+
+ /*
+ * PreAuthDelay is a debugging aid for investigating problems in the
+ * authentication cycle: it can be set in postgresql.conf to allow
+ * time to attach to the newly-forked backend with a debugger. (See
+ * also the -W backend switch, which we allow clients to pass through
+ * PGOPTIONS, but it is not honored until after authentication.)
+ */
+ if (PreAuthDelay > 0)
+ pg_usleep(PreAuthDelay * 1000000L);
+
+ ClientAuthInProgress = true; /* limit visibility of log messages */
+
/* save start time for end of session reporting */
gettimeofday(&(port->session_start), NULL);
@@ -2429,12 +2475,6 @@ BackendInit(Port *port)
port->remote_port = "";
port->commandTag = "";
- /* Save port etc. for ps status */
- MyProcPort = port;
-
- /* Reset MyProcPid to new backend's pid */
- MyProcPid = getpid();
-
/*
* Initialize libpq and enable reporting of ereport errors to the
* client. Must do this now because authentication uses libpq to send
@@ -2490,6 +2530,29 @@ BackendInit(Port *port)
port->remote_port = strdup(remote_port);
/*
+ * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.c
+ * etcetera from the postmaster, and have to load them ourselves.
+ * Build the PostmasterContext (which didn't exist before, in this
+ * process) to contain the data.
+ *
+ * FIXME: [fork/exec] Ugh. Is there a way around this overhead?
+ */
+#ifdef EXEC_BACKEND
+ Assert(PostmasterContext == NULL);
+ PostmasterContext = AllocSetContextCreate(TopMemoryContext,
+ "Postmaster",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ MemoryContextSwitchTo(PostmasterContext);
+
+ load_hba();
+ load_ident();
+ load_user();
+ load_group();
+#endif
+
+ /*
* Ready to begin client interaction. We will give up and exit(0)
* after a time delay, so that a broken client can't hog a connection
* indefinitely. PreAuthDelay doesn't count against the time limit.
@@ -2540,37 +2603,6 @@ BackendInit(Port *port)
random_seed = 0;
gettimeofday(&now, &tz);
srandom((unsigned int) now.tv_usec);
-}
-
-
-static int
-BackendRun(Port *port)
-{
- char **av;
- int maxac;
- int ac;
- char debugbuf[32];
- char protobuf[32];
- int i;
-
- /*
- * Let's clean up ourselves as the postmaster child, and close the
- * postmaster's other sockets
- */
- ClosePostmasterPorts(true);
-
- /*
- * PreAuthDelay is a debugging aid for investigating problems in the
- * authentication cycle: it can be set in postgresql.conf to allow
- * time to attach to the newly-forked backend with a debugger. (See
- * also the -W backend switch, which we allow clients to pass through
- * PGOPTIONS, but it is not honored until after authentication.)
- */
- if (PreAuthDelay > 0)
- pg_usleep(PreAuthDelay * 1000000L);
-
- /* Will exit on failure */
- BackendInit(port);
/* ----------------
@@ -2607,7 +2639,8 @@ BackendRun(Port *port)
/*
* Pass any backend switches specified with -o in the postmaster's own
- * command line. We assume these are secure.
+ * command line. We assume these are secure. (It's OK to mangle
+ * ExtraOptions now, since we're safely inside a subprocess.)
*/
split_opts(av, &ac, ExtraOptions);
@@ -2615,12 +2648,6 @@ BackendRun(Port *port)
snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto);
av[ac++] = protobuf;
-#ifdef EXEC_BACKEND
- /* pass data dir before end of secure switches (-p) */
- av[ac++] = "-D";
- av[ac++] = DataDir;
-#endif
-
/*
* Tell the backend it is being called from the postmaster, and which
* database to use. -p marks the end of secure switches.
@@ -2647,9 +2674,7 @@ BackendRun(Port *port)
* username isn't lost either; see ProcessStartupPacket().
*/
MemoryContextSwitchTo(TopMemoryContext);
-#ifndef EXEC_BACKEND
MemoryContextDelete(PostmasterContext);
-#endif
PostmasterContext = NULL;
/*
@@ -2673,111 +2698,176 @@ BackendRun(Port *port)
#ifdef EXEC_BACKEND
-
/*
- * SubPostmasterMain -- prepare the fork/exec'd process to be in an equivalent
- * state (for calling BackendRun) as a forked process.
+ * postmaster_forkexec -- fork and exec a postmaster subprocess
*
- * returns:
- * Shouldn't return at all.
+ * The caller must have set up the argv array already, except for argv[2]
+ * which will be filled with the name of the temp variable file.
+ *
+ * Returns the child process PID, or -1 on fork failure (a suitable error
+ * message has been logged on failure).
+ *
+ * All uses of this routine will dispatch to SubPostmasterMain in the
+ * child process.
*/
-void
-SubPostmasterMain(int argc, char *argv[])
+pid_t
+postmaster_forkexec(int argc, char *argv[])
{
- unsigned long backendID;
Port port;
- memset((void *) &port, 0, sizeof(Port));
- Assert(argc == 2);
+ /* This entry point passes dummy values for the Port variables */
+ memset(&port, 0, sizeof(port));
+ return internal_forkexec(argc, argv, &port);
+}
- /* Do this sooner rather than later... */
- IsUnderPostmaster = true; /* we are a postmaster subprocess now */
+/*
+ * backend_forkexec -- fork/exec off a backend process
+ *
+ * returns the pid of the fork/exec'd process, or -1 on failure
+ */
+static pid_t
+backend_forkexec(Port *port)
+{
+ char *av[4];
+ int ac = 0;
- /* In EXEC case we will not have inherited these settings */
- IsPostmasterEnvironment = true;
- whereToSendOutput = None;
+ av[ac++] = "postgres";
+ av[ac++] = "-forkbackend";
+ av[ac++] = NULL; /* filled in by internal_forkexec */
- /* Setup global context */
- MemoryContextInit();
- InitializeGUCOptions();
+ av[ac] = NULL;
+ Assert(ac < lengthof(av));
- /* Parse passed-in context */
- argc = 0;
- backendID = (unsigned long) atol(argv[argc++]);
- DataDir = strdup(argv[argc++]);
+ return internal_forkexec(ac, av, port);
+}
- /* Read in file-based context */
- read_backend_variables(backendID, &port);
- read_nondefault_variables();
+static pid_t
+internal_forkexec(int argc, char *argv[], Port *port)
+{
+ pid_t pid;
+ char tmpfilename[MAXPGPATH];
- /* Remaining initialization */
- pgstat_init_forkexec_backend();
+ if (!write_backend_variables(tmpfilename, port))
+ return -1; /* log made by write_backend_variables */
- /* FIXME: [fork/exec] Ugh */
- load_hba();
- load_ident();
- load_user();
- load_group();
+ /* Make sure caller set up argv properly */
+ Assert(argc >= 3);
+ Assert(argv[argc] == NULL);
+ Assert(strncmp(argv[1], "-fork", 5) == 0);
+ Assert(argv[2] == NULL);
- /* Attach process to shared segments */
- CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+ /* Insert temp file name after -fork argument */
+ argv[2] = tmpfilename;
- /* Run backend */
- proc_exit(BackendRun(&port));
-}
+#ifdef WIN32
+ pid = win32_forkexec(postgres_exec_path, argv);
+#else
+ /* Fire off execv in child */
+ if ((pid = fork()) == 0)
+ {
+ if (execv(postgres_exec_path, argv) < 0)
+ {
+ ereport(LOG,
+ (errmsg("could not exec backend process \"%s\": %m",
+ postgres_exec_path)));
+ /* We're already in the child process here, can't return */
+ exit(1);
+ }
+ }
+#endif
+ return pid; /* Parent returns pid, or -1 on fork failure */
+}
/*
- * Backend_forkexec -- fork/exec off a backend process
+ * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent
+ * to what it would be if we'd simply forked on Unix, and then
+ * dispatch to the appropriate place.
*
- * returns:
- * the pid of the fork/exec'd process
+ * The first two command line arguments are expected to be "-forkFOO"
+ * (where FOO indicates which postmaster child we are to become), and
+ * the name of a variables file that we can read to load data that would
+ * have been inherited by fork() on Unix. Remaining arguments go to the
+ * subprocess FooMain() routine.
*/
-static pid_t
-Backend_forkexec(Port *port)
+int
+SubPostmasterMain(int argc, char *argv[])
{
- pid_t pid;
- char *av[5];
- int ac = 0,
- bufc = 0,
- i;
- char buf[2][MAXPGPATH];
+ Port port;
- if (!write_backend_variables(port))
- return -1; /* log made by write_backend_variables */
+ /* Do this sooner rather than later... */
+ IsUnderPostmaster = true; /* we are a postmaster subprocess now */
- av[ac++] = "postgres";
- av[ac++] = "-forkexec";
+ MyProcPid = getpid(); /* reset MyProcPid */
- /* Format up context to pass to exec'd process */
- snprintf(buf[bufc++], MAXPGPATH, "%lu", tmpBackendFileNum);
- snprintf(buf[bufc++], MAXPGPATH, "\"%s\"", DataDir);
+ /* In EXEC_BACKEND case we will not have inherited these settings */
+ IsPostmasterEnvironment = true;
+ whereToSendOutput = None;
+ pqinitmask();
+ PG_SETMASK(&BlockSig);
- /* Add to the arg list */
- Assert(bufc <= lengthof(buf));
- for (i = 0; i < bufc; i++)
- av[ac++] = buf[i];
+ /* Setup essential subsystems */
+ MemoryContextInit();
+ InitializeGUCOptions();
- /* FIXME: [fork/exec] ExtraOptions? */
+ /* Check we got appropriate args */
+ if (argc < 3)
+ elog(FATAL, "invalid subpostmaster invocation");
- av[ac++] = NULL;
- Assert(ac <= lengthof(av));
+ /* Read in file-based context */
+ memset(&port, 0, sizeof(Port));
+ read_backend_variables(argv[2], &port);
+ read_nondefault_variables();
-#ifdef WIN32
- pid = win32_forkexec(postgres_exec_path, av); /* logs on error */
-#else
- /* Fire off execv in child */
- if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
+ /* Run backend or appropriate child */
+ if (strcmp(argv[1], "-forkbackend") == 0)
+ {
+ /* BackendRun will close sockets */
+
+ /* Attach process to shared segments */
+ CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+ Assert(argc == 3); /* shouldn't be any more args */
+ proc_exit(BackendRun(&port));
+ }
+ if (strcmp(argv[1], "-forkboot") == 0)
+ {
+ /* Close the postmaster's sockets */
+ ClosePostmasterPorts(true);
+
+ /* Attach process to shared segments */
+ CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+
+ BootstrapMain(argc - 2, argv + 2);
+ ExitPostmaster(0);
+ }
+ if (strcmp(argv[1], "-forkbuf") == 0)
+ {
+ /* Close the postmaster's sockets */
+ ClosePostmasterPorts(false);
+
+ /* Do not want to attach to shared memory */
+
+ PgstatBufferMain(argc, argv);
+ ExitPostmaster(0);
+ }
+ if (strcmp(argv[1], "-forkcol") == 0)
+ {
/*
- * FIXME: [fork/exec] suggestions for what to do here? Probably OK
- * to issue error (unlike pgstat case)
+ * Do NOT close postmaster sockets here, because we are forking from
+ * pgstat buffer process, which already did it.
*/
- abort();
-#endif
- return pid; /* Parent returns pid */
+
+ /* Do not want to attach to shared memory */
+
+ PgstatCollectorMain(argc, argv);
+ ExitPostmaster(0);
+ }
+
+ return 1; /* shouldn't get here */
}
-#endif
+
+#endif /* EXEC_BACKEND */
/*
@@ -2984,80 +3074,61 @@ CountChildren(void)
return cnt;
}
+
/*
- * Fire off a subprocess for startup/shutdown/checkpoint/bgwriter.
+ * SSDataBase -- start a non-backend child process for the postmaster
*
- * Return value of SSDataBase is subprocess' PID, or 0 if failed to start subprocess
- * (0 is returned only for checkpoint/bgwriter cases).
+ * xlog determines what kind of child will be started. All child types
+ * initially go to BootstrapMain, which will handle common setup.
*
- * note: in the EXEC_BACKEND case, we delay the fork until argument list has been
- * established
+ * Return value of SSDataBase is subprocess' PID, or 0 if failed to start
+ * subprocess (0 is returned only for checkpoint/bgwriter cases).
*/
-NON_EXEC_STATIC void
-SSDataBaseInit(int xlop)
+static pid_t
+SSDataBase(int xlop)
{
- const char *statmsg;
+ Backend *bn;
+ pid_t pid;
+ char *av[10];
+ int ac = 0;
+ char xlbuf[32];
+#ifdef LINUX_PROFILE
+ struct itimerval prof_itimer;
+#endif
- IsUnderPostmaster = true; /* we are a postmaster subprocess now */
+ /*
+ * Set up command-line arguments for subprocess
+ */
+ av[ac++] = "postgres";
#ifdef EXEC_BACKEND
- /* In EXEC case we will not have inherited these settings */
- IsPostmasterEnvironment = true;
- whereToSendOutput = None;
+ av[ac++] = "-forkboot";
+ av[ac++] = NULL; /* filled in by postmaster_forkexec */
#endif
- MyProcPid = getpid(); /* reset MyProcPid */
+ snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop);
+ av[ac++] = xlbuf;
- /* Lose the postmaster's on-exit routines and port connections */
- on_exit_reset();
+ av[ac++] = "-p";
+ av[ac++] = "template1";
+
+ av[ac] = NULL;
+ Assert(ac < lengthof(av));
/*
- * Identify myself via ps
+ * Flush stdio channels (see comments in BackendStartup)
*/
- switch (xlop)
- {
- case BS_XLOG_STARTUP:
- statmsg = "startup subprocess";
- break;
- case BS_XLOG_CHECKPOINT:
- statmsg = "checkpoint subprocess";
- break;
- case BS_XLOG_BGWRITER:
- statmsg = "bgwriter subprocess";
- break;
- case BS_XLOG_SHUTDOWN:
- statmsg = "shutdown subprocess";
- break;
- default:
- statmsg = "??? subprocess";
- break;
- }
- init_ps_display(statmsg, "", "");
- set_ps_display("");
-}
-
+ fflush(stdout);
+ fflush(stderr);
-static pid_t
-SSDataBase(int xlop)
-{
- pid_t pid;
- Backend *bn;
+#ifdef EXEC_BACKEND
-#ifndef EXEC_BACKEND
-#ifdef LINUX_PROFILE
- struct itimerval prof_itimer;
-#endif
-#else
- char idbuf[32];
- char ddirbuf[MAXPGPATH];
-#endif
+ pid = postmaster_forkexec(ac, av);
- fflush(stdout);
- fflush(stderr);
+#else /* !EXEC_BACKEND */
-#ifndef EXEC_BACKEND
#ifdef LINUX_PROFILE
- /* see comments in BackendRun */
+ /* see comments in BackendStartup */
getitimer(ITIMER_PROF, &prof_itimer);
#endif
@@ -3066,16 +3137,10 @@ SSDataBase(int xlop)
beos_before_backend_startup();
#endif
- /* Non EXEC_BACKEND case; fork here */
- if ((pid = fork()) == 0) /* child */
-#endif
- {
- char *av[10];
- int ac = 0;
- char nbbuf[32];
- char xlbuf[32];
+ pid = fork();
-#ifndef EXEC_BACKEND
+ if (pid == 0) /* child */
+ {
#ifdef LINUX_PROFILE
setitimer(ITIMER_PROF, &prof_itimer, NULL);
#endif
@@ -3085,72 +3150,30 @@ SSDataBase(int xlop)
beos_backend_startup();
#endif
+ IsUnderPostmaster = true; /* we are a postmaster subprocess now */
+
/* Close the postmaster's sockets */
ClosePostmasterPorts(true);
- SSDataBaseInit(xlop);
-#else
- if (!write_backend_variables(NULL))
- return -1; /* log issued by write_backend_variables */
-#endif
-
- /* Set up command-line arguments for subprocess */
- av[ac++] = "postgres";
-
-#ifdef EXEC_BACKEND
- av[ac++] = "-boot";
-#endif
- snprintf(nbbuf, sizeof(nbbuf), "-B%d", NBuffers);
- av[ac++] = nbbuf;
-
- snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop);
- av[ac++] = xlbuf;
-
-#ifdef EXEC_BACKEND
- /* pass data dir before end of secure switches (-p) */
- snprintf(ddirbuf, MAXPGPATH, "\"%s\"", DataDir);
- av[ac++] = "-D";
- av[ac++] = ddirbuf;
-
- /* and the backend identifier + dbname */
- snprintf(idbuf, sizeof(idbuf), "-p%lu,template1", tmpBackendFileNum);
- av[ac++] = idbuf;
-#else
- av[ac++] = "-p";
- av[ac++] = "template1";
-#endif
+ /* Lose the postmaster's on-exit routines and port connections */
+ on_exit_reset();
- av[ac] = NULL;
-
- Assert(ac < lengthof(av));
-
-#ifdef EXEC_BACKEND
- /* EXEC_BACKEND case; fork/exec here */
-#ifdef WIN32
- pid = win32_forkexec(postgres_exec_path, av); /* logs on error */
-#else
- if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
- {
- /* in child */
- elog(ERROR, "unable to execv in SSDataBase: %m");
- exit(0);
- }
-#endif
-#else
BootstrapMain(ac, av);
ExitPostmaster(0);
-#endif
}
- /* in parent */
+#endif /* EXEC_BACKEND */
+
if (pid < 0)
{
-#ifndef EXEC_BACKEND
+ /* in parent, fork failed */
+ int save_errno = errno;
+
#ifdef __BEOS__
/* Specific beos actions before backend startup */
beos_backend_startup_failed();
#endif
-#endif
+ errno = save_errno;
switch (xlop)
{
case BS_XLOG_STARTUP:
@@ -3188,6 +3211,8 @@ SSDataBase(int xlop)
}
/*
+ * in parent, successful fork
+ *
* The startup and shutdown processes are not considered normal
* backends, but the checkpoint and bgwriter processes are. They must
* be added to the list of backends.
@@ -3280,7 +3305,7 @@ postmaster_error(const char *fmt,...)
* functions
*/
#include "storage/spin.h"
-extern XLogwrtResult LogwrtResult;
+
extern slock_t *ShmemLock;
extern slock_t *ShmemIndexLock;
extern void *ShmemIndexAlloc;
@@ -3291,24 +3316,19 @@ extern int pgStatSock;
#define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp)
#define read_var(var,fp) fread((void*)&(var),sizeof(var),1,fp)
-#define get_tmp_backend_file_name(buf,id) \
- do { \
- Assert(DataDir); \
- sprintf((buf), \
- "%s/%s/%s.backend_var.%lu", \
- DataDir, \
- PG_TEMP_FILES_DIR, \
- PG_TEMP_FILE_PREFIX, \
- (id)); \
- } while (0)
static bool
-write_backend_variables(Port *port)
+write_backend_variables(char *filename, Port *port)
{
- char filename[MAXPGPATH];
+ static unsigned long tmpBackendFileNum = 0;
FILE *fp;
+ char str_buf[MAXPGPATH];
- get_tmp_backend_file_name(filename, ++tmpBackendFileNum);
+ /* Calculate name for temp file in caller's buffer */
+ Assert(DataDir);
+ snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%lu",
+ DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
+ ++tmpBackendFileNum);
/* Open file */
fp = AllocateFile(filename, PG_BINARY_W);
@@ -3317,33 +3337,38 @@ write_backend_variables(Port *port)
/* As per OpenTemporaryFile... */
char dirname[MAXPGPATH];
- sprintf(dirname, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
+ snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
mkdir(dirname, S_IRWXU);
fp = AllocateFile(filename, PG_BINARY_W);
if (!fp)
{
- ereport(ERROR,
+ ereport(LOG,
(errcode_for_file_access(),
- errmsg("could not write to file \"%s\": %m", filename)));
+ errmsg("could not create file \"%s\": %m",
+ filename)));
return false;
}
}
/* Write vars */
- if (port)
- {
- write_var(port->sock, fp);
- write_var(port->proto, fp);
- write_var(port->laddr, fp);
- write_var(port->raddr, fp);
- write_var(port->canAcceptConnections, fp);
- write_var(port->cryptSalt, fp);
- write_var(port->md5Salt, fp);
- }
- write_var(MyCancelKey, fp);
+ write_var(port->sock, fp);
+ write_var(port->proto, fp);
+ write_var(port->laddr, fp);
+ write_var(port->raddr, fp);
+ write_var(port->canAcceptConnections, fp);
+ write_var(port->cryptSalt, fp);
+ write_var(port->md5Salt, fp);
+
+ /*
+ * XXX FIXME later: writing these strings as MAXPGPATH bytes always is
+ * probably a waste of resources
+ */
- write_var(LogwrtResult, fp);
+ StrNCpy(str_buf, DataDir, MAXPGPATH);
+ fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+
+ write_var(MyCancelKey, fp);
write_var(UsedShmemSegID, fp);
write_var(UsedShmemSegAddr, fp);
@@ -3358,12 +3383,18 @@ write_backend_variables(Port *port)
write_var(ProcStructLock, fp);
write_var(pgStatSock, fp);
- write_var(PreAuthDelay, fp);
write_var(debug_flag, fp);
write_var(PostmasterPid, fp);
fwrite((void *) my_exec_path, MAXPGPATH, 1, fp);
+ fwrite((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
+
+ StrNCpy(str_buf, setlocale(LC_COLLATE, NULL), MAXPGPATH);
+ fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+ StrNCpy(str_buf, setlocale(LC_CTYPE, NULL), MAXPGPATH);
+ fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+
/* Release file */
if (FreeFile(fp))
{
@@ -3376,38 +3407,33 @@ write_backend_variables(Port *port)
return true;
}
-void
-read_backend_variables(unsigned long id, Port *port)
+static void
+read_backend_variables(char *filename, Port *port)
{
- char filename[MAXPGPATH];
FILE *fp;
-
- get_tmp_backend_file_name(filename, id);
+ char str_buf[MAXPGPATH];
/* Open file */
fp = AllocateFile(filename, PG_BINARY_R);
if (!fp)
- {
- ereport(ERROR,
+ ereport(FATAL,
(errcode_for_file_access(),
- errmsg("could not read from backend_variables file \"%s\": %m", filename)));
- return;
- }
+ errmsg("could not read from backend variables file \"%s\": %m",
+ filename)));
/* Read vars */
- if (port)
- {
- read_var(port->sock, fp);
- read_var(port->proto, fp);
- read_var(port->laddr, fp);
- read_var(port->raddr, fp);
- read_var(port->canAcceptConnections, fp);
- read_var(port->cryptSalt, fp);
- read_var(port->md5Salt, fp);
- }
- read_var(MyCancelKey, fp);
+ read_var(port->sock, fp);
+ read_var(port->proto, fp);
+ read_var(port->laddr, fp);
+ read_var(port->raddr, fp);
+ read_var(port->canAcceptConnections, fp);
+ read_var(port->cryptSalt, fp);
+ read_var(port->md5Salt, fp);
- read_var(LogwrtResult, fp);
+ fread((void *) str_buf, MAXPGPATH, 1, fp);
+ SetDataDir(str_buf);
+
+ read_var(MyCancelKey, fp);
read_var(UsedShmemSegID, fp);
read_var(UsedShmemSegAddr, fp);
@@ -3422,12 +3448,18 @@ read_backend_variables(unsigned long id, Port *port)
read_var(ProcStructLock, fp);
read_var(pgStatSock, fp);
- read_var(PreAuthDelay, fp);
read_var(debug_flag, fp);
read_var(PostmasterPid, fp);
fread((void *) my_exec_path, MAXPGPATH, 1, fp);
+ fread((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
+
+ fread((void *) str_buf, MAXPGPATH, 1, fp);
+ setlocale(LC_COLLATE, str_buf);
+ fread((void *) str_buf, MAXPGPATH, 1, fp);
+ setlocale(LC_CTYPE, str_buf);
+
/* Release file */
FreeFile(fp);
if (unlink(filename) != 0)
@@ -3490,52 +3522,54 @@ ShmemBackendArrayRemove(pid_t pid)
(errmsg_internal("unable to find backend entry with pid %d",
pid)));
}
-#endif
+
+#endif /* EXEC_BACKEND */
+
#ifdef WIN32
-pid_t
+static pid_t
win32_forkexec(const char *path, char *argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
char *p;
int i;
- char cmdLine[MAXPGPATH];
+ int j;
+ char cmdLine[MAXPGPATH * 2];
HANDLE childHandleCopy;
HANDLE waiterThread;
/* Format the cmd line */
- snprintf(cmdLine, sizeof(cmdLine), "\"%s\"", path);
+ cmdline[sizeof(cmdLine)-1] = '\0';
+ cmdline[sizeof(cmdLine)-2] = '\0';
+ snprintf(cmdLine, sizeof(cmdLine)-1, "\"%s\"", path);
i = 0;
while (argv[++i] != NULL)
{
- /* FIXME: [fork/exec] some strlen checks might be prudent here */
- strcat(cmdLine, " ");
- strcat(cmdLine, argv[i]);
+ j = strlen(cmdLine);
+ snprintf(cmdLine+j, sizeof(cmdLine)-1-j, " \"%s\"", argv[i]);
+ }
+ if (cmdline[sizeof(cmdLine)-2] != '\0')
+ {
+ elog(LOG, "subprocess command line too long");
+ return -1;
}
-
- /*
- * The following snippet can disappear when we consistently use
- * forward slashes.
- */
- p = cmdLine;
- while (*(p++) != '\0')
- if (*p == '/')
- *p = '\\';
memset(&pi, 0, sizeof(pi));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
- elog(ERROR, "CreateProcess call failed (%i): %m", (int) GetLastError());
+ elog(LOG, "CreateProcess call failed (%d): %m", (int) GetLastError());
return -1;
}
if (!IsUnderPostmaster)
+ {
/* We are the Postmaster creating a child... */
win32_AddChild(pi.dwProcessId, pi.hProcess);
+ }
if (!DuplicateHandle(GetCurrentProcess(),
pi.hProcess,
@@ -3545,11 +3579,15 @@ win32_forkexec(const char *path, char *argv[])
FALSE,
DUPLICATE_SAME_ACCESS))
ereport(FATAL,
- (errmsg_internal("failed to duplicate child handle: %i", (int) GetLastError())));
- waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter, (LPVOID) childHandleCopy, 0, NULL);
+ (errmsg_internal("failed to duplicate child handle: %d",
+ (int) GetLastError())));
+
+ waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter,
+ (LPVOID) childHandleCopy, 0, NULL);
if (!waiterThread)
ereport(FATAL,
- (errmsg_internal("failed to create sigchld waiter thread: %i", (int) GetLastError())));
+ (errmsg_internal("failed to create sigchld waiter thread: %d",
+ (int) GetLastError())));
CloseHandle(waiterThread);
if (IsUnderPostmaster)
@@ -3582,7 +3620,7 @@ win32_AddChild(pid_t pid, HANDLE handle)
else
ereport(FATAL,
(errmsg_internal("unable to add child entry with pid %lu",
- pid)));
+ (unsigned long) pid)));
}
static void
@@ -3608,7 +3646,7 @@ win32_RemoveChild(pid_t pid)
ereport(WARNING,
(errmsg_internal("unable to find child entry with pid %lu",
- pid)));
+ (unsigned long) pid)));
}
static pid_t
@@ -3678,9 +3716,10 @@ win32_sigchld_waiter(LPVOID param)
if (r == WAIT_OBJECT_0)
pg_queue_signal(SIGCHLD);
else
- fprintf(stderr, "ERROR: Failed to wait on child process handle: %i\n", (int) GetLastError());
+ fprintf(stderr, "ERROR: Failed to wait on child process handle: %i\n",
+ (int) GetLastError());
CloseHandle(procHandle);
return 0;
}
-#endif
+#endif /* WIN32 */
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 440b25ae512..25656f74448 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/buf_init.c,v 1.65 2004/04/22 07:21:55 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/buf_init.c,v 1.66 2004/05/28 05:13:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -93,15 +93,6 @@ InitBufferPool(void)
foundDescs;
int i;
- /*
- * It's probably not really necessary to grab the lock --- if there's
- * anyone else attached to the shmem at this point, we've got
- * problems.
- */
-#ifndef EXEC_BACKEND
- LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
-#endif
-
BufferDescriptors = (BufferDesc *)
ShmemInitStruct("Buffer Descriptors",
NBuffers * sizeof(BufferDesc), &foundDescs);
@@ -120,6 +111,13 @@ InitBufferPool(void)
BufferDesc *buf;
char *block;
+ /*
+ * It's probably not really necessary to grab the lock --- if there's
+ * anyone else attached to the shmem at this point, we've got
+ * problems.
+ */
+ LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
+
buf = BufferDescriptors;
block = BufferBlocks;
@@ -147,14 +145,12 @@ InitBufferPool(void)
/* Correct last entry */
BufferDescriptors[NBuffers - 1].bufNext = -1;
+
+ LWLockRelease(BufMgrLock);
}
/* Init other shared buffer-management stuff */
StrategyInitialize(!foundDescs);
-
-#ifndef EXEC_BACKEND
- LWLockRelease(BufMgrLock);
-#endif
}
/*
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 3e8c2a6c1b6..4ce5c98b577 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.66 2004/04/19 23:27:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.67 2004/05/28 05:13:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,9 +37,13 @@
*
* This is called by the postmaster or by a standalone backend.
* It is also called by a backend forked from the postmaster under
- * the EXEC_BACKEND case
- *
- * In the non EXEC_BACKEND case, backends already have shared memory ready-to-go.
+ * the EXEC_BACKEND case. (In the non EXEC_BACKEND case, backends
+ * start life already attached to shared memory.) The initialization
+ * functions are set up to simply "attach" to pre-existing shared memory
+ * structures in the latter case. We have to do that in order to
+ * initialize pointers in local memory that reference the shared structures.
+ * (In the non EXEC_BACKEND case, these pointer values are inherited via
+ * fork() from the postmaster.)
*
* If "makePrivate" is true then we only need private memory, not shared
* memory. This is true for a standalone backend, false for a postmaster.
@@ -96,8 +100,12 @@ CreateSharedMemoryAndSemaphores(bool makePrivate,
* (this should only ever be reached by EXEC_BACKEND code,
* and only then with makePrivate == false)
*/
- Assert(ExecBackend && !makePrivate);
+#ifdef EXEC_BACKEND
+ Assert(!makePrivate);
seghdr = PGSharedMemoryCreate(-1, makePrivate, 0);
+#else
+ Assert(false);
+#endif
}
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 41e2df3a9be..e4e52b16abf 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.62 2003/12/01 21:59:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.63 2004/05/28 05:13:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -75,6 +75,13 @@ InitLockTable(int maxBackends)
{
LOCKMETHODID LongTermTableId;
+ /* there's no zero-th table */
+ NumLockMethods = 1;
+
+ /*
+ * Create the default lock method table
+ */
+
/* number of lock modes is lengthof()-1 because of dummy zero */
LockTableId = LockMethodTableInit("LockTable",
LockConflicts,
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8cb25b4ccdd..88179a0731a 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.131 2003/12/20 17:31:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.132 2004/05/28 05:13:05 tgl Exp $
*
* NOTES
* Outside modules can create a lock table and acquire/release
@@ -155,7 +155,9 @@ PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
static LockMethod LockMethods[MAX_LOCK_METHODS];
static HTAB* LockMethodLockHash[MAX_LOCK_METHODS];
static HTAB* LockMethodProcLockHash[MAX_LOCK_METHODS];
-static int NumLockMethods;
+
+/* exported so lmgr.c can initialize it */
+int NumLockMethods;
/*
@@ -190,15 +192,15 @@ GetLocksMethodTable(LOCK *lock)
*/
static void
LockMethodInit(LockMethod lockMethodTable,
- LOCKMASK *conflictsP,
+ const LOCKMASK *conflictsP,
int numModes)
{
int i;
lockMethodTable->numLockModes = numModes;
/* copies useless zero element as well as the N lockmodes */
- for (i = 0; i <= numModes; i++, conflictsP++)
- lockMethodTable->conflictTab[i] = *conflictsP;
+ for (i = 0; i <= numModes; i++)
+ lockMethodTable->conflictTab[i] = conflictsP[i];
}
/*
@@ -211,8 +213,8 @@ LockMethodInit(LockMethod lockMethodTable,
* TopMemoryContext.
*/
LOCKMETHODID
-LockMethodTableInit(char *tabName,
- LOCKMASK *conflictsP,
+LockMethodTableInit(const char *tabName,
+ const LOCKMASK *conflictsP,
int numModes,
int maxBackends)
{
@@ -245,17 +247,6 @@ LockMethodTableInit(char *tabName,
elog(FATAL, "could not initialize lock table \"%s\"", tabName);
/*
- * Lock the LWLock for the table (probably not necessary here)
- */
-#ifndef EXEC_BACKEND
- LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
-#endif
- /*
- * no zero-th table
- */
- NumLockMethods = 1;
-
- /*
* we're first - initialize
*/
if (!found)
@@ -263,6 +254,7 @@ LockMethodTableInit(char *tabName,
MemSet(newLockMethod, 0, sizeof(LockMethodData));
newLockMethod->masterLock = LockMgrLock;
newLockMethod->lockmethodid = NumLockMethods;
+ LockMethodInit(newLockMethod, conflictsP, numModes);
}
/*
@@ -311,12 +303,6 @@ LockMethodTableInit(char *tabName,
if (!LockMethodProcLockHash[NumLockMethods-1])
elog(FATAL, "could not initialize lock table \"%s\"", tabName);
- /* init data structures */
- LockMethodInit(newLockMethod, conflictsP, numModes);
-
-#ifndef EXEC_BACKEND
- LWLockRelease(LockMgrLock);
-#endif
pfree(shmemName);
return newLockMethod->lockmethodid;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 7a4390538b6..7acaf9117db 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.415 2004/05/26 04:41:35 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.416 2004/05/28 05:13:12 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -2189,10 +2189,13 @@ PostgresMain(int argc, char *argv[], const char *username)
/* Set up reference point for stack depth checking */
stack_base_ptr = &stack_base;
- if (my_exec_path[0] == '\0' && find_my_exec(argv[0], my_exec_path) < 0)
- elog(FATAL,
- gettext("%s: could not locate my own executable path"),
- argv[0]);
+ /* Compute paths, if we didn't inherit them from postmaster */
+ if (my_exec_path[0] == '\0')
+ {
+ if (find_my_exec(argv[0], my_exec_path) < 0)
+ elog(FATAL, "%s: could not locate my own executable path",
+ argv[0]);
+ }
if (pkglib_path[0] == '\0')
get_pkglib_path(my_exec_path, pkglib_path);
@@ -2547,7 +2550,7 @@ PostgresMain(int argc, char *argv[], const char *username)
on_proc_exit(log_disconnections,0);
}
- if (!IsUnderPostmaster || ExecBackend)
+ if (!IsUnderPostmaster)
{
if (!potential_DataDir)
{
@@ -2563,17 +2566,14 @@ PostgresMain(int argc, char *argv[], const char *username)
}
Assert(DataDir);
- /* Acquire configuration parameters */
- if (IsUnderPostmaster)
+ /* Acquire configuration parameters, unless inherited from postmaster */
+ if (!IsUnderPostmaster)
{
-#ifdef EXEC_BACKEND
- read_nondefault_variables();
-#endif
- } else
ProcessConfigFile(PGC_POSTMASTER);
- /* If timezone is not set, determine what the OS uses */
- pg_timezone_initialize();
+ /* If timezone is not set, determine what the OS uses */
+ pg_timezone_initialize();
+ }
/*
* Set up signal handlers and masks.
@@ -2918,11 +2918,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (got_SIGHUP)
{
got_SIGHUP = false;
-#ifdef EXEC_BACKEND
- read_nondefault_variables();
-#else
ProcessConfigFile(PGC_SIGHUP);
-#endif
}
/*
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index a3d13b9cedc..85c3e23a019 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.87 2004/05/18 03:36:36 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.88 2004/05/28 05:13:15 tgl Exp $
*
* NOTES
* Globals used all over the place should be declared here and not
@@ -43,11 +43,15 @@ char *DataDir = NULL;
* variable. NULL if no option given and no environment variable set
*/
-char OutputFileName[MAXPGPATH];
+char OutputFileName[MAXPGPATH]; /* debugging output file */
-char my_exec_path[MAXPGPATH]; /* full path to postgres executable */
-char postgres_exec_path[MAXPGPATH]; /* full path to backend executable */
-char pkglib_path[MAXPGPATH]; /* full path to lib directory */
+char my_exec_path[MAXPGPATH]; /* full path to my executable */
+char pkglib_path[MAXPGPATH]; /* full path to lib directory */
+
+#ifdef EXEC_BACKEND
+char postgres_exec_path[MAXPGPATH]; /* full path to backend */
+/* note: currently this is not valid in backend processes */
+#endif
BackendId MyBackendId;
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 851dfd865d3..fec968e7a20 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/slru.h,v 1.4 2003/11/29 22:40:55 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/access/slru.h,v 1.5 2004/05/28 05:13:17 tgl Exp $
*/
#ifndef SLRU_H
#define SLRU_H
@@ -16,35 +16,38 @@
/* exported because lwlock.c needs it */
#define NUM_CLOG_BUFFERS 8
+/*
+ * Note: the separation between SlruLockData and SlruSharedData is purely
+ * historical; the structs could be combined.
+ */
typedef struct SlruLockData
{
LWLockId ControlLock;
-/*
- * BufferLocks is set during CLOGShmemInit and does not change thereafter.
- * The value is automatically inherited by backends via fork, and
- * doesn't need to be in shared memory.
- */
LWLockId BufferLocks[NUM_CLOG_BUFFERS]; /* Per-buffer I/O locks */
} SlruLockData;
typedef SlruLockData *SlruLock;
+/*
+ * SlruCtlData is an unshared structure that points to the active information
+ * in shared memory.
+ */
typedef struct SlruCtlData
{
void *shared; /* pointer to SlruSharedData */
SlruLock locks;
-/*
- * Dir is set during SimpleLruShmemInit and does not change thereafter.
- * The value is automatically inherited by backends via fork, and
- * doesn't need to be in shared memory.
- */
+ /*
+ * Dir is set during SimpleLruShmemInit and does not change thereafter.
+ * The value is automatically inherited by backends via fork, and
+ * doesn't need to be in shared memory.
+ */
char Dir[MAXPGPATH];
-/*
- * Decide which of two page numbers is "older" for truncation purposes.
- * We need to use comparison of TransactionIds here in order to do the right
- * thing with wraparound XID arithmetic.
- */
+ /*
+ * Decide which of two page numbers is "older" for truncation purposes.
+ * We need to use comparison of TransactionIds here in order to do the
+ * right thing with wraparound XID arithmetic.
+ */
bool (*PagePrecedes) (int, int);
} SlruCtlData;
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index 719fb5a3b73..7dd9c808fde 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.33 2003/11/29 22:40:56 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.34 2004/05/28 05:13:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,7 @@ typedef struct hashnode
extern Relation boot_reldesc;
extern Form_pg_attribute attrtypes[MAXATTR];
extern int numattr;
-extern int BootstrapMain(int ac, char *av[]);
+extern int BootstrapMain(int argc, char *argv[]);
extern void index_register(Oid heap, Oid ind, IndexInfo *indexInfo);
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 03491f2ee56..e8e35fd6b58 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.160 2004/05/18 03:36:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.161 2004/05/28 05:13:24 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to
@@ -116,13 +116,13 @@ do { \
* from postmaster/postmaster.c
*/
extern bool ClientAuthInProgress;
-extern const bool ExecBackend;
extern int PostmasterMain(int argc, char *argv[]);
+extern void ClosePostmasterPorts(bool pgstat_too);
#ifdef EXEC_BACKEND
-extern void SubPostmasterMain(int argc, char* argv[]);
+extern pid_t postmaster_forkexec(int argc, char *argv[]);
+extern int SubPostmasterMain(int argc, char *argv[]);
#endif
-extern void ClosePostmasterPorts(bool pgstat_too);
#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
@@ -143,8 +143,10 @@ extern long MyCancelKey;
extern char OutputFileName[];
extern char my_exec_path[];
-extern char postgres_exec_path[];
extern char pkglib_path[];
+#ifdef EXEC_BACKEND
+extern char postgres_exec_path[];
+#endif
/*
* done in storage/backendid.h for now.
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 7380a883cfa..8f7c4dc4515 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -5,7 +5,7 @@
*
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.21 2004/03/09 05:11:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.22 2004/05/28 05:13:25 tgl Exp $
* ----------
*/
#ifndef PGSTAT_H
@@ -325,18 +325,6 @@ typedef union PgStat_Msg
} PgStat_Msg;
-#ifdef EXEC_BACKEND
-typedef enum STATS_PROCESS_TYPE
-{
- STAT_PROC_BUFFER,
- STAT_PROC_COLLECTOR
-} STATS_PROCESS_TYPE;
-#define PGSTAT_FORK_ARGS int argc, char *argv[]
-#else
-#define PGSTAT_FORK_ARGS void
-#endif
-
-
/* ----------
* GUC parameters
* ----------
@@ -355,28 +343,21 @@ extern bool pgstat_is_running;
/* ----------
- * Functions called from main
- * ----------
- */
-#ifdef EXEC_BACKEND
-extern void pgstat_main(PGSTAT_FORK_ARGS);
-extern void pgstat_mainChild(PGSTAT_FORK_ARGS);
-#endif
-
-
-/* ----------
* Functions called from postmaster
* ----------
*/
-#ifdef EXEC_BACKEND
-extern void pgstat_init_forkexec_backend(void);
-#endif
extern void pgstat_init(void);
extern void pgstat_start(void);
extern bool pgstat_ispgstat(int pid);
extern void pgstat_close_sockets(void);
extern void pgstat_beterm(int pid);
+#ifdef EXEC_BACKEND
+extern void PgstatBufferMain(int argc, char *argv[]);
+extern void PgstatCollectorMain(int argc, char *argv[]);
+#endif
+
+
/* ----------
* Functions called from backends
* ----------
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 2d13e9df114..8c7159c0cb0 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.76 2003/12/20 17:31:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.77 2004/05/28 05:13:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -223,13 +223,16 @@ typedef struct
LOCK *locks;
} LockData;
+extern int NumLockMethods;
+
/*
* function prototypes
*/
extern void InitLocks(void);
extern LockMethod GetLocksMethodTable(LOCK *lock);
-extern LOCKMETHODID LockMethodTableInit(char *tabName, LOCKMASK *conflictsP,
- int numModes, int maxBackends);
+extern LOCKMETHODID LockMethodTableInit(const char *tabName,
+ const LOCKMASK *conflictsP,
+ int numModes, int maxBackends);
extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid);
extern bool LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
TransactionId xid, LOCKMODE lockmode, bool dontWait);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 707dca33910..b91682af88f 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -7,7 +7,7 @@
* Copyright (c) 2000-2003, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.46 2004/05/26 15:07:41 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.47 2004/05/28 05:13:32 tgl Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
@@ -206,8 +206,8 @@ extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *va
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
#ifdef EXEC_BACKEND
-void write_nondefault_variables(GucContext context);
-void read_nondefault_variables(void);
+extern void write_nondefault_variables(GucContext context);
+extern void read_nondefault_variables(void);
#endif
/*