]> granicus.if.org Git - postgresql/commitdiff
Rearrange backend startup sequence so that ShmemIndexLock can become
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 4 Jan 2006 21:06:32 +0000 (21:06 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 4 Jan 2006 21:06:32 +0000 (21:06 +0000)
an LWLock instead of a spinlock.  This hardly matters on Unix machines
but should improve startup performance on Windows (or any port using
EXEC_BACKEND).  Per previous discussion.

15 files changed:
src/backend/bootstrap/bootstrap.c
src/backend/postmaster/autovacuum.c
src/backend/postmaster/pgarch.c
src/backend/postmaster/pgstat.c
src/backend/postmaster/postmaster.c
src/backend/postmaster/syslogger.c
src/backend/storage/ipc/ipci.c
src/backend/storage/ipc/shmem.c
src/backend/storage/lmgr/proc.c
src/backend/tcop/postgres.c
src/backend/utils/init/postinit.c
src/include/storage/lwlock.h
src/include/storage/pg_shmem.h
src/include/storage/proc.h
src/include/storage/shmem.h

index 283ca246473260f1b3466f2e1e6280d4e5d918a5..66cf4c4ce0ac20645b29851530bae666fd000734 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.209 2005/11/22 18:17:07 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.210 2006/01/04 21:06:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -381,22 +381,19 @@ BootstrapMain(int argc, char *argv[])
        BaseInit();
 
        /*
-        * We aren't going to do the full InitPostgres pushups, but there are a
-        * couple of things that need to get lit up even in a dummy process.
+        * When we are a dummy process, we aren't going to do the full
+        * InitPostgres pushups, but there are a couple of things that need
+        * to get lit up even in a dummy process.
         */
        if (IsUnderPostmaster)
        {
-               /* set up proc.c to get use of LWLocks */
-               switch (xlogop)
-               {
-                       case BS_XLOG_BGWRITER:
-                               InitDummyProcess(DUMMY_PROC_BGWRITER);
-                               break;
-
-                       default:
-                               InitDummyProcess(DUMMY_PROC_DEFAULT);
-                               break;
-               }
+               /*
+                * Create a PGPROC so we can use LWLocks.  In the EXEC_BACKEND case,
+                * this was already done by SubPostmasterMain().
+                */
+#ifndef EXEC_BACKEND
+               InitDummyProcess();
+#endif
 
                /* finish setting up bufmgr.c */
                InitBufferPoolBackend();
@@ -437,11 +434,17 @@ BootstrapMain(int argc, char *argv[])
                        proc_exit(1);
        }
 
+       /*
+        * We must be getting invoked for bootstrap mode
+        */
+       Assert(!IsUnderPostmaster);
+
        SetProcessingMode(BootstrapProcessing);
 
        /*
-        * backend initialization
+        * Do backend-like initialization for bootstrap mode
         */
+       InitProcess();
        (void) InitPostgres(dbname, NULL);
 
        /*
index 0049f4307cdf68bd4aa1be244ee6f2464ace2bac..c2b6ac1a2988d496f725ccba3e95ae93bc77c5a2 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.8 2005/11/28 17:23:11 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.9 2006/01/04 21:06:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -167,6 +167,9 @@ autovac_start(void)
                        /* Close the postmaster's sockets */
                        ClosePostmasterPorts(false);
 
+                       /* Lose the postmaster's on-exit routines */
+                       on_exit_reset();
+
                        AutoVacMain(0, NULL);
                        break;
 #endif
@@ -230,9 +233,6 @@ AutoVacMain(int argc, char *argv[])
        /* reset MyProcPid */
        MyProcPid = getpid();
 
-       /* Lose the postmaster's on-exit routines */
-       on_exit_reset();
-
        /* Identify myself via ps */
        init_ps_display("autovacuum process", "", "");
        set_ps_display("");
@@ -268,6 +268,16 @@ AutoVacMain(int argc, char *argv[])
        /* Early initialization */
        BaseInit();
 
+       /*
+        * Create a per-backend PGPROC struct in shared memory, except in
+        * the EXEC_BACKEND case where this was done in SubPostmasterMain.
+        * We must do this before we can use LWLocks (and in the EXEC_BACKEND
+        * case we already had to do some stuff with LWLocks).
+        */
+#ifndef EXEC_BACKEND
+       InitProcess();
+#endif
+
        /*
         * If an exception is encountered, processing resumes here.
         *
index 61019d7a5e3b405c8a6ffdca490887d458e49eea..7b604b9f9f993d57c40c8cd04f3abcedface372d 100644 (file)
@@ -19,7 +19,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.18 2005/10/15 02:49:23 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.19 2006/01/04 21:06:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -158,6 +158,9 @@ pgarch_start(void)
                        /* Close the postmaster's sockets */
                        ClosePostmasterPorts(false);
 
+                       /* Lose the postmaster's on-exit routines */
+                       on_exit_reset();
+
                        /* Drop our connection to postmaster's shared memory, as well */
                        PGSharedMemoryDetach();
 
@@ -219,9 +222,6 @@ PgArchiverMain(int argc, char *argv[])
 
        MyProcPid = getpid();           /* reset MyProcPid */
 
-       /* Lose the postmaster's on-exit routines */
-       on_exit_reset();
-
        /*
         * Ignore all signals usually bound to some action in the postmaster,
         * except for SIGHUP, SIGUSR1 and SIGQUIT.
index a192b4e5c878beccdd4473f2e31163c527c077bc..d4a07efce2f0de60dcd2d0cdd99d2c81b2ccd425 100644 (file)
@@ -13,7 +13,7 @@
  *
  *     Copyright (c) 2001-2005, PostgreSQL Global Development Group
  *
- *     $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.118 2006/01/03 19:54:08 momjian Exp $
+ *     $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.119 2006/01/04 21:06:31 tgl Exp $
  * ----------
  */
 #include "postgres.h"
@@ -147,6 +147,7 @@ static int  pgStatNumBackends = 0;
 
 static volatile bool   need_statwrite;
 
+
 /* ----------
  * Local function forward declarations
  * ----------
@@ -608,6 +609,9 @@ pgstat_start(void)
                        /* Close the postmaster's sockets */
                        ClosePostmasterPorts(false);
 
+                       /* Lose the postmaster's on-exit routines */
+                       on_exit_reset();
+
                        /* Drop our connection to postmaster's shared memory, as well */
                        PGSharedMemoryDetach();
 
@@ -1465,9 +1469,6 @@ PgstatBufferMain(int argc, char *argv[])
 
        MyProcPid = getpid();           /* reset MyProcPid */
 
-       /* Lose the postmaster's on-exit routines */
-       on_exit_reset();
-
        /*
         * Ignore all signals usually bound to some action in the postmaster,
         * except for SIGCHLD and SIGQUIT --- see pgstat_recvbuffer.
@@ -1551,10 +1552,10 @@ PgstatCollectorMain(int argc, char *argv[])
        fd_set          rfds;
        int                     readPipe;
        int                     len = 0;
-       struct itimerval timeval;
+       struct itimerval timeout;
        HASHCTL         hash_ctl;
        bool            need_timer = false;
-       
+
        MyProcPid = getpid();           /* reset MyProcPid */
 
        /*
@@ -1597,11 +1598,15 @@ PgstatCollectorMain(int argc, char *argv[])
        init_ps_display("stats collector process", "", "");
        set_ps_display("");
 
+       /*
+        * Arrange to write the initial status file right away
+        */
        need_statwrite = true;
 
-       MemSet(&timeval, 0, sizeof(struct itimerval));
-       timeval.it_value.tv_sec = PGSTAT_STAT_INTERVAL / 1000;
-       timeval.it_value.tv_usec = PGSTAT_STAT_INTERVAL % 1000;
+       /* Preset the delay between status file writes */
+       MemSet(&timeout, 0, sizeof(struct itimerval));
+       timeout.it_value.tv_sec = PGSTAT_STAT_INTERVAL / 1000;
+       timeout.it_value.tv_usec = PGSTAT_STAT_INTERVAL % 1000;
 
        /*
         * Read in an existing statistics stats file or initialize the stats to
@@ -1634,6 +1639,12 @@ PgstatCollectorMain(int argc, char *argv[])
         */
        for (;;)
        {
+               /*
+                * If time to write the stats file, do so.  Note that the alarm
+                * interrupt isn't re-enabled immediately, but only after we next
+                * receive a stats message; so no cycles are wasted when there is
+                * nothing going on.
+                */
                if (need_statwrite)
                {
                        pgstat_write_statsfile();
@@ -1776,11 +1787,16 @@ PgstatCollectorMain(int argc, char *argv[])
                         */
                        pgStatNumMessages++;
 
+                       /*
+                        * If this is the first message after we wrote the stats file the
+                        * last time, enable the alarm interrupt to make it be written
+                        * again later.
+                        */
                        if (need_timer)
                        {
-                               if (setitimer(ITIMER_REAL, &timeval, NULL))
+                               if (setitimer(ITIMER_REAL, &timeout, NULL))
                                        ereport(ERROR,
-                                                 (errmsg("unable to set statistics collector timer: %m")));
+                                                 (errmsg("could not set statistics collector timer: %m")));
                                need_timer = false;
                        }
                }
@@ -1806,6 +1822,7 @@ PgstatCollectorMain(int argc, char *argv[])
 }
 
 
+/* SIGALRM signal handler for collector process */
 static void
 force_statwrite(SIGNAL_ARGS)
 {
@@ -1913,8 +1930,10 @@ pgstat_recvbuffer(void)
                /*
                 * Wait for some work to do; but not for more than 10 seconds. (This
                 * determines how quickly we will shut down after an ungraceful
-                * postmaster termination; so it needn't be very fast.)  struct timeout
-                * is modified by some operating systems.
+                * postmaster termination; so it needn't be very fast.)
+                *
+                * struct timeout is modified by select() on some operating systems,
+                * so re-fill it each time.
                 */
                timeout.tv_sec = 10;
                timeout.tv_usec = 0;
index 24212f1ffffa4d597a83f18b9c86bd8added4d53..187bfeb47ec317c79c3260933ef7de63fe69a079 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.476 2005/11/22 18:17:18 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.477 2006/01/04 21:06:31 tgl Exp $
  *
  * NOTES
  *
@@ -262,6 +262,7 @@ static void CleanupBackend(int pid, int exitstatus);
 static void HandleChildCrash(int pid, int exitstatus, const char *procname);
 static void LogChildExit(int lev, const char *procname,
                         int pid, int exitstatus);
+static void BackendInitialize(Port *port);
 static int     BackendRun(Port *port);
 static void ExitPostmaster(int status);
 static void usage(const char *);
@@ -324,12 +325,12 @@ typedef struct
        unsigned long UsedShmemSegID;
        void       *UsedShmemSegAddr;
        slock_t    *ShmemLock;
-       slock_t    *ShmemIndexLock;
        VariableCache ShmemVariableCache;
-       void       *ShmemIndexAlloc;
        Backend    *ShmemBackendArray;
        LWLock     *LWLockArray;
        slock_t    *ProcStructLock;
+       PROC_HDR   *ProcGlobal;
+       PGPROC     *DummyProcs;
        InheritableSocket pgStatSock;
        InheritableSocket pgStatPipe0;
        InheritableSocket pgStatPipe1;
@@ -2496,6 +2497,26 @@ BackendStartup(Port *port)
        if (pid == 0)                           /* child */
        {
                free(bn);
+
+               /*
+                * Let's clean up ourselves as the postmaster child, and close the
+                * postmaster's listen sockets.  (In EXEC_BACKEND case this is all
+                * done in SubPostmasterMain.)
+                */
+               IsUnderPostmaster = true;       /* we are a postmaster subprocess now */
+
+               MyProcPid = getpid();           /* reset MyProcPid */
+
+               /* We don't want the postmaster's proc_exit() handlers */
+               on_exit_reset();
+
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(false);
+
+               /* Perform additional initialization and client authentication */
+               BackendInitialize(port);
+
+               /* And run the backend */
                proc_exit(BackendRun(port));
        }
 #endif   /* EXEC_BACKEND */
@@ -2589,47 +2610,26 @@ split_opts(char **argv, int *argcp, char *s)
 
 
 /*
- * BackendRun -- perform authentication, and if successful,
- *                             set up the backend's argument list and invoke PostgresMain()
+ * BackendInitialize -- initialize an interactive (postmaster-child)
+ *                             backend process, and perform client authentication.
  *
- * returns:
- *             Shouldn't return at all.
- *             If PostgresMain() fails, return status.
+ * returns: nothing.  Will not return at all if there's any failure.
+ *
+ * Note: this code does not depend on having any access to shared memory.
+ * In the EXEC_BACKEND case, we are physically attached to shared memory
+ * but have not yet set up most of our local pointers to shmem structures.
  */
-static int
-BackendRun(Port *port)
+static void
+BackendInitialize(Port *port)
 {
        int                     status;
        char            remote_host[NI_MAXHOST];
        char            remote_port[NI_MAXSERV];
        char            remote_ps_data[NI_MAXHOST];
-       char      **av;
-       int                     maxac;
-       int                     ac;
-       char            protobuf[32];
-       int                     i;
-
-       IsUnderPostmaster = true;       /* we are a postmaster subprocess now */
-
-       /*
-        * Let's clean up ourselves as the postmaster child, and close the
-        * postmaster's listen sockets
-        */
-       ClosePostmasterPorts(false);
-
-       /* We don't want the postmaster's proc_exit() handlers */
-       on_exit_reset();
-
-       /*
-        * 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
@@ -2698,7 +2698,7 @@ BackendRun(Port *port)
                                                remote_port)));
 
        /*
-        * save remote_host and remote_port in port stucture
+        * save remote_host and remote_port in port structure
         */
        port->remote_host = strdup(remote_host);
        port->remote_port = strdup(remote_port);
@@ -2766,6 +2766,24 @@ BackendRun(Port *port)
                ereport(LOG,
                                (errmsg("connection authorized: user=%s database=%s",
                                                port->user_name, port->database_name)));
+}
+
+
+/*
+ * BackendRun -- set up the backend's argument list and invoke PostgresMain()
+ *
+ * returns:
+ *             Shouldn't return at all.
+ *             If PostgresMain() fails, return status.
+ */
+static int
+BackendRun(Port *port)
+{
+       char      **av;
+       int                     maxac;
+       int                     ac;
+       char            protobuf[32];
+       int                     i;
 
        /*
         * Don't want backend to be able to see the postmaster random number
@@ -3184,6 +3202,9 @@ SubPostmasterMain(int argc, char *argv[])
 
        MyProcPid = getpid();           /* reset MyProcPid */
 
+       /* Lose the postmaster's on-exit routines (really a no-op) */
+       on_exit_reset();
+
        /* In EXEC_BACKEND case we will not have inherited these settings */
        IsPostmasterEnvironment = true;
        whereToSendOutput = DestNone;
@@ -3229,23 +3250,43 @@ SubPostmasterMain(int argc, char *argv[])
        /* Run backend or appropriate child */
        if (strcmp(argv[1], "-forkbackend") == 0)
        {
-               /* BackendRun will close sockets */
-
-               /* Attach process to shared data structures */
-               CreateSharedMemoryAndSemaphores(false, 0);
+               Assert(argc == 3);              /* shouldn't be any more args */
 
-#ifdef USE_SSL
+               /* Close the postmaster's sockets */
+               ClosePostmasterPorts(false);
 
                /*
                 * Need to reinitialize the SSL library in the backend, since the
                 * context structures contain function pointers and cannot be passed
                 * through the parameter file.
                 */
+#ifdef USE_SSL
                if (EnableSSL)
                        secure_initialize();
 #endif
 
-               Assert(argc == 3);              /* shouldn't be any more args */
+               /*
+                * Perform additional initialization and client authentication.
+                *
+                * We want to do this before InitProcess() for a couple of reasons:
+                * 1. so that we aren't eating up a PGPROC slot while waiting on the 
+                * client.
+                * 2. so that if InitProcess() fails due to being out of PGPROC slots,
+                * we have already initialized libpq and are able to report the error
+                * to the client.
+                */
+               BackendInitialize(&port);
+
+               /* Restore basic shared memory pointers */
+               InitShmemAccess(UsedShmemSegAddr);
+
+               /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
+               InitProcess();
+
+               /* Attach process to shared data structures */
+               CreateSharedMemoryAndSemaphores(false, 0);
+
+               /* And run the backend */
                proc_exit(BackendRun(&port));
        }
        if (strcmp(argv[1], "-forkboot") == 0)
@@ -3253,6 +3294,12 @@ SubPostmasterMain(int argc, char *argv[])
                /* Close the postmaster's sockets */
                ClosePostmasterPorts(false);
 
+               /* Restore basic shared memory pointers */
+               InitShmemAccess(UsedShmemSegAddr);
+
+               /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
+               InitDummyProcess();
+
                /* Attach process to shared data structures */
                CreateSharedMemoryAndSemaphores(false, 0);
 
@@ -3264,6 +3311,12 @@ SubPostmasterMain(int argc, char *argv[])
                /* Close the postmaster's sockets */
                ClosePostmasterPorts(false);
 
+               /* Restore basic shared memory pointers */
+               InitShmemAccess(UsedShmemSegAddr);
+
+               /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
+               InitProcess();
+
                /* Attach process to shared data structures */
                CreateSharedMemoryAndSemaphores(false, 0);
 
@@ -3630,10 +3683,10 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
  * functions
  */
 extern slock_t *ShmemLock;
-extern slock_t *ShmemIndexLock;
-extern void *ShmemIndexAlloc;
 extern LWLock *LWLockArray;
 extern slock_t *ProcStructLock;
+extern PROC_HDR *ProcGlobal;
+extern PGPROC *DummyProcs;
 extern int     pgStatSock;
 extern int     pgStatPipe[2];
 
@@ -3671,13 +3724,13 @@ save_backend_variables(BackendParameters * param, Port *port,
        param->UsedShmemSegAddr = UsedShmemSegAddr;
 
        param->ShmemLock = ShmemLock;
-       param->ShmemIndexLock = ShmemIndexLock;
        param->ShmemVariableCache = ShmemVariableCache;
-       param->ShmemIndexAlloc = ShmemIndexAlloc;
        param->ShmemBackendArray = ShmemBackendArray;
 
        param->LWLockArray = LWLockArray;
        param->ProcStructLock = ProcStructLock;
+       param->ProcGlobal = ProcGlobal;
+       param->DummyProcs = DummyProcs;
        write_inheritable_socket(&param->pgStatSock, pgStatSock, childPid);
        write_inheritable_socket(&param->pgStatPipe0, pgStatPipe[0], childPid);
        write_inheritable_socket(&param->pgStatPipe1, pgStatPipe[1], childPid);
@@ -3876,13 +3929,13 @@ restore_backend_variables(BackendParameters * param, Port *port)
        UsedShmemSegAddr = param->UsedShmemSegAddr;
 
        ShmemLock = param->ShmemLock;
-       ShmemIndexLock = param->ShmemIndexLock;
        ShmemVariableCache = param->ShmemVariableCache;
-       ShmemIndexAlloc = param->ShmemIndexAlloc;
        ShmemBackendArray = param->ShmemBackendArray;
 
        LWLockArray = param->LWLockArray;
        ProcStructLock = param->ProcStructLock;
+       ProcGlobal = param->ProcGlobal;
+       DummyProcs = param->DummyProcs;
        read_inheritable_socket(&pgStatSock, &param->pgStatSock);
        read_inheritable_socket(&pgStatPipe[0], &param->pgStatPipe0);
        read_inheritable_socket(&pgStatPipe[1], &param->pgStatPipe1);
index 805ea8087a3d0f958b1b76ed4da4335d397b43fa..e27f2bf8bc6ad69efe78018f42f678468ee649c5 100644 (file)
@@ -18,7 +18,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.21 2005/11/22 18:17:18 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.22 2006/01/04 21:06:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -135,9 +135,6 @@ SysLoggerMain(int argc, char *argv[])
 
        MyProcPid = getpid();           /* reset MyProcPid */
 
-       /* Lose the postmaster's on-exit routines */
-       on_exit_reset();
-
 #ifdef EXEC_BACKEND
        syslogger_parseArgs(argc, argv);
 #endif   /* EXEC_BACKEND */
@@ -460,6 +457,9 @@ SysLogger_Start(void)
                        /* Close the postmaster's sockets */
                        ClosePostmasterPorts(true);
 
+                       /* Lose the postmaster's on-exit routines */
+                       on_exit_reset();
+
                        /* Drop our connection to postmaster's shared memory, as well */
                        PGSharedMemoryDetach();
 
index bfe8d52af3028c77c18a49e3dfba2202f6069982..e878462100e9f15950749abbc2c5f2c088e60568 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.80 2005/12/09 01:22:03 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.81 2006/01/04 21:06:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 void
 CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 {
-       PGShmemHeader *seghdr = NULL;
-
        if (!IsUnderPostmaster)
        {
+               PGShmemHeader *seghdr;
                Size            size;
                int                     numSemas;
 
@@ -104,6 +103,8 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
                 */
                seghdr = PGSharedMemoryCreate(size, makePrivate, port);
 
+               InitShmemAccess(seghdr);
+
                /*
                 * Create semaphores
                 */
@@ -120,18 +121,16 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
                 */
 #ifdef EXEC_BACKEND
                Assert(!makePrivate);
-               Assert(UsedShmemSegAddr != NULL);
-               seghdr = UsedShmemSegAddr;
 #else
                elog(PANIC, "should be attached to shared memory already");
 #endif
        }
 
-
        /*
         * Set up shared memory allocation mechanism
         */
-       InitShmemAllocation(seghdr, !IsUnderPostmaster);
+       if (!IsUnderPostmaster)
+               InitShmemAllocation();
 
        /*
         * Now initialize LWLocks, which do shared memory allocation and are
@@ -163,7 +162,8 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
        /*
         * Set up process table
         */
-       InitProcGlobal();
+       if (!IsUnderPostmaster)
+               InitProcGlobal();
        CreateSharedProcArray();
 
        /*
index e6865563b398a84d002b53ec275e062f2da72e35..21d136d6cf01f5182b4b4de6baa0a03302bb6d0d 100644 (file)
@@ -8,25 +8,26 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.89 2005/12/29 18:08:05 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.90 2006/01/04 21:06:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * POSTGRES processes share one or more regions of shared memory.
  * The shared memory is created by a postmaster and is inherited
- * by each backend via fork(). The routines in this file are used for
- * allocating and binding to shared memory data structures.
+ * by each backend via fork() (or, in some ports, via other OS-specific
+ * methods).  The routines in this file are used for allocating and
+ * binding to shared memory data structures.
  *
  * NOTES:
  *             (a) There are three kinds of shared memory data structures
  *     available to POSTGRES: fixed-size structures, queues and hash
  *     tables.  Fixed-size structures contain things like global variables
- *     for a module and should never be allocated after the process
+ *     for a module and should never be allocated after the shared memory
  *     initialization phase.  Hash tables have a fixed maximum size, but
  *     their actual size can vary dynamically.  When entries are added
  *     to the table, more space is allocated.  Queues link data structures
- *     that have been allocated either as fixed size structures or as hash
+ *     that have been allocated either within fixed-size structures or as hash
  *     buckets.  Each shared data structure has a string name to identify
  *     it (assigned in the module that declares it).
  *
  *     of shared memory in a lot of different places (and changing
  *     things during development), this is important.
  *
- *             (c) memory allocation model: shared memory can never be
+ *             (c) In standard Unix-ish environments, individual backends do not
+ *     need to re-establish their local pointers into shared memory, because
+ *     they inherit correct values of those variables via fork() from the
+ *     postmaster.  However, this does not work in the EXEC_BACKEND case.
+ *     In ports using EXEC_BACKEND, new backends have to set up their local
+ *     pointers using the method described in (b) above.
+
+ *             (d) memory allocation model: shared memory can never be
  *     freed, once allocated.   Each hash table has its own free list,
  *     so hash buckets can be reused when an item is deleted.  However,
  *     if one hash table grows very large and then shrinks, its space
@@ -75,58 +83,59 @@ static SHMEM_OFFSET ShmemEnd;       /* end+1 address of shared memory */
 slock_t    *ShmemLock;                 /* spinlock for shared memory and LWLock
                                                                 * allocation */
 
-NON_EXEC_STATIC slock_t *ShmemIndexLock;               /* spinlock for ShmemIndex */
-
-NON_EXEC_STATIC void *ShmemIndexAlloc = NULL;  /* Memory actually allocated
-                                                                                                * for ShmemIndex */
-
 static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
 
 
 /*
- *     InitShmemAllocation() --- set up shared-memory allocation.
+ *     InitShmemAccess() --- set up basic pointers to shared memory.
  *
  * Note: the argument should be declared "PGShmemHeader *seghdr",
  * but we use void to avoid having to include ipc.h in shmem.h.
  */
 void
-InitShmemAllocation(void *seghdr, bool init)
+InitShmemAccess(void *seghdr)
 {
        PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr;
 
-       /* Set up basic pointers to shared memory */
        ShmemSegHdr = shmhdr;
        ShmemBase = (SHMEM_OFFSET) shmhdr;
        ShmemEnd = ShmemBase + shmhdr->totalsize;
+}
 
-       if (init)
-       {
-               /*
-                * Initialize the spinlocks used by ShmemAlloc/ShmemInitStruct. We
-                * have to do the space allocation the hard way, since ShmemAlloc
-                * can't be called yet.
-                */
-               ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
-               shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
-               Assert(shmhdr->freeoffset <= shmhdr->totalsize);
+/*
+ *     InitShmemAllocation() --- set up shared-memory space allocation.
+ *
+ * This should be called only in the postmaster or a standalone backend.
+ */
+void
+InitShmemAllocation(void)
+{
+       PGShmemHeader *shmhdr = ShmemSegHdr;
 
-               ShmemIndexLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
-               shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
-               Assert(shmhdr->freeoffset <= shmhdr->totalsize);
+       Assert(shmhdr != NULL);
 
-               SpinLockInit(ShmemLock);
-               SpinLockInit(ShmemIndexLock);
+       /*
+        * Initialize the spinlock used by ShmemAlloc.  We have to do the
+        * space allocation the hard way, since obviously ShmemAlloc can't
+        * be called yet.
+        */
+       ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
+       shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
+       Assert(shmhdr->freeoffset <= shmhdr->totalsize);
 
-               /* ShmemIndex can't be set up yet (need LWLocks first) */
-               ShmemIndex = (HTAB *) NULL;
+       SpinLockInit(ShmemLock);
 
-               /*
-                * Initialize ShmemVariableCache for transaction manager.
-                */
-               ShmemVariableCache = (VariableCache)
-                       ShmemAlloc(sizeof(*ShmemVariableCache));
-               memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
-       }
+       /* ShmemIndex can't be set up yet (need LWLocks first) */
+       shmhdr->indexoffset = 0;
+       ShmemIndex = (HTAB *) NULL;
+
+       /*
+        * Initialize ShmemVariableCache for transaction manager.
+        * (This doesn't really belong here, but not worth moving.)
+        */
+       ShmemVariableCache = (VariableCache)
+               ShmemAlloc(sizeof(*ShmemVariableCache));
+       memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
 }
 
 /*
@@ -194,7 +203,7 @@ ShmemIsValid(unsigned long addr)
 }
 
 /*
- *     InitShmemIndex() --- set up shmem index table.
+ *     InitShmemIndex() --- set up or attach to shmem index table.
  */
 void
 InitShmemIndex(void)
@@ -239,15 +248,14 @@ InitShmemIndex(void)
 
                result->location = MAKE_OFFSET(ShmemIndex->hctl);
                result->size = SHMEM_INDEX_SIZE;
-
        }
 
        /* now release the lock acquired in ShmemInitStruct */
-       SpinLockRelease(ShmemIndexLock);
+       LWLockRelease(ShmemIndexLock);
 }
 
 /*
- * ShmemInitHash -- Create/Attach to and initialize
+ * ShmemInitHash -- Create and initialize, or attach to, a
  *             shared memory hash table.
  *
  * We assume caller is doing some kind of synchronization
@@ -290,8 +298,8 @@ ShmemInitHash(const char *name, /* table string name for shmem index */
                                                           &found);
 
        /*
-        * shmem index is corrupted.    Let someone else give the error message
-        * since they have more information
+        * If fail, shmem index is corrupted.  Let caller give the error message
+        * since it has more information
         */
        if (location == NULL)
                return NULL;
@@ -315,8 +323,8 @@ ShmemInitHash(const char *name, /* table string name for shmem index */
  *             memory.
  *
  *     This is called during initialization to find or allocate
- *             a data structure in shared memory.      If no other processes
- *             have created the structure, this routine allocates space
+ *             a data structure in shared memory.      If no other process
+ *             has created the structure, this routine allocates space
  *             for it.  If it exists already, a pointer to the existing
  *             table is returned.
  *
@@ -334,15 +342,18 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
        strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
        item.location = BAD_LOCATION;
 
-       SpinLockAcquire(ShmemIndexLock);
+       LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
 
        if (!ShmemIndex)
        {
+               PGShmemHeader *shmemseghdr = ShmemSegHdr;
+
                Assert(strcmp(name, "ShmemIndex") == 0);
                if (IsUnderPostmaster)
                {
                        /* Must be initializing a (non-standalone) backend */
-                       Assert(ShmemIndexAlloc);
+                       Assert(shmemseghdr->indexoffset != 0);
+                       structPtr = (void *) MAKE_PTR(shmemseghdr->indexoffset);
                        *foundPtr = TRUE;
                }
                else
@@ -354,10 +365,12 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
                         * Notice that the ShmemIndexLock is held until the shmem index
                         * has been completely initialized.
                         */
+                       Assert(shmemseghdr->indexoffset == 0);
+                       structPtr = ShmemAlloc(size);
+                       shmemseghdr->indexoffset = MAKE_OFFSET(structPtr);
                        *foundPtr = FALSE;
-                       ShmemIndexAlloc = ShmemAlloc(size);
                }
-               return ShmemIndexAlloc;
+               return structPtr;
        }
 
        /* look it up in the shmem index */
@@ -366,7 +379,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
 
        if (!result)
        {
-               SpinLockRelease(ShmemIndexLock);
+               LWLockRelease(ShmemIndexLock);
                ereport(ERROR,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
                                 errmsg("out of shared memory")));
@@ -381,7 +394,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
                 */
                if (result->size != size)
                {
-                       SpinLockRelease(ShmemIndexLock);
+                       LWLockRelease(ShmemIndexLock);
 
                        elog(WARNING, "ShmemIndex entry size is wrong");
                        /* let caller print its message too */
@@ -398,7 +411,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
                        /* out of memory */
                        Assert(ShmemIndex);
                        hash_search(ShmemIndex, (void *) &item, HASH_REMOVE, NULL);
-                       SpinLockRelease(ShmemIndexLock);
+                       LWLockRelease(ShmemIndexLock);
 
                        ereport(WARNING,
                                        (errcode(ERRCODE_OUT_OF_MEMORY),
@@ -411,7 +424,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
        }
        Assert(ShmemIsValid((unsigned long) structPtr));
 
-       SpinLockRelease(ShmemIndexLock);
+       LWLockRelease(ShmemIndexLock);
        return structPtr;
 }
 
index 34d80bfceeacf8ea4e5007831964dab095e8440b..605f8b5e68bc6d3d4f31a3af31b20bdb94c87b5d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.170 2005/12/11 21:02:18 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.171 2006/01/04 21:06:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,8 +61,8 @@ PGPROC           *MyProc = NULL;
 NON_EXEC_STATIC slock_t *ProcStructLock = NULL;
 
 /* Pointers to shared-memory structures */
-static PROC_HDR *ProcGlobal = NULL;
-static PGPROC *DummyProcs = NULL;
+NON_EXEC_STATIC PROC_HDR *ProcGlobal = NULL;
+NON_EXEC_STATIC PGPROC *DummyProcs = NULL;
 
 /* If we are waiting for a lock, this points to the associated LOCALLOCK */
 static LOCALLOCK *lockAwaited = NULL;
@@ -76,6 +76,7 @@ volatile bool cancel_from_timeout = false;
 static struct timeval statement_fin_time;
 
 
+static void RemoveProcFromArray(int code, Datum arg);
 static void ProcKill(int code, Datum arg);
 static void DummyProcKill(int code, Datum arg);
 static bool CheckStatementTimeout(void);
@@ -113,7 +114,8 @@ ProcGlobalSemas(void)
 
 /*
  * InitProcGlobal -
- *       Initialize the global process table during postmaster startup.
+ *       Initialize the global process table during postmaster or standalone
+ *       backend startup.
  *
  *       We also create all the per-process semaphores we will need to support
  *       the requested number of backends.  We used to allocate semaphores
@@ -129,69 +131,65 @@ ProcGlobalSemas(void)
  *       Another reason for creating semaphores here is that the semaphore
  *       implementation typically requires us to create semaphores in the
  *       postmaster, not in backends.
+ *
+ * Note: this is NOT called by individual backends under a postmaster,
+ * not even in the EXEC_BACKEND case.  The ProcGlobal and DummyProcs
+ * pointers must be propagated specially for EXEC_BACKEND operation.
  */
 void
 InitProcGlobal(void)
 {
-       bool            foundProcGlobal,
-                               foundDummy;
+       PGPROC     *procs;
+       int                     i;
+       bool            found;
 
-       /* Create or attach to the ProcGlobal shared structure */
+       /* Create the ProcGlobal shared structure */
        ProcGlobal = (PROC_HDR *)
-               ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &foundProcGlobal);
+               ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
+       Assert(!found);
 
        /*
-        * Create or attach to the PGPROC structures for dummy (bgwriter)
-        * processes, too.      These do not get linked into the freeProcs list.
+        * Create the PGPROC structures for dummy (bgwriter) processes, too.
+        * These do not get linked into the freeProcs list.
         */
        DummyProcs = (PGPROC *)
                ShmemInitStruct("DummyProcs", NUM_DUMMY_PROCS * sizeof(PGPROC),
-                                               &foundDummy);
-
-       if (foundProcGlobal || foundDummy)
-       {
-               /* both should be present or neither */
-               Assert(foundProcGlobal && foundDummy);
-       }
-       else
-       {
-               /*
-                * We're the first - initialize.
-                */
-               PGPROC     *procs;
-               int                     i;
-
-               ProcGlobal->freeProcs = INVALID_OFFSET;
+                                               &found);
+       Assert(!found);
 
-               ProcGlobal->spins_per_delay = DEFAULT_SPINS_PER_DELAY;
+       /*
+        * Initialize the data structures.
+        */
+       ProcGlobal->freeProcs = INVALID_OFFSET;
 
-               /*
-                * Pre-create the PGPROC structures and create a semaphore for each.
-                */
-               procs = (PGPROC *) ShmemAlloc(MaxBackends * sizeof(PGPROC));
-               if (!procs)
-                       ereport(FATAL,
-                                       (errcode(ERRCODE_OUT_OF_MEMORY),
-                                        errmsg("out of shared memory")));
-               MemSet(procs, 0, MaxBackends * sizeof(PGPROC));
-               for (i = 0; i < MaxBackends; i++)
-               {
-                       PGSemaphoreCreate(&(procs[i].sem));
-                       procs[i].links.next = ProcGlobal->freeProcs;
-                       ProcGlobal->freeProcs = MAKE_OFFSET(&procs[i]);
-               }
+       ProcGlobal->spins_per_delay = DEFAULT_SPINS_PER_DELAY;
 
-               MemSet(DummyProcs, 0, NUM_DUMMY_PROCS * sizeof(PGPROC));
-               for (i = 0; i < NUM_DUMMY_PROCS; i++)
-               {
-                       DummyProcs[i].pid = 0;          /* marks dummy proc as not in use */
-                       PGSemaphoreCreate(&(DummyProcs[i].sem));
-               }
+       /*
+        * Pre-create the PGPROC structures and create a semaphore for each.
+        */
+       procs = (PGPROC *) ShmemAlloc(MaxBackends * sizeof(PGPROC));
+       if (!procs)
+               ereport(FATAL,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of shared memory")));
+       MemSet(procs, 0, MaxBackends * sizeof(PGPROC));
+       for (i = 0; i < MaxBackends; i++)
+       {
+               PGSemaphoreCreate(&(procs[i].sem));
+               procs[i].links.next = ProcGlobal->freeProcs;
+               ProcGlobal->freeProcs = MAKE_OFFSET(&procs[i]);
+       }
 
-               /* Create ProcStructLock spinlock, too */
-               ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
-               SpinLockInit(ProcStructLock);
+       MemSet(DummyProcs, 0, NUM_DUMMY_PROCS * sizeof(PGPROC));
+       for (i = 0; i < NUM_DUMMY_PROCS; i++)
+       {
+               DummyProcs[i].pid = 0;          /* marks dummy proc as not in use */
+               PGSemaphoreCreate(&(DummyProcs[i].sem));
        }
+
+       /* Create ProcStructLock spinlock, too */
+       ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
+       SpinLockInit(ProcStructLock);
 }
 
 /*
@@ -206,8 +204,8 @@ InitProcess(void)
        int                     i;
 
        /*
-        * ProcGlobal should be set by a previous call to InitProcGlobal (if we
-        * are a backend, we inherit this by fork() from the postmaster).
+        * ProcGlobal should be set up already (if we are a backend, we inherit
+        * this by fork() or EXEC_BACKEND mechanism from the postmaster).
         */
        if (procglobal == NULL)
                elog(PANIC, "proc header uninitialized");
@@ -256,8 +254,8 @@ InitProcess(void)
        MyProc->xid = InvalidTransactionId;
        MyProc->xmin = InvalidTransactionId;
        MyProc->pid = MyProcPid;
-       MyProc->databaseId = MyDatabaseId;
-       /* Will be set properly after the session role id is determined */
+       /* databaseId and roleId will be filled in later */
+       MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
        MyProc->lwWaiting = false;
        MyProc->lwExclusive = false;
@@ -268,21 +266,16 @@ InitProcess(void)
                SHMQueueInit(&(MyProc->myProcLocks[i]));
 
        /*
-        * Add our PGPROC to the PGPROC array in shared memory.
+        * We might be reusing a semaphore that belonged to a failed process. So
+        * be careful and reinitialize its value here.
         */
-       ProcArrayAdd(MyProc);
+       PGSemaphoreReset(&MyProc->sem);
 
        /*
         * Arrange to clean up at backend exit.
         */
        on_shmem_exit(ProcKill, 0);
 
-       /*
-        * We might be reusing a semaphore that belonged to a failed process. So
-        * be careful and reinitialize its value here.
-        */
-       PGSemaphoreReset(&MyProc->sem);
-
        /*
         * Now that we have a PGPROC, we could try to acquire locks, so initialize
         * the deadlock checker.
@@ -290,26 +283,59 @@ InitProcess(void)
        InitDeadLockChecking();
 }
 
+/*
+ * InitProcessPhase2 -- make MyProc visible in the shared ProcArray.
+ *
+ * This is separate from InitProcess because we can't acquire LWLocks until
+ * we've created a PGPROC, but in the EXEC_BACKEND case there is a good deal
+ * of stuff to be done before this step that will require LWLock access.
+ */
+void
+InitProcessPhase2(void)
+{
+       Assert(MyProc != NULL);
+
+       /*
+        * We should now know what database we're in, so advertise that.  (We
+        * need not do any locking here, since no other backend can yet see
+        * our PGPROC.)
+        */
+       Assert(OidIsValid(MyDatabaseId));
+       MyProc->databaseId = MyDatabaseId;
+
+       /*
+        * Add our PGPROC to the PGPROC array in shared memory.
+        */
+       ProcArrayAdd(MyProc);
+
+       /*
+        * Arrange to clean that up at backend exit.
+        */
+       on_shmem_exit(RemoveProcFromArray, 0);
+}
+
 /*
  * InitDummyProcess -- create a dummy per-process data structure
  *
  * This is called by bgwriter and similar processes so that they will have a
  * MyProc value that's real enough to let them wait for LWLocks.  The PGPROC
- * and sema that are assigned are the extra ones created during
+ * and sema that are assigned are one of the extra ones created during
  * InitProcGlobal.
  *
  * Dummy processes are presently not expected to wait for real (lockmgr)
- * locks, nor to participate in sinval messaging.
+ * locks, so we need not set up the deadlock checker.  They are never added
+ * to the ProcArray or the sinval messaging mechanism, either.
  */
 void
-InitDummyProcess(int proctype)
+InitDummyProcess(void)
 {
        PGPROC     *dummyproc;
+       int                     proctype;
        int                     i;
 
        /*
-        * ProcGlobal should be set by a previous call to InitProcGlobal (we
-        * inherit this by fork() from the postmaster).
+        * ProcGlobal should be set up already (if we are a backend, we inherit
+        * this by fork() or EXEC_BACKEND mechanism from the postmaster).
         */
        if (ProcGlobal == NULL || DummyProcs == NULL)
                elog(PANIC, "proc header uninitialized");
@@ -317,11 +343,9 @@ InitDummyProcess(int proctype)
        if (MyProc != NULL)
                elog(ERROR, "you already exist");
 
-       Assert(proctype >= 0 && proctype < NUM_DUMMY_PROCS);
-
        /*
-        * Just for paranoia's sake, we use the ProcStructLock to protect
-        * assignment and releasing of DummyProcs entries.
+        * We use the ProcStructLock to protect assignment and releasing of
+        * DummyProcs entries.
         *
         * While we are holding the ProcStructLock, also copy the current shared
         * estimate of spins_per_delay to local storage.
@@ -330,32 +354,38 @@ InitDummyProcess(int proctype)
 
        set_spins_per_delay(ProcGlobal->spins_per_delay);
 
-       dummyproc = &DummyProcs[proctype];
-
        /*
-        * dummyproc should not presently be in use by anyone else
+        * Find a free dummyproc ... *big* trouble if there isn't one ...
         */
-       if (dummyproc->pid != 0)
+       for (proctype = 0; proctype < NUM_DUMMY_PROCS; proctype++)
+       {
+               dummyproc = &DummyProcs[proctype];
+               if (dummyproc->pid == 0)
+                       break;
+       }
+       if (proctype >= NUM_DUMMY_PROCS)
        {
                SpinLockRelease(ProcStructLock);
-               elog(FATAL, "DummyProc[%d] is in use by PID %d",
-                        proctype, dummyproc->pid);
+               elog(FATAL, "all DummyProcs are in use");
        }
-       MyProc = dummyproc;
 
-       MyProc->pid = MyProcPid;        /* marks dummy proc as in use by me */
+       /* Mark dummy proc as in use by me */
+       /* use volatile pointer to prevent code rearrangement */
+       ((volatile PGPROC *) dummyproc)->pid = MyProcPid;
+
+       MyProc = dummyproc;
 
        SpinLockRelease(ProcStructLock);
 
        /*
-        * Initialize all fields of MyProc, except MyProc->sem which was set up by
-        * InitProcGlobal.
+        * Initialize all fields of MyProc, except for the semaphore which was
+        * prepared for us by InitProcGlobal.
         */
        SHMQueueElemInit(&(MyProc->links));
        MyProc->waitStatus = STATUS_OK;
        MyProc->xid = InvalidTransactionId;
        MyProc->xmin = InvalidTransactionId;
-       MyProc->databaseId = MyDatabaseId;
+       MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
        MyProc->lwWaiting = false;
        MyProc->lwExclusive = false;
@@ -365,16 +395,16 @@ InitDummyProcess(int proctype)
        for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
                SHMQueueInit(&(MyProc->myProcLocks[i]));
 
-       /*
-        * Arrange to clean up at process exit.
-        */
-       on_shmem_exit(DummyProcKill, Int32GetDatum(proctype));
-
        /*
         * We might be reusing a semaphore that belonged to a failed process. So
         * be careful and reinitialize its value here.
         */
        PGSemaphoreReset(&MyProc->sem);
+
+       /*
+        * Arrange to clean up at process exit.
+        */
+       on_shmem_exit(DummyProcKill, Int32GetDatum(proctype));
 }
 
 /*
@@ -501,6 +531,16 @@ ProcReleaseLocks(bool isCommit)
 }
 
 
+/*
+ * RemoveProcFromArray() -- Remove this process from the shared ProcArray.
+ */
+static void
+RemoveProcFromArray(int code, Datum arg)
+{
+       Assert(MyProc != NULL);
+       ProcArrayRemove(MyProc);
+}
+
 /*
  * ProcKill() -- Destroy the per-proc data structure for
  *             this process. Release any of its held LW locks.
@@ -520,9 +560,6 @@ ProcKill(int code, Datum arg)
         */
        LWLockReleaseAll();
 
-       /* Remove our PGPROC from the PGPROC array in shared memory */
-       ProcArrayRemove(MyProc);
-
        SpinLockAcquire(ProcStructLock);
 
        /* Return PGPROC structure (and semaphore) to freelist */
index 64fda9783163aacfb6a322ed3fa951dacd3541d3..8991258523b5e13f9190d3c8629080a447b64daf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.474 2005/12/31 16:50:44 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.475 2006/01/04 21:06:31 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -2860,7 +2860,6 @@ PostgresMain(int argc, char *argv[], const char *username)
 
        PG_SETMASK(&BlockSig);          /* block everything except SIGQUIT */
 
-
        if (IsUnderPostmaster)
        {
                /* noninteractive case: nothing should be left after switches */
@@ -2933,6 +2932,19 @@ PostgresMain(int argc, char *argv[], const char *username)
                BuildFlatFiles(true);
        }
 
+       /*
+        * Create a per-backend PGPROC struct in shared memory, except in
+        * the EXEC_BACKEND case where this was done in SubPostmasterMain.
+        * We must do this before we can use LWLocks (and in the EXEC_BACKEND
+        * case we already had to do some stuff with LWLocks).
+        */
+#ifdef EXEC_BACKEND
+       if (!IsUnderPostmaster)
+               InitProcess();
+#else
+       InitProcess();
+#endif
+
        /*
         * General initialization.
         *
index b9b1f56dd08456aa5e53c899205c03e14c0ca316..580a2b4068b76628f2a725d994e3123641988c15 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.159 2005/11/22 18:17:26 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.160 2006/01/04 21:06:32 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -311,6 +311,9 @@ BaseInit(void)
  * can only be tested inside a transaction, so we want to do it during
  * the startup transaction rather than doing a separate one in postgres.c.)
  *
+ * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we
+ * already have a PGPROC struct ... but it's not filled in yet.
+ *
  * Note:
  *             Be very careful with the order of calls in the InitPostgres function.
  * --------------------------------
@@ -383,17 +386,17 @@ InitPostgres(const char *dbname, const char *username)
         */
 
        /*
-        * Set up my per-backend PGPROC struct in shared memory.        (We need to
-        * know MyDatabaseId before we can do this, since it's entered into the
-        * PGPROC struct.)
+        * Finish filling in the PGPROC struct, and add it to the ProcArray.
+        * (We need to know MyDatabaseId before we can do this, since it's entered
+        * into the PGPROC struct.)
+        *
+        * Once I have done this, I am visible to other backends!
         */
-       InitProcess();
+       InitProcessPhase2();
 
        /*
         * Initialize my entry in the shared-invalidation manager's array of
-        * per-backend data.  (Formerly this came before InitProcess, but now it
-        * must happen after, because it uses MyProc.)  Once I have done this, I
-        * am visible to other backends!
+        * per-backend data.
         *
         * Sets up MyBackendId, a unique backend identifier.
         */
index c318e60b5771fbeb35845dad0d0eea98226278f4..ca384218a50cb5f8716f3c302ee3fabaab55f4a0 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.24 2005/12/11 21:02:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.25 2006/01/04 21:06:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@ typedef enum LWLockId
 {
        BufMappingLock,
        BufFreelistLock,
+       ShmemIndexLock,
        OidGenLock,
        XidGenLock,
        ProcArrayLock,
index 4dd91e8540f7260d8fb639b0a13445b3c99ea3ab..59784117614a2dd5c61c68337349a4c0e8156478 100644 (file)
@@ -17,7 +17,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/pg_shmem.h,v 1.16 2005/10/15 02:49:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/pg_shmem.h,v 1.17 2006/01/04 21:06:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 typedef struct PGShmemHeader   /* standard header for all Postgres shmem */
 {
        int32           magic;                  /* magic # to identify Postgres segments */
-#define PGShmemMagic  679834893
+#define PGShmemMagic  679834894
        pid_t           creatorPID;             /* PID of creating process */
        Size            totalsize;              /* total size of segment */
        Size            freeoffset;             /* offset to first free space */
+       Size            indexoffset;    /* offset to ShmemIndex table */
 #ifndef WIN32                                  /* Windows doesn't have useful inode#s */
        dev_t           device;                 /* device data directory is on */
        ino_t           inode;                  /* inode number of data directory */
index 2cfee41eff91e85f6767aa8098402e36ea69148a..abf99668f349475d380d15a54ec421cacfbf4ca4 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.85 2005/12/11 21:02:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.86 2006/01/04 21:06:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -114,9 +114,10 @@ typedef struct PROC_HDR
        int                     spins_per_delay;
 } PROC_HDR;
 
-
-#define DUMMY_PROC_DEFAULT     0
-#define DUMMY_PROC_BGWRITER 1
+/*
+ * We set aside some extra PGPROC structures for "dummy" processes,
+ * ie things that aren't full-fledged backends but need shmem access.
+ */
 #define NUM_DUMMY_PROCS                2
 
 
@@ -134,7 +135,8 @@ extern int  ProcGlobalSemas(void);
 extern Size ProcGlobalShmemSize(void);
 extern void InitProcGlobal(void);
 extern void InitProcess(void);
-extern void InitDummyProcess(int proctype);
+extern void InitProcessPhase2(void);
+extern void InitDummyProcess(void);
 extern bool HaveNFreeProcs(int n);
 extern void ProcReleaseLocks(bool isCommit);
 
index 520f8eb3adff930c30de33a0c680f47e7ed38adf..141ecf17d9006f523d065f02342fc889a91cff47 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/shmem.h,v 1.45 2005/08/20 23:26:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/shmem.h,v 1.46 2006/01/04 21:06:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,7 +61,8 @@ typedef struct SHM_QUEUE
 } SHM_QUEUE;
 
 /* shmem.c */
-extern void InitShmemAllocation(void *seghdr, bool init);
+extern void InitShmemAccess(void *seghdr);
+extern void InitShmemAllocation(void);
 extern void *ShmemAlloc(Size size);
 extern bool ShmemIsValid(unsigned long addr);
 extern void InitShmemIndex(void);