Rearrange backend startup sequence so that ShmemIndexLock can become
authorTom Lane
Wed, 4 Jan 2006 21:06:32 +0000 (21:06 +0000)
committerTom Lane
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(¶m->pgStatSock, pgStatSock, childPid);
    write_inheritable_socket(¶m->pgStatPipe0, pgStatPipe[0], childPid);
    write_inheritable_socket(¶m->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, ¶m->pgStatSock);
    read_inheritable_socket(&pgStatPipe[0], ¶m->pgStatPipe0);
    read_inheritable_socket(&pgStatPipe[1], ¶m->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);