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