Commit 1a321f26 authored by Tom Lane's avatar Tom Lane

Code review for EXEC_BACKEND changes. Reduce the number of #ifdefs by

about a third, make it work on non-Windows platforms again.  (But perhaps
I broke the WIN32 code, since I have no way to test that.)  Fold all the
paths that fork postmaster child processes to go through the single
routine SubPostmasterMain, which takes care of resurrecting the state that
would normally be inherited from the postmaster (including GUC variables).
Clean up some places where there's no particularly good reason for the
EXEC and non-EXEC cases to work differently.  Take care of one or two
FIXMEs that remained in the code.
parent 37da0ba0
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -164,10 +164,9 @@ static bool SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions);
int int
SimpleLruShmemSize(void) SimpleLruShmemSize(void)
{ {
return MAXALIGN(sizeof(SlruSharedData)) + BLCKSZ * NUM_CLOG_BUFFERS return MAXALIGN(sizeof(SlruSharedData))
#ifdef EXEC_BACKEND + BLCKSZ * NUM_CLOG_BUFFERS
+ MAXALIGN(sizeof(SlruLockData)) + MAXALIGN(sizeof(SlruLockData))
#endif
; ;
} }
...@@ -181,21 +180,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir) ...@@ -181,21 +180,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
ptr = ShmemInitStruct(name, SimpleLruShmemSize(), &found); ptr = ShmemInitStruct(name, SimpleLruShmemSize(), &found);
shared = (SlruShared) ptr; shared = (SlruShared) ptr;
#ifdef EXEC_BACKEND
/*
* Locks are in shared memory
*/
locks = (SlruLock) (ptr + MAXALIGN(sizeof(SlruSharedData)) + locks = (SlruLock) (ptr + MAXALIGN(sizeof(SlruSharedData)) +
BLCKSZ * NUM_CLOG_BUFFERS); BLCKSZ * NUM_CLOG_BUFFERS);
#else
/*
* Locks are in private memory
*/
Assert(!IsUnderPostmaster);
locks = malloc(sizeof(SlruLockData));
Assert(locks);
#endif
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
...@@ -225,6 +211,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir) ...@@ -225,6 +211,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
else else
Assert(found); Assert(found);
/* Initialize the unshared control struct */
ctl->locks = locks; ctl->locks = locks;
ctl->shared = shared; ctl->shared = shared;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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]; ...@@ -397,7 +397,7 @@ static char ControlFilePath[MAXPGPATH];
* Private, possibly out-of-date copy of shared LogwrtResult. * Private, possibly out-of-date copy of shared LogwrtResult.
* See discussion above. * 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. * openLogFile is -1 or a kernel FD for an open log file segment.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -43,17 +43,12 @@
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/ps_status.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t))) #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); extern int Int_yyparse(void);
static hashnode *AddStr(char *str, int strlength, int mderef); static hashnode *AddStr(char *str, int strlength, int mderef);
static Form_pg_attribute AllocateAttribute(void); static Form_pg_attribute AllocateAttribute(void);
...@@ -233,34 +228,29 @@ usage(void) ...@@ -233,34 +228,29 @@ usage(void)
} }
/*
int * The main loop for running the backend in bootstrap mode
BootstrapMain(int argc, char *argv[]) *
/* ---------------------------------------------------------------- * The bootstrap mode is used to initialize the template database.
* The main loop for handling the backend in bootstrap mode * The bootstrap backend doesn't speak SQL, but instead expects
* 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. * commands in a special bootstrap language.
* *
* The arguments passed in to BootstrapMain are the run-time arguments * For historical reasons, BootstrapMain is also used as the control
* without the argument '-boot', the caller is required to have * routine for non-backend subprocesses launched by the postmaster,
* removed -boot from the run-time args * such as startup and shutdown.
* ----------------------------------------------------------------
*/ */
int
BootstrapMain(int argc, char *argv[])
{ {
int i; int i;
char *dbname; char *dbname;
int flag; int flag;
int xlogop = BS_XLOG_NOP; int xlogop = BS_XLOG_NOP;
char *potential_DataDir = NULL; char *potential_DataDir = NULL;
#ifdef EXEC_BACKEND
unsigned long backendID = 0;
#endif
/* /*
* initialize globals * initialize globals
*/ */
MyProcPid = getpid(); MyProcPid = getpid();
/* /*
...@@ -268,7 +258,7 @@ BootstrapMain(int argc, char *argv[]) ...@@ -268,7 +258,7 @@ BootstrapMain(int argc, char *argv[])
* *
* If we are running under the postmaster, this is done already. * If we are running under the postmaster, this is done already.
*/ */
if (!IsUnderPostmaster || ExecBackend) if (!IsUnderPostmaster)
MemoryContextInit(); MemoryContextInit();
/* /*
...@@ -284,6 +274,13 @@ BootstrapMain(int argc, char *argv[]) ...@@ -284,6 +274,13 @@ BootstrapMain(int argc, char *argv[])
* variable */ * 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) while ((flag = getopt(argc, argv, "B:c:d:D:Fo:p:x:-:")) != -1)
{ {
switch (flag) switch (flag)
...@@ -315,14 +312,6 @@ BootstrapMain(int argc, char *argv[]) ...@@ -315,14 +312,6 @@ BootstrapMain(int argc, char *argv[])
xlogop = atoi(optarg); xlogop = atoi(optarg);
break; break;
case 'p': case 'p':
#ifdef EXEC_BACKEND
{
char buf[MAXPGPATH];
IsUnderPostmaster = true;
sscanf(optarg,"%lu,%s",&backendID,buf);
dbname = strdup(buf);
}
#endif
dbname = strdup(optarg); dbname = strdup(optarg);
break; break;
case 'B': case 'B':
...@@ -369,7 +358,7 @@ BootstrapMain(int argc, char *argv[]) ...@@ -369,7 +358,7 @@ BootstrapMain(int argc, char *argv[])
if (!dbname || argc != optind) if (!dbname || argc != optind)
usage(); usage();
if (!IsUnderPostmaster || ExecBackend) if (!IsUnderPostmaster)
{ {
if (!potential_DataDir) if (!potential_DataDir)
{ {
...@@ -388,21 +377,43 @@ BootstrapMain(int argc, char *argv[]) ...@@ -388,21 +377,43 @@ BootstrapMain(int argc, char *argv[])
Assert(DataDir); Assert(DataDir);
ValidatePgVersion(DataDir); ValidatePgVersion(DataDir);
/* Acquire configuration parameters */ /*
* Identify myself via ps
*/
if (IsUnderPostmaster) if (IsUnderPostmaster)
{ {
#ifdef EXEC_BACKEND const char *statmsg;
read_backend_variables(backendID,NULL);
read_nondefault_variables();
SSDataBaseInit(xlogop); switch (xlogop)
#endif {
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); ProcessConfigFile(PGC_POSTMASTER);
/* If timezone is not set, determine what the OS uses */ /* If timezone is not set, determine what the OS uses */
pg_timezone_initialize(); pg_timezone_initialize();
}
if (IsUnderPostmaster) if (IsUnderPostmaster)
{ {
...@@ -450,10 +461,6 @@ BootstrapMain(int argc, char *argv[]) ...@@ -450,10 +461,6 @@ BootstrapMain(int argc, char *argv[])
SetProcessingMode(BootstrapProcessing); SetProcessingMode(BootstrapProcessing);
IgnoreSystemIndexes(true); IgnoreSystemIndexes(true);
#ifdef EXEC_BACKEND
if (IsUnderPostmaster)
CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
#endif
XLOGPathInit(); XLOGPathInit();
BaseInit(); BaseInit();
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * 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[]) ...@@ -242,9 +242,9 @@ main(int argc, char *argv[])
/* /*
* Now dispatch to one of PostmasterMain, PostgresMain, GucInfoMain, * Now dispatch to one of PostmasterMain, PostgresMain, GucInfoMain,
* SubPostmasterMain, pgstat_main, pgstat_mainChild or BootstrapMain * SubPostmasterMain, or BootstrapMain depending on the program name
* depending on the program name (and possibly first argument) we were * (and possibly first argument) we were called with. The lack of
* called with. The lack of consistency here is historical. * consistency here is historical.
*/ */
len = strlen(argv[0]); len = strlen(argv[0]);
...@@ -259,43 +259,21 @@ main(int argc, char *argv[]) ...@@ -259,43 +259,21 @@ main(int argc, char *argv[])
} }
/* /*
* If the first argument is "-boot", then invoke bootstrap mode. Note * If the first argument begins with "-fork", then invoke
* we remove "-boot" from the arguments passed on to BootstrapMain. * 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 #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 * If the first argument is "-boot", then invoke bootstrap mode.
* SubPostmasterMain. Note we remove "-forkexec" from the arguments * (This path is taken only for a standalone bootstrap process.)
* 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 (argc > 1 && strcmp(argv[1], "-statCol") == 0) if (argc > 1 && strcmp(argv[1], "-boot") == 0)
{ exit(BootstrapMain(argc, argv));
pgstat_mainChild(argc, argv);
exit(0);
}
#endif
/* /*
* If the first argument is "--describe-config", then invoke runtime * If the first argument is "--describe-config", then invoke runtime
...@@ -331,7 +309,7 @@ main(int argc, char *argv[]) ...@@ -331,7 +309,7 @@ main(int argc, char *argv[])
exit(1); exit(1);
} }
} }
#endif #endif /* WIN32 */
exit(PostgresMain(argc, argv, pw_name_persist)); exit(PostgresMain(argc, argv, pw_name_persist));
} }
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* *
* *
* IDENTIFICATION * 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; ...@@ -46,8 +46,6 @@ volatile bool ImmediateInterruptOK = false;
volatile uint32 InterruptHoldoffCount = 0; volatile uint32 InterruptHoldoffCount = 0;
volatile uint32 CritSectionCount = 0; volatile uint32 CritSectionCount = 0;
const bool ExecBackend = false;
bool IsUnderPostmaster = false; bool IsUnderPostmaster = false;
int MaxBackends = 32; int MaxBackends = 32;
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
* - Add some automatic call for pgstat vacuuming. * - Add some automatic call for pgstat vacuuming.
* *
* - Add a pgstat config column to pg_database, so this * - 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 * 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" #include "postgres.h"
...@@ -51,13 +51,6 @@ ...@@ -51,13 +51,6 @@
#include "utils/ps_status.h" #include "utils/ps_status.h"
#include "utils/syscache.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 * GUC parameters
...@@ -107,8 +100,8 @@ static HTAB *pgStatBeDead = NULL; ...@@ -107,8 +100,8 @@ static HTAB *pgStatBeDead = NULL;
static PgStat_StatBeEntry *pgStatBeTable = NULL; static PgStat_StatBeEntry *pgStatBeTable = NULL;
static int pgStatNumBackends = 0; static int pgStatNumBackends = 0;
static char pgStat_tmpfname[MAXPGPATH];
static char pgStat_fname[MAXPGPATH]; static char pgStat_fname[MAXPGPATH];
static char pgStat_tmpfname[MAXPGPATH];
/* ---------- /* ----------
...@@ -116,12 +109,20 @@ static char pgStat_fname[MAXPGPATH]; ...@@ -116,12 +109,20 @@ static char pgStat_fname[MAXPGPATH];
* ---------- * ----------
*/ */
#ifdef EXEC_BACKEND #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 pid_t pgstat_forkexec(STATS_PROCESS_TYPE procType);
static void pgstat_parseArgs(PGSTAT_FORK_ARGS); static void pgstat_parseArgs(int argc, char *argv[]);
#endif #endif
NON_EXEC_STATIC void pgstat_main(PGSTAT_FORK_ARGS);
NON_EXEC_STATIC void pgstat_mainChild(PGSTAT_FORK_ARGS); NON_EXEC_STATIC void PgstatBufferMain(int argc, char *argv[]);
static void pgstat_mainInit(void); NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]);
static void pgstat_recvbuffer(void); static void pgstat_recvbuffer(void);
static void pgstat_die(SIGNAL_ARGS); static void pgstat_die(SIGNAL_ARGS);
...@@ -150,18 +151,6 @@ static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); ...@@ -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() - * pgstat_init() -
* *
...@@ -195,12 +184,12 @@ pgstat_init(void) ...@@ -195,12 +184,12 @@ pgstat_init(void)
pgstat_collect_startcollector = true; 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, snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
PGSTAT_STAT_TMPFILE, DataDir, getpid());
snprintf(pgStat_fname, MAXPGPATH,
PGSTAT_STAT_FILENAME, DataDir);
/* /*
* If we don't have to start a collector or should reset the collected * If we don't have to start a collector or should reset the collected
...@@ -441,112 +430,83 @@ startup_failed: ...@@ -441,112 +430,83 @@ startup_failed:
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
/* ---------- /*
* pgstat_forkexec() - * 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 * (buffer and collector) processes
*
*/ */
static pid_t static pid_t
pgstat_forkexec(STATS_PROCESS_TYPE procType) pgstat_forkexec(STATS_PROCESS_TYPE procType)
{ {
pid_t pid; char *av[12];
char *av[15];
int ac = 0, bufc = 0, i; int ac = 0, bufc = 0, i;
char pgstatBuf[12][MAXPGPATH]; char pgstatBuf[7][32];
av[ac++] = "postgres"; av[ac++] = "postgres";
switch (procType) switch (procType)
{ {
case STAT_PROC_BUFFER: case STAT_PROC_BUFFER:
av[ac++] = "-statBuf"; av[ac++] = "-forkbuf";
break; break;
case STAT_PROC_COLLECTOR: case STAT_PROC_COLLECTOR:
av[ac++] = "-statCol"; av[ac++] = "-forkcol";
break; break;
default: default:
Assert(false); Assert(false);
} }
/* Sockets + pipes */ av[ac++] = NULL; /* filled in by postmaster_forkexec */
bufc = 0;
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatSock); /* postgres_exec_path is not passed by write_backend_variables */
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[0]); av[ac++] = postgres_exec_path;
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[1]);
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[0]); /* Sockets + pipes (those not passed by write_backend_variables) */
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[1]); snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[0]);
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[0]); snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[1]);
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[1]); snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[0]);
snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[1]);
/* + misc */ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[0]);
snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",MaxBackends); snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[1]);
/* + 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);
/* Add to the arg list */ /* Add to the arg list */
Assert(bufc <= lengthof(pgstatBuf)); Assert(bufc <= lengthof(pgstatBuf));
for (i = 0; i < bufc; i++) for (i = 0; i < bufc; i++)
av[ac++] = pgstatBuf[i]; av[ac++] = pgstatBuf[i];
av[ac++] = NULL; av[ac] = NULL;
Assert(ac <= lengthof(av)); Assert(ac < lengthof(av));
/* Fire off execv in child */ return postmaster_forkexec(ac, av);
#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 */
} }
/* ---------- /*
* pgstat_parseArgs() - * pgstat_parseArgs() -
* *
* Used to unformat the arglist for exec'ed statistics * Extract data from the arglist for exec'ed statistics
* (buffer and collector) processes * (buffer and collector) processes
*
*/ */
static void static void
pgstat_parseArgs(PGSTAT_FORK_ARGS) pgstat_parseArgs(int argc, char *argv[])
{ {
Assert(argc == 14); Assert(argc == 10);
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);
argc = 2; argc = 3;
pgStatSock = atoi(argv[argc++]); StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
pgStatPmPipe[0] = atoi(argv[argc++]); pgStatPmPipe[0] = atoi(argv[argc++]);
pgStatPmPipe[1] = atoi(argv[argc++]); pgStatPmPipe[1] = atoi(argv[argc++]);
pgStatCollectorPmPipe[0] = atoi(argv[argc++]); pgStatCollectorPmPipe[0] = atoi(argv[argc++]);
pgStatCollectorPmPipe[1] = atoi(argv[argc++]); pgStatCollectorPmPipe[1] = atoi(argv[argc++]);
pgStatPipe[0] = atoi(argv[argc++]); pgStatPipe[0] = atoi(argv[argc++]);
pgStatPipe[1] = 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() - * pgstat_start() -
...@@ -638,7 +598,7 @@ pgstat_start(void) ...@@ -638,7 +598,7 @@ pgstat_start(void)
/* Drop our connection to postmaster's shared memory, as well */ /* Drop our connection to postmaster's shared memory, as well */
PGSharedMemoryDetach(); PGSharedMemoryDetach();
pgstat_main(); PgstatBufferMain(0, NULL);
break; break;
#endif #endif
...@@ -1443,26 +1403,20 @@ pgstat_send(void *msg, int len) ...@@ -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.
* ----------
*/ */
NON_EXEC_STATIC void
static void PgstatBufferMain(int argc, char *argv[])
pgstat_mainInit(void)
{ {
IsUnderPostmaster = true; /* we are a postmaster subprocess now */ 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 */ MyProcPid = getpid(); /* reset MyProcPid */
/* Lose the postmaster's on-exit routines */ /* Lose the postmaster's on-exit routines */
...@@ -1485,20 +1439,8 @@ pgstat_mainInit(void) ...@@ -1485,20 +1439,8 @@ pgstat_mainInit(void)
pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL);
pqsignal(SIGCONT, SIG_DFL); pqsignal(SIGCONT, SIG_DFL);
pqsignal(SIGWINCH, 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 #ifdef EXEC_BACKEND
pgstat_parseArgs(argc,argv); pgstat_parseArgs(argc,argv);
#endif #endif
...@@ -1547,7 +1489,7 @@ pgstat_main(PGSTAT_FORK_ARGS) ...@@ -1547,7 +1489,7 @@ pgstat_main(PGSTAT_FORK_ARGS)
#ifndef EXEC_BACKEND #ifndef EXEC_BACKEND
case 0: case 0:
/* child becomes collector process */ /* child becomes collector process */
pgstat_mainChild(); PgstatCollectorMain(0, NULL);
break; break;
#endif #endif
...@@ -1560,8 +1502,17 @@ pgstat_main(PGSTAT_FORK_ARGS) ...@@ -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 NON_EXEC_STATIC void
pgstat_mainChild(PGSTAT_FORK_ARGS) PgstatCollectorMain(int argc, char *argv[])
{ {
PgStat_Msg msg; PgStat_Msg msg;
fd_set rfds; fd_set rfds;
...@@ -1574,29 +1525,52 @@ pgstat_mainChild(PGSTAT_FORK_ARGS) ...@@ -1574,29 +1525,52 @@ pgstat_mainChild(PGSTAT_FORK_ARGS)
bool need_statwrite; bool need_statwrite;
HASHCTL hash_ctl; 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 #ifdef EXEC_BACKEND
pgstat_mainInit(); /* Note: only in EXEC_BACKEND case */
pgstat_parseArgs(argc,argv); pgstat_parseArgs(argc,argv);
#else
MyProcPid = getpid(); /* reset MyProcPid */
#endif #endif
/* Close unwanted files */
closesocket(pgStatPipe[1]); closesocket(pgStatPipe[1]);
closesocket(pgStatSock); closesocket(pgStatSock);
pmPipe = pgStatCollectorPmPipe[0]; 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 * Identify myself via ps
*/ */
init_ps_display("stats collector process", "", ""); init_ps_display("stats collector process", "", "");
set_ps_display(""); 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 * Arrange to write the initial status file right away
*/ */
...@@ -2549,6 +2523,18 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, ...@@ -2549,6 +2523,18 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
if (betab != NULL) if (betab != NULL)
*betab = NULL; *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 * Try to open the status file. If it doesn't exist, the backends
* simply return zero for anything and the collector simply starts * simply return zero for anything and the collector simply starts
......
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
* message to setup a backend process. * message to setup a backend process.
* *
* The postmaster also manages system-wide operations such as * The postmaster also manages system-wide operations such as
* startup, shutdown, and periodic checkpoints. The postmaster * startup and shutdown. The postmaster itself doesn't do those
* itself doesn't do those operations, mind you --- it just forks * operations, mind you --- it just forks off a subprocess to do them
* off a subprocess to do them at the right times. It also takes * at the right times. It also takes care of resetting the system
* care of resetting the system if a backend crashes. * if a backend crashes.
* *
* The postmaster process creates the shared memory and semaphore * The postmaster process creates the shared memory and semaphore
* pools during startup, but as a rule does not touch them itself. * pools during startup, but as a rule does not touch them itself.
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -113,8 +113,6 @@ ...@@ -113,8 +113,6 @@
#include "pgstat.h" #include "pgstat.h"
#define INVALID_SOCK (-1)
#ifdef HAVE_SIGPROCMASK #ifdef HAVE_SIGPROCMASK
sigset_t UnBlockSig, sigset_t UnBlockSig,
BlockSig, BlockSig,
...@@ -177,14 +175,6 @@ static const char *progname = NULL; ...@@ -177,14 +175,6 @@ static const char *progname = NULL;
#define MAXLISTEN 10 #define MAXLISTEN 10
static int ListenSocket[MAXLISTEN]; 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 * Set by the -o option
*/ */
...@@ -258,7 +248,12 @@ extern int optreset; ...@@ -258,7 +248,12 @@ extern int optreset;
/* /*
* postmaster.c - function prototypes * 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 Port *ConnCreate(int serverFd);
static void ConnFree(Port *port); static void ConnFree(Port *port);
static void reset_shared(unsigned short port); static void reset_shared(unsigned short port);
...@@ -270,7 +265,6 @@ static void dummy_handler(SIGNAL_ARGS); ...@@ -270,7 +265,6 @@ static void dummy_handler(SIGNAL_ARGS);
static void CleanupProc(int pid, int exitstatus); static void CleanupProc(int pid, int exitstatus);
static void LogChildExit(int lev, const char *procname, static void LogChildExit(int lev, const char *procname,
int pid, int exitstatus); int pid, int exitstatus);
static void BackendInit(Port *port);
static int BackendRun(Port *port); static int BackendRun(Port *port);
static void ExitPostmaster(int status); static void ExitPostmaster(int status);
static void usage(const char *); static void usage(const char *);
...@@ -286,7 +280,6 @@ static void RandomSalt(char *cryptSalt, char *md5Salt); ...@@ -286,7 +280,6 @@ static void RandomSalt(char *cryptSalt, char *md5Salt);
static void SignalChildren(int signal); static void SignalChildren(int signal);
static int CountChildren(void); static int CountChildren(void);
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname); static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
NON_EXEC_STATIC void SSDataBaseInit(int xlop);
static pid_t SSDataBase(int xlop); static pid_t SSDataBase(int xlop);
static void static void
postmaster_error(const char *fmt,...) postmaster_error(const char *fmt,...)
...@@ -296,8 +289,7 @@ __attribute__((format(printf, 1, 2))); ...@@ -296,8 +289,7 @@ __attribute__((format(printf, 1, 2)));
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
#ifdef WIN32 #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_AddChild(pid_t pid, HANDLE handle);
static void win32_RemoveChild(pid_t pid); static void win32_RemoveChild(pid_t pid);
static pid_t win32_waitpid(int *exitstatus); static pid_t win32_waitpid(int *exitstatus);
...@@ -308,98 +300,26 @@ static HANDLE *win32_childHNDArray; ...@@ -308,98 +300,26 @@ static HANDLE *win32_childHNDArray;
static unsigned long win32_numChildren = 0; static unsigned long win32_numChildren = 0;
#endif #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; static void read_backend_variables(char *filename, Port *port);
void read_backend_variables(unsigned long id, Port *port); static bool write_backend_variables(char *filename, Port *port);
static bool write_backend_variables(Port *port);
static void ShmemBackendArrayAdd(Backend *bn); static void ShmemBackendArrayAdd(Backend *bn);
static void ShmemBackendArrayRemove(pid_t pid); static void ShmemBackendArrayRemove(pid_t pid);
#endif
#endif /* EXEC_BACKEND */
#define StartupDataBase() SSDataBase(BS_XLOG_STARTUP) #define StartupDataBase() SSDataBase(BS_XLOG_STARTUP)
#define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT) #define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)
#define StartBackgroundWriter() SSDataBase(BS_XLOG_BGWRITER) #define StartBackgroundWriter() SSDataBase(BS_XLOG_BGWRITER)
#define ShutdownDataBase() SSDataBase(BS_XLOG_SHUTDOWN) #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 int
PostmasterMain(int argc, char *argv[]) PostmasterMain(int argc, char *argv[])
{ {
...@@ -462,8 +382,7 @@ PostmasterMain(int argc, char *argv[]) ...@@ -462,8 +382,7 @@ PostmasterMain(int argc, char *argv[])
IgnoreSystemIndexes(false); IgnoreSystemIndexes(false);
if (find_my_exec(argv[0], my_exec_path) < 0) if (find_my_exec(argv[0], my_exec_path) < 0)
elog(FATAL, elog(FATAL, "%s: could not locate my own executable path",
gettext("%s: could not locate my own executable path"),
argv[0]); argv[0]);
get_pkglib_path(my_exec_path, pkglib_path); get_pkglib_path(my_exec_path, pkglib_path);
...@@ -700,9 +619,10 @@ PostmasterMain(int argc, char *argv[]) ...@@ -700,9 +619,10 @@ PostmasterMain(int argc, char *argv[])
} }
#ifdef EXEC_BACKEND #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, ereport(FATAL,
(errmsg("%s: could not locate postgres executable or non-matching version", (errmsg("%s: could not locate matching postgres executable",
progname))); progname)));
#endif #endif
...@@ -728,7 +648,7 @@ PostmasterMain(int argc, char *argv[]) ...@@ -728,7 +648,7 @@ PostmasterMain(int argc, char *argv[])
* will show the wrong PID. * will show the wrong PID.
*/ */
if (SilentMode) if (SilentMode)
pmdaemonize(argc, argv); pmdaemonize();
/* /*
* Create lockfile for data directory. * Create lockfile for data directory.
...@@ -945,8 +865,96 @@ PostmasterMain(int argc, char *argv[]) ...@@ -945,8 +865,96 @@ PostmasterMain(int argc, char *argv[])
return 0; /* not reached */ 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 static void
pmdaemonize(int argc, char *argv[]) pmdaemonize(void)
{ {
#ifdef WIN32 #ifdef WIN32
/* not supported */ /* not supported */
...@@ -960,7 +968,7 @@ pmdaemonize(int argc, char *argv[]) ...@@ -960,7 +968,7 @@ pmdaemonize(int argc, char *argv[])
#endif #endif
#ifdef LINUX_PROFILE #ifdef LINUX_PROFILE
/* see comments in BackendRun */ /* see comments in BackendStartup */
getitimer(ITIMER_PROF, &prof_itimer); getitimer(ITIMER_PROF, &prof_itimer);
#endif #endif
...@@ -1003,7 +1011,6 @@ pmdaemonize(int argc, char *argv[]) ...@@ -1003,7 +1011,6 @@ pmdaemonize(int argc, char *argv[])
} }
/* /*
* Print out help message * Print out help message
*/ */
...@@ -1044,6 +1051,10 @@ usage(const char *progname) ...@@ -1044,6 +1051,10 @@ usage(const char *progname)
"Report bugs to <pgsql-bugs@postgresql.org>.\n")); "Report bugs to <pgsql-bugs@postgresql.org>.\n"));
} }
/*
* Main loop of postmaster
*/
static int static int
ServerLoop(void) ServerLoop(void)
{ {
...@@ -1194,7 +1205,6 @@ ServerLoop(void) ...@@ -1194,7 +1205,6 @@ ServerLoop(void)
* Initialise the masks for select() for the ports * Initialise the masks for select() for the ports
* we are listening on. Return the number of sockets to listen on. * we are listening on. Return the number of sockets to listen on.
*/ */
static int static int
initMasks(fd_set *rmask) initMasks(fd_set *rmask)
{ {
...@@ -1524,10 +1534,8 @@ processCancelRequest(Port *port, void *pkt) ...@@ -1524,10 +1534,8 @@ processCancelRequest(Port *port, void *pkt)
int backendPID; int backendPID;
long cancelAuthCode; long cancelAuthCode;
Backend *bp; Backend *bp;
#ifndef EXEC_BACKEND #ifndef EXEC_BACKEND
Dlelem *curr; Dlelem *curr;
#else #else
int i; int i;
#endif #endif
...@@ -1550,7 +1558,11 @@ processCancelRequest(Port *port, void *pkt) ...@@ -1550,7 +1558,11 @@ processCancelRequest(Port *port, void *pkt)
return; 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 #ifndef EXEC_BACKEND
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
{ {
...@@ -1728,13 +1740,15 @@ SIGHUP_handler(SIGNAL_ARGS) ...@@ -1728,13 +1740,15 @@ SIGHUP_handler(SIGNAL_ARGS)
ereport(LOG, ereport(LOG,
(errmsg("received SIGHUP, reloading configuration files"))); (errmsg("received SIGHUP, reloading configuration files")));
ProcessConfigFile(PGC_SIGHUP); ProcessConfigFile(PGC_SIGHUP);
#ifdef EXEC_BACKEND
write_nondefault_variables(PGC_SIGHUP);
#endif
SignalChildren(SIGHUP); SignalChildren(SIGHUP);
load_hba(); load_hba();
load_ident(); 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 * Tell the background writer to terminate so that we will start a
* new one with a possibly changed config * new one with a possibly changed config
...@@ -1749,7 +1763,6 @@ SIGHUP_handler(SIGNAL_ARGS) ...@@ -1749,7 +1763,6 @@ SIGHUP_handler(SIGNAL_ARGS)
} }
/* /*
* pmdie -- signal handler for processing various postmaster signals. * pmdie -- signal handler for processing various postmaster signals.
*/ */
...@@ -2249,6 +2262,9 @@ BackendStartup(Port *port) ...@@ -2249,6 +2262,9 @@ BackendStartup(Port *port)
return STATUS_ERROR; 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 * Flush stdio channels just before fork, to avoid double-output
* problems. Ideally we'd use fflush(NULL) here, but there are still a * problems. Ideally we'd use fflush(NULL) here, but there are still a
...@@ -2260,6 +2276,12 @@ BackendStartup(Port *port) ...@@ -2260,6 +2276,12 @@ BackendStartup(Port *port)
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
#ifdef EXEC_BACKEND
pid = backend_forkexec(port);
#else /* !EXEC_BACKEND */
#ifdef LINUX_PROFILE #ifdef LINUX_PROFILE
/* /*
...@@ -2277,10 +2299,6 @@ BackendStartup(Port *port) ...@@ -2277,10 +2299,6 @@ BackendStartup(Port *port)
beos_before_backend_startup(); beos_before_backend_startup();
#endif #endif
port->canAcceptConnections = canAcceptConnections();
#ifdef EXEC_BACKEND
pid = Backend_forkexec(port);
#else
pid = fork(); pid = fork();
if (pid == 0) /* child */ if (pid == 0) /* child */
...@@ -2297,11 +2315,12 @@ BackendStartup(Port *port) ...@@ -2297,11 +2315,12 @@ BackendStartup(Port *port)
proc_exit(BackendRun(port)); proc_exit(BackendRun(port));
} }
#endif
/* in parent, error */ #endif /* EXEC_BACKEND */
if (pid < 0) if (pid < 0)
{ {
/* in parent, fork failed */
int save_errno = errno; int save_errno = errno;
#ifdef __BEOS__ #ifdef __BEOS__
...@@ -2316,7 +2335,7 @@ BackendStartup(Port *port) ...@@ -2316,7 +2335,7 @@ BackendStartup(Port *port)
return STATUS_ERROR; return STATUS_ERROR;
} }
/* in parent, normal */ /* in parent, successful fork */
ereport(DEBUG2, ereport(DEBUG2,
(errmsg_internal("forked new backend, pid=%d socket=%d", (errmsg_internal("forked new backend, pid=%d socket=%d",
(int) pid, port->sock))); (int) pid, port->sock)));
...@@ -2392,16 +2411,15 @@ split_opts(char **argv, int *argcp, char *s) ...@@ -2392,16 +2411,15 @@ split_opts(char **argv, int *argcp, char *s)
/* /*
* BackendInit/Run -- perform authentication [BackendInit], and if successful, * BackendRun -- perform authentication, and if successful,
* set up the backend's argument list [BackendRun] and invoke * set up the backend's argument list and invoke PostgresMain()
* backend main()
* *
* returns: * returns:
* Shouldn't return at all. * Shouldn't return at all.
* If PostgresMain() fails, return status. * If PostgresMain() fails, return status.
*/ */
static void static int
BackendInit(Port *port) BackendRun(Port *port)
{ {
int status; int status;
struct timeval now; struct timeval now;
...@@ -2409,10 +2427,20 @@ BackendInit(Port *port) ...@@ -2409,10 +2427,20 @@ BackendInit(Port *port)
char remote_host[NI_MAXHOST]; char remote_host[NI_MAXHOST];
char remote_port[NI_MAXSERV]; char remote_port[NI_MAXSERV];
char remote_ps_data[NI_MAXHOST]; 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 */ 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 */ /* We don't want the postmaster's proc_exit() handlers */
on_exit_reset(); on_exit_reset();
...@@ -2421,6 +2449,24 @@ BackendInit(Port *port) ...@@ -2421,6 +2449,24 @@ BackendInit(Port *port)
* Signal handlers setting is moved to tcop/postgres... * 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 */ /* save start time for end of session reporting */
gettimeofday(&(port->session_start), NULL); gettimeofday(&(port->session_start), NULL);
...@@ -2429,12 +2475,6 @@ BackendInit(Port *port) ...@@ -2429,12 +2475,6 @@ BackendInit(Port *port)
port->remote_port = ""; port->remote_port = "";
port->commandTag = ""; 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 * Initialize libpq and enable reporting of ereport errors to the
* client. Must do this now because authentication uses libpq to send * client. Must do this now because authentication uses libpq to send
...@@ -2489,6 +2529,29 @@ BackendInit(Port *port) ...@@ -2489,6 +2529,29 @@ BackendInit(Port *port)
port->remote_host = strdup(remote_host); port->remote_host = strdup(remote_host);
port->remote_port = strdup(remote_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) * 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 * after a time delay, so that a broken client can't hog a connection
...@@ -2540,37 +2603,6 @@ BackendInit(Port *port) ...@@ -2540,37 +2603,6 @@ BackendInit(Port *port)
random_seed = 0; random_seed = 0;
gettimeofday(&now, &tz); gettimeofday(&now, &tz);
srandom((unsigned int) now.tv_usec); 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) ...@@ -2607,7 +2639,8 @@ BackendRun(Port *port)
/* /*
* Pass any backend switches specified with -o in the postmaster's own * 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); split_opts(av, &ac, ExtraOptions);
...@@ -2615,12 +2648,6 @@ BackendRun(Port *port) ...@@ -2615,12 +2648,6 @@ BackendRun(Port *port)
snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto); snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto);
av[ac++] = protobuf; 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 * Tell the backend it is being called from the postmaster, and which
* database to use. -p marks the end of secure switches. * database to use. -p marks the end of secure switches.
...@@ -2647,9 +2674,7 @@ BackendRun(Port *port) ...@@ -2647,9 +2674,7 @@ BackendRun(Port *port)
* username isn't lost either; see ProcessStartupPacket(). * username isn't lost either; see ProcessStartupPacket().
*/ */
MemoryContextSwitchTo(TopMemoryContext); MemoryContextSwitchTo(TopMemoryContext);
#ifndef EXEC_BACKEND
MemoryContextDelete(PostmasterContext); MemoryContextDelete(PostmasterContext);
#endif
PostmasterContext = NULL; PostmasterContext = NULL;
/* /*
...@@ -2673,111 +2698,176 @@ BackendRun(Port *port) ...@@ -2673,111 +2698,176 @@ BackendRun(Port *port)
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
/* /*
* SubPostmasterMain -- prepare the fork/exec'd process to be in an equivalent * postmaster_forkexec -- fork and exec a postmaster subprocess
* state (for calling BackendRun) as a forked process.
* *
* returns: * The caller must have set up the argv array already, except for argv[2]
* Shouldn't return at all. * 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 pid_t
SubPostmasterMain(int argc, char *argv[]) postmaster_forkexec(int argc, char *argv[])
{ {
unsigned long backendID;
Port port; Port port;
memset((void *) &port, 0, sizeof(Port)); /* This entry point passes dummy values for the Port variables */
Assert(argc == 2); 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 */ av[ac++] = "postgres";
IsPostmasterEnvironment = true; av[ac++] = "-forkbackend";
whereToSendOutput = None; av[ac++] = NULL; /* filled in by internal_forkexec */
/* Setup global context */ av[ac] = NULL;
MemoryContextInit(); Assert(ac < lengthof(av));
InitializeGUCOptions();
/* Parse passed-in context */ return internal_forkexec(ac, av, port);
argc = 0; }
backendID = (unsigned long) atol(argv[argc++]);
DataDir = strdup(argv[argc++]);
/* Read in file-based context */ static pid_t
read_backend_variables(backendID, &port); internal_forkexec(int argc, char *argv[], Port *port)
read_nondefault_variables(); {
pid_t pid;
char tmpfilename[MAXPGPATH];
/* Remaining initialization */ if (!write_backend_variables(tmpfilename, port))
pgstat_init_forkexec_backend(); return -1; /* log made by write_backend_variables */
/* FIXME: [fork/exec] Ugh */ /* Make sure caller set up argv properly */
load_hba(); Assert(argc >= 3);
load_ident(); Assert(argv[argc] == NULL);
load_user(); Assert(strncmp(argv[1], "-fork", 5) == 0);
load_group(); Assert(argv[2] == NULL);
/* Attach process to shared segments */ /* Insert temp file name after -fork argument */
CreateSharedMemoryAndSemaphores(false, MaxBackends, 0); argv[2] = tmpfilename;
/* Run backend */ #ifdef WIN32
proc_exit(BackendRun(&port)); 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 first two command line arguments are expected to be "-forkFOO"
* the pid of the fork/exec'd process * (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 int
Backend_forkexec(Port *port) SubPostmasterMain(int argc, char *argv[])
{ {
pid_t pid; Port port;
char *av[5];
int ac = 0,
bufc = 0,
i;
char buf[2][MAXPGPATH];
if (!write_backend_variables(port)) /* Do this sooner rather than later... */
return -1; /* log made by write_backend_variables */ IsUnderPostmaster = true; /* we are a postmaster subprocess now */
av[ac++] = "postgres"; MyProcPid = getpid(); /* reset MyProcPid */
av[ac++] = "-forkexec";
/* Format up context to pass to exec'd process */ /* In EXEC_BACKEND case we will not have inherited these settings */
snprintf(buf[bufc++], MAXPGPATH, "%lu", tmpBackendFileNum); IsPostmasterEnvironment = true;
snprintf(buf[bufc++], MAXPGPATH, "\"%s\"", DataDir); whereToSendOutput = None;
pqinitmask();
PG_SETMASK(&BlockSig);
/* Add to the arg list */ /* Setup essential subsystems */
Assert(bufc <= lengthof(buf)); MemoryContextInit();
for (i = 0; i < bufc; i++) InitializeGUCOptions();
av[ac++] = buf[i];
/* FIXME: [fork/exec] ExtraOptions? */ /* Check we got appropriate args */
if (argc < 3)
elog(FATAL, "invalid subpostmaster invocation");
av[ac++] = NULL; /* Read in file-based context */
Assert(ac <= lengthof(av)); memset(&port, 0, sizeof(Port));
read_backend_variables(argv[2], &port);
read_nondefault_variables();
#ifdef WIN32 /* Run backend or appropriate child */
pid = win32_forkexec(postgres_exec_path, av); /* logs on error */ if (strcmp(argv[1], "-forkbackend") == 0)
#else {
/* Fire off execv in child */ /* BackendRun will close sockets */
if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
/* 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 * Do NOT close postmaster sockets here, because we are forking from
* to issue error (unlike pgstat case) * pgstat buffer process, which already did it.
*/ */
abort();
#endif /* Do not want to attach to shared memory */
return pid; /* Parent returns pid */
PgstatCollectorMain(argc, argv);
ExitPostmaster(0);
}
return 1; /* shouldn't get here */
} }
#endif
#endif /* EXEC_BACKEND */
/* /*
...@@ -2984,80 +3074,61 @@ CountChildren(void) ...@@ -2984,80 +3074,61 @@ CountChildren(void)
return cnt; 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 * xlog determines what kind of child will be started. All child types
* (0 is returned only for checkpoint/bgwriter cases). * initially go to BootstrapMain, which will handle common setup.
* *
* note: in the EXEC_BACKEND case, we delay the fork until argument list has been * Return value of SSDataBase is subprocess' PID, or 0 if failed to start
* established * subprocess (0 is returned only for checkpoint/bgwriter cases).
*/ */
NON_EXEC_STATIC void static pid_t
SSDataBaseInit(int xlop) 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 #ifdef EXEC_BACKEND
/* In EXEC case we will not have inherited these settings */ av[ac++] = "-forkboot";
IsPostmasterEnvironment = true; av[ac++] = NULL; /* filled in by postmaster_forkexec */
whereToSendOutput = None;
#endif #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 */ av[ac++] = "-p";
on_exit_reset(); av[ac++] = "template1";
av[ac] = NULL;
Assert(ac < lengthof(av));
/* /*
* Identify myself via ps * Flush stdio channels (see comments in BackendStartup)
*/ */
switch (xlop) fflush(stdout);
{ fflush(stderr);
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("");
}
static pid_t #ifdef EXEC_BACKEND
SSDataBase(int xlop)
{
pid_t pid;
Backend *bn;
#ifndef EXEC_BACKEND pid = postmaster_forkexec(ac, av);
#ifdef LINUX_PROFILE
struct itimerval prof_itimer;
#endif
#else
char idbuf[32];
char ddirbuf[MAXPGPATH];
#endif
fflush(stdout); #else /* !EXEC_BACKEND */
fflush(stderr);
#ifndef EXEC_BACKEND
#ifdef LINUX_PROFILE #ifdef LINUX_PROFILE
/* see comments in BackendRun */ /* see comments in BackendStartup */
getitimer(ITIMER_PROF, &prof_itimer); getitimer(ITIMER_PROF, &prof_itimer);
#endif #endif
...@@ -3066,16 +3137,10 @@ SSDataBase(int xlop) ...@@ -3066,16 +3137,10 @@ SSDataBase(int xlop)
beos_before_backend_startup(); beos_before_backend_startup();
#endif #endif
/* Non EXEC_BACKEND case; fork here */ pid = fork();
if ((pid = fork()) == 0) /* child */
#endif
{
char *av[10];
int ac = 0;
char nbbuf[32];
char xlbuf[32];
#ifndef EXEC_BACKEND if (pid == 0) /* child */
{
#ifdef LINUX_PROFILE #ifdef LINUX_PROFILE
setitimer(ITIMER_PROF, &prof_itimer, NULL); setitimer(ITIMER_PROF, &prof_itimer, NULL);
#endif #endif
...@@ -3085,72 +3150,30 @@ SSDataBase(int xlop) ...@@ -3085,72 +3150,30 @@ SSDataBase(int xlop)
beos_backend_startup(); beos_backend_startup();
#endif #endif
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
/* Close the postmaster's sockets */ /* Close the postmaster's sockets */
ClosePostmasterPorts(true); ClosePostmasterPorts(true);
SSDataBaseInit(xlop); /* Lose the postmaster's on-exit routines and port connections */
#else on_exit_reset();
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
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); BootstrapMain(ac, av);
ExitPostmaster(0); ExitPostmaster(0);
#endif
} }
/* in parent */ #endif /* EXEC_BACKEND */
if (pid < 0) if (pid < 0)
{ {
#ifndef EXEC_BACKEND /* in parent, fork failed */
int save_errno = errno;
#ifdef __BEOS__ #ifdef __BEOS__
/* Specific beos actions before backend startup */ /* Specific beos actions before backend startup */
beos_backend_startup_failed(); beos_backend_startup_failed();
#endif #endif
#endif errno = save_errno;
switch (xlop) switch (xlop)
{ {
case BS_XLOG_STARTUP: case BS_XLOG_STARTUP:
...@@ -3188,6 +3211,8 @@ SSDataBase(int xlop) ...@@ -3188,6 +3211,8 @@ SSDataBase(int xlop)
} }
/* /*
* in parent, successful fork
*
* The startup and shutdown processes are not considered normal * The startup and shutdown processes are not considered normal
* backends, but the checkpoint and bgwriter processes are. They must * backends, but the checkpoint and bgwriter processes are. They must
* be added to the list of backends. * be added to the list of backends.
...@@ -3280,7 +3305,7 @@ postmaster_error(const char *fmt,...) ...@@ -3280,7 +3305,7 @@ postmaster_error(const char *fmt,...)
* functions * functions
*/ */
#include "storage/spin.h" #include "storage/spin.h"
extern XLogwrtResult LogwrtResult;
extern slock_t *ShmemLock; extern slock_t *ShmemLock;
extern slock_t *ShmemIndexLock; extern slock_t *ShmemIndexLock;
extern void *ShmemIndexAlloc; extern void *ShmemIndexAlloc;
...@@ -3291,24 +3316,19 @@ extern int pgStatSock; ...@@ -3291,24 +3316,19 @@ extern int pgStatSock;
#define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp) #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 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 static bool
write_backend_variables(Port *port) write_backend_variables(char *filename, Port *port)
{ {
char filename[MAXPGPATH]; static unsigned long tmpBackendFileNum = 0;
FILE *fp; 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 */ /* Open file */
fp = AllocateFile(filename, PG_BINARY_W); fp = AllocateFile(filename, PG_BINARY_W);
...@@ -3317,33 +3337,38 @@ write_backend_variables(Port *port) ...@@ -3317,33 +3337,38 @@ write_backend_variables(Port *port)
/* As per OpenTemporaryFile... */ /* As per OpenTemporaryFile... */
char dirname[MAXPGPATH]; 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); mkdir(dirname, S_IRWXU);
fp = AllocateFile(filename, PG_BINARY_W); fp = AllocateFile(filename, PG_BINARY_W);
if (!fp) if (!fp)
{ {
ereport(ERROR, ereport(LOG,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m", filename))); errmsg("could not create file \"%s\": %m",
filename)));
return false; return false;
} }
} }
/* Write vars */ /* Write vars */
if (port) write_var(port->sock, fp);
{ write_var(port->proto, fp);
write_var(port->sock, fp); write_var(port->laddr, fp);
write_var(port->proto, fp); write_var(port->raddr, fp);
write_var(port->laddr, fp); write_var(port->canAcceptConnections, fp);
write_var(port->raddr, fp); write_var(port->cryptSalt, fp);
write_var(port->canAcceptConnections, fp); write_var(port->md5Salt, fp);
write_var(port->cryptSalt, fp);
write_var(port->md5Salt, fp); /*
} * XXX FIXME later: writing these strings as MAXPGPATH bytes always is
write_var(MyCancelKey, fp); * 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(UsedShmemSegID, fp);
write_var(UsedShmemSegAddr, fp); write_var(UsedShmemSegAddr, fp);
...@@ -3358,12 +3383,18 @@ write_backend_variables(Port *port) ...@@ -3358,12 +3383,18 @@ write_backend_variables(Port *port)
write_var(ProcStructLock, fp); write_var(ProcStructLock, fp);
write_var(pgStatSock, fp); write_var(pgStatSock, fp);
write_var(PreAuthDelay, fp);
write_var(debug_flag, fp); write_var(debug_flag, fp);
write_var(PostmasterPid, fp); write_var(PostmasterPid, fp);
fwrite((void *) my_exec_path, MAXPGPATH, 1, 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 */ /* Release file */
if (FreeFile(fp)) if (FreeFile(fp))
{ {
...@@ -3376,38 +3407,33 @@ write_backend_variables(Port *port) ...@@ -3376,38 +3407,33 @@ write_backend_variables(Port *port)
return true; return true;
} }
void static void
read_backend_variables(unsigned long id, Port *port) read_backend_variables(char *filename, Port *port)
{ {
char filename[MAXPGPATH];
FILE *fp; FILE *fp;
char str_buf[MAXPGPATH];
get_tmp_backend_file_name(filename, id);
/* Open file */ /* Open file */
fp = AllocateFile(filename, PG_BINARY_R); fp = AllocateFile(filename, PG_BINARY_R);
if (!fp) if (!fp)
{ ereport(FATAL,
ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read from backend_variables file \"%s\": %m", filename))); errmsg("could not read from backend variables file \"%s\": %m",
return; filename)));
}
/* Read vars */ /* Read vars */
if (port) read_var(port->sock, fp);
{ read_var(port->proto, fp);
read_var(port->sock, fp); read_var(port->laddr, fp);
read_var(port->proto, fp); read_var(port->raddr, fp);
read_var(port->laddr, fp); read_var(port->canAcceptConnections, fp);
read_var(port->raddr, fp); read_var(port->cryptSalt, fp);
read_var(port->canAcceptConnections, fp); read_var(port->md5Salt, fp);
read_var(port->cryptSalt, fp);
read_var(port->md5Salt, fp);
}
read_var(MyCancelKey, 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(UsedShmemSegID, fp);
read_var(UsedShmemSegAddr, fp); read_var(UsedShmemSegAddr, fp);
...@@ -3422,12 +3448,18 @@ read_backend_variables(unsigned long id, Port *port) ...@@ -3422,12 +3448,18 @@ read_backend_variables(unsigned long id, Port *port)
read_var(ProcStructLock, fp); read_var(ProcStructLock, fp);
read_var(pgStatSock, fp); read_var(pgStatSock, fp);
read_var(PreAuthDelay, fp);
read_var(debug_flag, fp); read_var(debug_flag, fp);
read_var(PostmasterPid, fp); read_var(PostmasterPid, fp);
fread((void *) my_exec_path, MAXPGPATH, 1, 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 */ /* Release file */
FreeFile(fp); FreeFile(fp);
if (unlink(filename) != 0) if (unlink(filename) != 0)
...@@ -3490,52 +3522,54 @@ ShmemBackendArrayRemove(pid_t pid) ...@@ -3490,52 +3522,54 @@ ShmemBackendArrayRemove(pid_t pid)
(errmsg_internal("unable to find backend entry with pid %d", (errmsg_internal("unable to find backend entry with pid %d",
pid))); pid)));
} }
#endif
#endif /* EXEC_BACKEND */
#ifdef WIN32 #ifdef WIN32
pid_t static pid_t
win32_forkexec(const char *path, char *argv[]) win32_forkexec(const char *path, char *argv[])
{ {
STARTUPINFO si; STARTUPINFO si;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
char *p; char *p;
int i; int i;
char cmdLine[MAXPGPATH]; int j;
char cmdLine[MAXPGPATH * 2];
HANDLE childHandleCopy; HANDLE childHandleCopy;
HANDLE waiterThread; HANDLE waiterThread;
/* Format the cmd line */ /* 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; i = 0;
while (argv[++i] != NULL) while (argv[++i] != NULL)
{ {
/* FIXME: [fork/exec] some strlen checks might be prudent here */ j = strlen(cmdLine);
strcat(cmdLine, " "); snprintf(cmdLine+j, sizeof(cmdLine)-1-j, " \"%s\"", argv[i]);
strcat(cmdLine, 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(&pi, 0, sizeof(pi));
memset(&si, 0, sizeof(si)); memset(&si, 0, sizeof(si));
si.cb = sizeof(si); si.cb = sizeof(si);
if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) 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; return -1;
} }
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{
/* We are the Postmaster creating a child... */ /* We are the Postmaster creating a child... */
win32_AddChild(pi.dwProcessId, pi.hProcess); win32_AddChild(pi.dwProcessId, pi.hProcess);
}
if (!DuplicateHandle(GetCurrentProcess(), if (!DuplicateHandle(GetCurrentProcess(),
pi.hProcess, pi.hProcess,
...@@ -3545,11 +3579,15 @@ win32_forkexec(const char *path, char *argv[]) ...@@ -3545,11 +3579,15 @@ win32_forkexec(const char *path, char *argv[])
FALSE, FALSE,
DUPLICATE_SAME_ACCESS)) DUPLICATE_SAME_ACCESS))
ereport(FATAL, ereport(FATAL,
(errmsg_internal("failed to duplicate child handle: %i", (int) GetLastError()))); (errmsg_internal("failed to duplicate child handle: %d",
waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter, (LPVOID) childHandleCopy, 0, NULL); (int) GetLastError())));
waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter,
(LPVOID) childHandleCopy, 0, NULL);
if (!waiterThread) if (!waiterThread)
ereport(FATAL, 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); CloseHandle(waiterThread);
if (IsUnderPostmaster) if (IsUnderPostmaster)
...@@ -3582,7 +3620,7 @@ win32_AddChild(pid_t pid, HANDLE handle) ...@@ -3582,7 +3620,7 @@ win32_AddChild(pid_t pid, HANDLE handle)
else else
ereport(FATAL, ereport(FATAL,
(errmsg_internal("unable to add child entry with pid %lu", (errmsg_internal("unable to add child entry with pid %lu",
pid))); (unsigned long) pid)));
} }
static void static void
...@@ -3608,7 +3646,7 @@ win32_RemoveChild(pid_t pid) ...@@ -3608,7 +3646,7 @@ win32_RemoveChild(pid_t pid)
ereport(WARNING, ereport(WARNING,
(errmsg_internal("unable to find child entry with pid %lu", (errmsg_internal("unable to find child entry with pid %lu",
pid))); (unsigned long) pid)));
} }
static pid_t static pid_t
...@@ -3678,9 +3716,10 @@ win32_sigchld_waiter(LPVOID param) ...@@ -3678,9 +3716,10 @@ win32_sigchld_waiter(LPVOID param)
if (r == WAIT_OBJECT_0) if (r == WAIT_OBJECT_0)
pg_queue_signal(SIGCHLD); pg_queue_signal(SIGCHLD);
else 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); CloseHandle(procHandle);
return 0; return 0;
} }
#endif #endif /* WIN32 */
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -93,15 +93,6 @@ InitBufferPool(void)
foundDescs; foundDescs;
int i; 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 *) BufferDescriptors = (BufferDesc *)
ShmemInitStruct("Buffer Descriptors", ShmemInitStruct("Buffer Descriptors",
NBuffers * sizeof(BufferDesc), &foundDescs); NBuffers * sizeof(BufferDesc), &foundDescs);
...@@ -120,6 +111,13 @@ InitBufferPool(void) ...@@ -120,6 +111,13 @@ InitBufferPool(void)
BufferDesc *buf; BufferDesc *buf;
char *block; 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; buf = BufferDescriptors;
block = BufferBlocks; block = BufferBlocks;
...@@ -147,14 +145,12 @@ InitBufferPool(void) ...@@ -147,14 +145,12 @@ InitBufferPool(void)
/* Correct last entry */ /* Correct last entry */
BufferDescriptors[NBuffers - 1].bufNext = -1; BufferDescriptors[NBuffers - 1].bufNext = -1;
LWLockRelease(BufMgrLock);
} }
/* Init other shared buffer-management stuff */ /* Init other shared buffer-management stuff */
StrategyInitialize(!foundDescs); StrategyInitialize(!foundDescs);
#ifndef EXEC_BACKEND
LWLockRelease(BufMgrLock);
#endif
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -37,9 +37,13 @@
* *
* This is called by the postmaster or by a standalone backend. * This is called by the postmaster or by a standalone backend.
* It is also called by a backend forked from the postmaster under * It is also called by a backend forked from the postmaster under
* the EXEC_BACKEND case * the EXEC_BACKEND case. (In the non EXEC_BACKEND case, backends
* * start life already attached to shared memory.) The initialization
* In the non EXEC_BACKEND case, backends already have shared memory ready-to-go. * 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 * If "makePrivate" is true then we only need private memory, not shared
* memory. This is true for a standalone backend, false for a postmaster. * memory. This is true for a standalone backend, false for a postmaster.
...@@ -96,8 +100,12 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, ...@@ -96,8 +100,12 @@ CreateSharedMemoryAndSemaphores(bool makePrivate,
* (this should only ever be reached by EXEC_BACKEND code, * (this should only ever be reached by EXEC_BACKEND code,
* and only then with makePrivate == false) * and only then with makePrivate == false)
*/ */
Assert(ExecBackend && !makePrivate); #ifdef EXEC_BACKEND
Assert(!makePrivate);
seghdr = PGSharedMemoryCreate(-1, makePrivate, 0); seghdr = PGSharedMemoryCreate(-1, makePrivate, 0);
#else
Assert(false);
#endif
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -75,6 +75,13 @@ InitLockTable(int maxBackends)
{ {
LOCKMETHODID LongTermTableId; 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 */ /* number of lock modes is lengthof()-1 because of dummy zero */
LockTableId = LockMethodTableInit("LockTable", LockTableId = LockMethodTableInit("LockTable",
LockConflicts, LockConflicts,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Outside modules can create a lock table and acquire/release * Outside modules can create a lock table and acquire/release
...@@ -155,7 +155,9 @@ PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP) ...@@ -155,7 +155,9 @@ PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
static LockMethod LockMethods[MAX_LOCK_METHODS]; static LockMethod LockMethods[MAX_LOCK_METHODS];
static HTAB* LockMethodLockHash[MAX_LOCK_METHODS]; static HTAB* LockMethodLockHash[MAX_LOCK_METHODS];
static HTAB* LockMethodProcLockHash[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) ...@@ -190,15 +192,15 @@ GetLocksMethodTable(LOCK *lock)
*/ */
static void static void
LockMethodInit(LockMethod lockMethodTable, LockMethodInit(LockMethod lockMethodTable,
LOCKMASK *conflictsP, const LOCKMASK *conflictsP,
int numModes) int numModes)
{ {
int i; int i;
lockMethodTable->numLockModes = numModes; lockMethodTable->numLockModes = numModes;
/* copies useless zero element as well as the N lockmodes */ /* copies useless zero element as well as the N lockmodes */
for (i = 0; i <= numModes; i++, conflictsP++) for (i = 0; i <= numModes; i++)
lockMethodTable->conflictTab[i] = *conflictsP; lockMethodTable->conflictTab[i] = conflictsP[i];
} }
/* /*
...@@ -211,8 +213,8 @@ LockMethodInit(LockMethod lockMethodTable, ...@@ -211,8 +213,8 @@ LockMethodInit(LockMethod lockMethodTable,
* TopMemoryContext. * TopMemoryContext.
*/ */
LOCKMETHODID LOCKMETHODID
LockMethodTableInit(char *tabName, LockMethodTableInit(const char *tabName,
LOCKMASK *conflictsP, const LOCKMASK *conflictsP,
int numModes, int numModes,
int maxBackends) int maxBackends)
{ {
...@@ -244,17 +246,6 @@ LockMethodTableInit(char *tabName, ...@@ -244,17 +246,6 @@ LockMethodTableInit(char *tabName,
if (!newLockMethod) if (!newLockMethod)
elog(FATAL, "could not initialize lock table \"%s\"", 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 * we're first - initialize
*/ */
...@@ -263,6 +254,7 @@ LockMethodTableInit(char *tabName, ...@@ -263,6 +254,7 @@ LockMethodTableInit(char *tabName,
MemSet(newLockMethod, 0, sizeof(LockMethodData)); MemSet(newLockMethod, 0, sizeof(LockMethodData));
newLockMethod->masterLock = LockMgrLock; newLockMethod->masterLock = LockMgrLock;
newLockMethod->lockmethodid = NumLockMethods; newLockMethod->lockmethodid = NumLockMethods;
LockMethodInit(newLockMethod, conflictsP, numModes);
} }
/* /*
...@@ -311,12 +303,6 @@ LockMethodTableInit(char *tabName, ...@@ -311,12 +303,6 @@ LockMethodTableInit(char *tabName,
if (!LockMethodProcLockHash[NumLockMethods-1]) if (!LockMethodProcLockHash[NumLockMethods-1])
elog(FATAL, "could not initialize lock table \"%s\"", tabName); elog(FATAL, "could not initialize lock table \"%s\"", tabName);
/* init data structures */
LockMethodInit(newLockMethod, conflictsP, numModes);
#ifndef EXEC_BACKEND
LWLockRelease(LockMgrLock);
#endif
pfree(shmemName); pfree(shmemName);
return newLockMethod->lockmethodid; return newLockMethod->lockmethodid;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -2189,10 +2189,13 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -2189,10 +2189,13 @@ PostgresMain(int argc, char *argv[], const char *username)
/* Set up reference point for stack depth checking */ /* Set up reference point for stack depth checking */
stack_base_ptr = &stack_base; stack_base_ptr = &stack_base;
if (my_exec_path[0] == '\0' && find_my_exec(argv[0], my_exec_path) < 0) /* Compute paths, if we didn't inherit them from postmaster */
elog(FATAL, if (my_exec_path[0] == '\0')
gettext("%s: could not locate my own executable path"), {
argv[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') if (pkglib_path[0] == '\0')
get_pkglib_path(my_exec_path, pkglib_path); get_pkglib_path(my_exec_path, pkglib_path);
...@@ -2547,7 +2550,7 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -2547,7 +2550,7 @@ PostgresMain(int argc, char *argv[], const char *username)
on_proc_exit(log_disconnections,0); on_proc_exit(log_disconnections,0);
} }
if (!IsUnderPostmaster || ExecBackend) if (!IsUnderPostmaster)
{ {
if (!potential_DataDir) if (!potential_DataDir)
{ {
...@@ -2563,17 +2566,14 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -2563,17 +2566,14 @@ PostgresMain(int argc, char *argv[], const char *username)
} }
Assert(DataDir); Assert(DataDir);
/* Acquire configuration parameters */ /* Acquire configuration parameters, unless inherited from postmaster */
if (IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
#ifdef EXEC_BACKEND
read_nondefault_variables();
#endif
} else
ProcessConfigFile(PGC_POSTMASTER); ProcessConfigFile(PGC_POSTMASTER);
/* If timezone is not set, determine what the OS uses */ /* If timezone is not set, determine what the OS uses */
pg_timezone_initialize(); pg_timezone_initialize();
}
/* /*
* Set up signal handlers and masks. * Set up signal handlers and masks.
...@@ -2918,11 +2918,7 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -2918,11 +2918,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (got_SIGHUP) if (got_SIGHUP)
{ {
got_SIGHUP = false; got_SIGHUP = false;
#ifdef EXEC_BACKEND
read_nondefault_variables();
#else
ProcessConfigFile(PGC_SIGHUP); ProcessConfigFile(PGC_SIGHUP);
#endif
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Globals used all over the place should be declared here and not * Globals used all over the place should be declared here and not
...@@ -43,11 +43,15 @@ char *DataDir = NULL; ...@@ -43,11 +43,15 @@ char *DataDir = NULL;
* variable. NULL if no option given and no environment variable set * 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 my_exec_path[MAXPGPATH]; /* full path to my executable */
char postgres_exec_path[MAXPGPATH]; /* full path to backend executable */ char pkglib_path[MAXPGPATH]; /* full path to lib directory */
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; BackendId MyBackendId;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 2003, PostgreSQL Global Development Group * Portions Copyright (c) 2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef SLRU_H
#define SLRU_H #define SLRU_H
...@@ -16,35 +16,38 @@ ...@@ -16,35 +16,38 @@
/* exported because lwlock.c needs it */ /* exported because lwlock.c needs it */
#define NUM_CLOG_BUFFERS 8 #define NUM_CLOG_BUFFERS 8
/*
* Note: the separation between SlruLockData and SlruSharedData is purely
* historical; the structs could be combined.
*/
typedef struct SlruLockData typedef struct SlruLockData
{ {
LWLockId ControlLock; 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 */ LWLockId BufferLocks[NUM_CLOG_BUFFERS]; /* Per-buffer I/O locks */
} SlruLockData; } SlruLockData;
typedef SlruLockData *SlruLock; typedef SlruLockData *SlruLock;
/*
* SlruCtlData is an unshared structure that points to the active information
* in shared memory.
*/
typedef struct SlruCtlData typedef struct SlruCtlData
{ {
void *shared; /* pointer to SlruSharedData */ void *shared; /* pointer to SlruSharedData */
SlruLock locks; SlruLock locks;
/* /*
* Dir is set during SimpleLruShmemInit and does not change thereafter. * Dir is set during SimpleLruShmemInit and does not change thereafter.
* The value is automatically inherited by backends via fork, and * The value is automatically inherited by backends via fork, and
* doesn't need to be in shared memory. * doesn't need to be in shared memory.
*/ */
char Dir[MAXPGPATH]; char Dir[MAXPGPATH];
/* /*
* Decide which of two page numbers is "older" for truncation purposes. * 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 * We need to use comparison of TransactionIds here in order to do the
* thing with wraparound XID arithmetic. * right thing with wraparound XID arithmetic.
*/ */
bool (*PagePrecedes) (int, int); bool (*PagePrecedes) (int, int);
} SlruCtlData; } SlruCtlData;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -34,7 +34,7 @@ typedef struct hashnode
extern Relation boot_reldesc; extern Relation boot_reldesc;
extern Form_pg_attribute attrtypes[MAXATTR]; extern Form_pg_attribute attrtypes[MAXATTR];
extern int numattr; 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); extern void index_register(Oid heap, Oid ind, IndexInfo *indexInfo);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* some of the information in this file should be moved to * some of the information in this file should be moved to
...@@ -116,13 +116,13 @@ do { \ ...@@ -116,13 +116,13 @@ do { \
* from postmaster/postmaster.c * from postmaster/postmaster.c
*/ */
extern bool ClientAuthInProgress; extern bool ClientAuthInProgress;
extern const bool ExecBackend;
extern int PostmasterMain(int argc, char *argv[]); extern int PostmasterMain(int argc, char *argv[]);
extern void ClosePostmasterPorts(bool pgstat_too);
#ifdef EXEC_BACKEND #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 #endif
extern void ClosePostmasterPorts(bool pgstat_too);
#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n" #define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
...@@ -143,8 +143,10 @@ extern long MyCancelKey; ...@@ -143,8 +143,10 @@ extern long MyCancelKey;
extern char OutputFileName[]; extern char OutputFileName[];
extern char my_exec_path[]; extern char my_exec_path[];
extern char postgres_exec_path[];
extern char pkglib_path[]; extern char pkglib_path[];
#ifdef EXEC_BACKEND
extern char postgres_exec_path[];
#endif
/* /*
* done in storage/backendid.h for now. * done in storage/backendid.h for now.
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 2001-2003, PostgreSQL Global Development Group * 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 #ifndef PGSTAT_H
...@@ -325,18 +325,6 @@ typedef union PgStat_Msg ...@@ -325,18 +325,6 @@ typedef union PgStat_Msg
} 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 * GUC parameters
* ---------- * ----------
...@@ -354,29 +342,22 @@ extern bool pgstat_collect_blocklevel; ...@@ -354,29 +342,22 @@ extern bool pgstat_collect_blocklevel;
extern bool pgstat_is_running; 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 * Functions called from postmaster
* ---------- * ----------
*/ */
#ifdef EXEC_BACKEND
extern void pgstat_init_forkexec_backend(void);
#endif
extern void pgstat_init(void); extern void pgstat_init(void);
extern void pgstat_start(void); extern void pgstat_start(void);
extern bool pgstat_ispgstat(int pid); extern bool pgstat_ispgstat(int pid);
extern void pgstat_close_sockets(void); extern void pgstat_close_sockets(void);
extern void pgstat_beterm(int pid); 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 * Functions called from backends
* ---------- * ----------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -223,13 +223,16 @@ typedef struct
LOCK *locks; LOCK *locks;
} LockData; } LockData;
extern int NumLockMethods;
/* /*
* function prototypes * function prototypes
*/ */
extern void InitLocks(void); extern void InitLocks(void);
extern LockMethod GetLocksMethodTable(LOCK *lock); extern LockMethod GetLocksMethodTable(LOCK *lock);
extern LOCKMETHODID LockMethodTableInit(char *tabName, LOCKMASK *conflictsP, extern LOCKMETHODID LockMethodTableInit(const char *tabName,
int numModes, int maxBackends); const LOCKMASK *conflictsP,
int numModes, int maxBackends);
extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid); extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid);
extern bool LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, extern bool LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
TransactionId xid, LOCKMODE lockmode, bool dontWait); TransactionId xid, LOCKMODE lockmode, bool dontWait);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 2000-2003, PostgreSQL Global Development Group * Copyright (c) 2000-2003, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>. * 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 #ifndef GUC_H
...@@ -206,8 +206,8 @@ extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *va ...@@ -206,8 +206,8 @@ extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *va
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name); extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
void write_nondefault_variables(GucContext context); extern void write_nondefault_variables(GucContext context);
void read_nondefault_variables(void); extern void read_nondefault_variables(void);
#endif #endif
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment