Significant cleanups in SysV IPC handling (shared mem and semaphores).
authorTom Lane
Tue, 28 Nov 2000 23:27:57 +0000 (23:27 +0000)
committerTom Lane
Tue, 28 Nov 2000 23:27:57 +0000 (23:27 +0000)
IPC key assignment will now work correctly even when multiple postmasters
are using same logical port number (which is possible given -k switch).
There is only one shared-mem segment per postmaster now, not 3.
Rip out broken code for non-TAS case in bufmgr and xlog, substitute a
complete S_LOCK emulation using semaphores in spin.c.  TAS and non-TAS
logic is now exactly the same.
When deadlock is detected, "Deadlock detected" is now the elog(ERROR)
message, rather than a NOTICE that comes out before an unhelpful ERROR.

27 files changed:
doc/src/sgml/ref/postmaster.sgml
src/backend/access/transam/xlog.c
src/backend/commands/async.c
src/backend/postmaster/postmaster.c
src/backend/storage/buffer/buf_init.c
src/backend/storage/buffer/bufmgr.c
src/backend/storage/buffer/s_lock.c
src/backend/storage/buffer/xlog_bufmgr.c
src/backend/storage/ipc/ipc.c
src/backend/storage/ipc/ipci.c
src/backend/storage/ipc/shmem.c
src/backend/storage/ipc/sinval.c
src/backend/storage/ipc/sinvaladt.c
src/backend/storage/ipc/spin.c
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/proc.c
src/backend/utils/init/postinit.c
src/include/storage/buf_internals.h
src/include/storage/bufmgr.h
src/include/storage/ipc.h
src/include/storage/lmgr.h
src/include/storage/proc.h
src/include/storage/s_lock.h
src/include/storage/shmem.h
src/include/storage/sinval.h
src/include/storage/sinvaladt.h
src/include/storage/spin.h

index beb6c0ee93f661301e00cc4a85c36e5ec8148298..5bf5e4cb92b205ce12839b9f6b70c7124843427d 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -400,32 +400,6 @@ $ ps -e | grep postmast
        
       
      
-
-     
-      
-IpcMemoryAttach: shmat() failed: Permission denied
-       
-      
-       
-   A likely explanation is that another user attempted to start a
-   postmaster
-   process on the same port which acquired shared resources and then 
-   died.  Since Postgres shared memory keys are based on the port number 
-   assigned to the
-   postmaster,
-   such conflicts are likely if there is more than one installation on 
-   a single host.  If there are no other
-   postmaster
-   processes currently running (see above), run
-   ipcclean
-   and try again.  If other postmaster
-   images
-   are running, you will have to find the owners of those processes to
-   coordinate the assignment of port numbers and/or removal of unused
-   shared memory segments.
-       
-      
-     
     
    
   
index b31a6182ee2f0c2cf0e89dfc0ac8ee5829fc3d10..c70dbc7b4fbe8edef792a7ab01f1a542c52a10bf 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.35 2000/11/27 05:36:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.36 2000/11/28 23:27:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -85,12 +85,6 @@ typedef struct XLogCtlWrite
 } XLogCtlWrite;
 
 
-#ifndef HAS_TEST_AND_SET
-#define TAS(lck)       0
-#define S_UNLOCK(lck)
-#define S_INIT_LOCK(lck)
-#endif
-
 typedef struct XLogCtlData
 {
    XLogCtlInsert   Insert;
@@ -102,12 +96,10 @@ typedef struct XLogCtlData
    uint32          XLogCacheByte;
    uint32          XLogCacheBlck;
    StartUpID       ThisStartUpID;
-#ifdef HAS_TEST_AND_SET
    slock_t         insert_lck;
    slock_t         info_lck;
    slock_t         lgwr_lck;
    slock_t         chkp_lck;       /* checkpoint lock */
-#endif
 } XLogCtlData;
 
 static XLogCtlData *XLogCtl = NULL;
index e364d53b9df0e14a9893a046e10864b8a41811b8..6316262d042ff9e654763d07caf648a8bc2840fe 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.72 2000/11/21 21:15:59 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.73 2000/11/28 23:27:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,8 +119,8 @@ static Dllist *pendingNotifies = NULL;
 static volatile int notifyInterruptEnabled = 0;
 static volatile int notifyInterruptOccurred = 0;
 
-/* True if we've registered an on_shmem_exit cleanup (or at least tried to). */
-static int unlistenExitRegistered = 0;
+/* True if we've registered an on_shmem_exit cleanup */
+static bool unlistenExitRegistered = false;
 
 
 static void Async_UnlistenAll(void);
@@ -253,9 +253,8 @@ Async_Listen(char *relname, int pid)
     */
    if (!unlistenExitRegistered)
    {
-       if (on_shmem_exit(Async_UnlistenOnExit, 0) < 0)
-           elog(NOTICE, "Async_Listen: out of shmem_exit slots");
-       unlistenExitRegistered = 1;
+       on_shmem_exit(Async_UnlistenOnExit, 0);
+       unlistenExitRegistered = true;
    }
 }
 
index 3b2eb95d4fc2bd881d6d6533cad1474213cae96d..9fa4ebb368901cf848727c4c3b74616e3f60a482 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.193 2000/11/27 04:03:20 inoue Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.194 2000/11/28 23:27:55 tgl Exp $
  *
  * NOTES
  *
@@ -117,26 +117,6 @@ int PostPortNumber;
 char * UnixSocketDir;
 char * Virtual_host;
 
-/*
- * This is a sequence number that indicates how many times we've had to
- * throw away the shared memory and start over because we doubted its
- * integrity.  It starts off at zero and is incremented every time we
- * start over.  We use this to ensure that we use a new IPC shared memory
- * key for the new shared memory segment in case the old segment isn't
- * entirely gone yet.
- *
- * The sequence actually cycles back to 0 after 9, so pathologically there
- * could be an IPC failure if 10 sets of backends are all stuck and won't
- * release IPC resources.
- */
-static short shmem_seq = 0;
-
-/*
- * This is the base IPC shared memory key.  Other keys are generated by
- * adding to this.
- */
-static IpcMemoryKey ipc_key;
-
 /*
  * MaxBackends is the actual limit on the number of backends we will
  * start. The default is established by configure, but it can be
@@ -1292,39 +1272,6 @@ ConnFree(Port *conn)
    free(conn);
 }
 
-/*
- * get_host_port -- return a pseudo port number (16 bits)
- * derived from the primary IP address of Virtual_host.
- */
-static unsigned short
-get_host_port(void)
-{
-   static unsigned short hostPort = 0;
-
-   if (hostPort == 0)
-   {
-       SockAddr    saddr;
-       struct hostent *hp;
-
-       hp = gethostbyname(Virtual_host);
-       if ((hp == NULL) || (hp->h_addrtype != AF_INET))
-       {
-           char msg[1024];
-           snprintf(msg, sizeof(msg),
-                "FATAL: get_host_port: gethostbyname(%s) failed\n",
-                Virtual_host);
-           fputs(msg, stderr);
-           pqdebug("%s", msg);
-           exit(1);
-       }
-       memmove((char *) &(saddr.in.sin_addr),
-           (char *) hp->h_addr,
-           hp->h_length);
-       hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
-   }
-
-   return hostPort;
-}
 
 /*
  * reset_shared -- reset shared memory and semaphores
@@ -1333,40 +1280,16 @@ static void
 reset_shared(unsigned short port)
 {
    /*
-    * A typical ipc_key is 5432001, which is port 5432, sequence
-    * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
-    * The 32-bit INT_MAX is 2147483 6 47.
-    *
-    * The default algorithm for calculating the IPC keys assumes that all
-    * instances of postmaster on a given host are listening on different
-    * ports.  In order to work (prevent shared memory collisions) if you
-    * run multiple PostgreSQL instances on the same port and different IP
-    * addresses on a host, we change the algorithm if you give postmaster
-    * the -h option, or set PGHOST, to a value other than the internal
-    * default.
-    *
-    * If Virtual_host is set, then we generate the IPC keys using the
-    * last two octets of the IP address instead of the port number.
-    * This algorithm assumes that no one will run multiple PostgreSQL
-    * instances on one host using two IP addresses that have the same two
-    * last octets in different class C networks.  If anyone does, it
-    * would be rare.
-    *
-    * So, if you use -h or PGHOST, don't try to run two instances of
-    * PostgreSQL on the same IP address but different ports.  If you
-    * don't use them, then you must use different ports (via -p or
-    * PGPORT).  And, of course, don't try to use both approaches on one
-    * host.
+    * Reset assignment of shared mem and semaphore IPC keys.
+    * Doing this means that in normal cases we'll assign the same keys
+    * on each "cycle of life", and thereby avoid leaving dead IPC objects
+    * floating around if the postmaster crashes and is restarted.
     */
-
-   if (Virtual_host[0] != '\0')
-       port = get_host_port();
-
-   ipc_key = port * 1000 + shmem_seq * 100;
-   CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
-   shmem_seq += 1;
-   if (shmem_seq >= 10)
-       shmem_seq -= 10;
+   IpcInitKeyAssignment(port);
+   /*
+    * Create or re-create shared memory and semaphores.
+    */
+   CreateSharedMemoryAndSemaphores(false, MaxBackends);
 }
 
 
index 3c40009422da9bed0d11b6a2125c430b2917ead7..0fda21972f60947c8290c084c2bcd8c21bb16c27 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.37 2000/10/23 04:10:06 vadim Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.38 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,13 +56,6 @@ int          Num_Descriptors;
 BufferDesc *BufferDescriptors;
 BufferBlock BufferBlocks;
 
-#ifndef HAS_TEST_AND_SET
-long      *NWaitIOBackendP;
-
-#endif
-
-extern IpcSemaphoreId WaitIOSemId;
-
 long      *PrivateRefCount;    /* also used in freelist.c */
 bits8     *BufferLocks;        /* flag bits showing locks I have set */
 BufferTag  *BufferTagLastDirtied;      /* tag buffer had when last
@@ -139,7 +132,7 @@ long int    LocalBufferFlushCount;
  * amount of available memory.
  */
 void
-InitBufferPool(IPCKey key)
+InitBufferPool(void)
 {
    bool        foundBufs,
                foundDescs;
@@ -170,18 +163,6 @@ InitBufferPool(IPCKey key)
        ShmemInitStruct("Buffer Blocks",
                        NBuffers * BLCKSZ, &foundBufs);
 
-#ifndef HAS_TEST_AND_SET
-   {
-       bool        foundNWaitIO;
-
-       NWaitIOBackendP = (long *) ShmemInitStruct("#Backends Waiting IO",
-                                                  sizeof(long),
-                                                  &foundNWaitIO);
-       if (!foundNWaitIO)
-           *NWaitIOBackendP = 0;
-   }
-#endif
-
    if (foundDescs || foundBufs)
    {
 
@@ -214,10 +195,8 @@ InitBufferPool(IPCKey key)
            buf->flags = (BM_DELETED | BM_FREE | BM_VALID);
            buf->refcount = 0;
            buf->buf_id = i;
-#ifdef HAS_TEST_AND_SET
            S_INIT_LOCK(&(buf->io_in_progress_lock));
            S_INIT_LOCK(&(buf->cntx_lock));
-#endif
        }
 
        /* close the circular queue */
@@ -231,22 +210,6 @@ InitBufferPool(IPCKey key)
 
    SpinRelease(BufMgrLock);
 
-#ifndef HAS_TEST_AND_SET
-   {
-       extern IpcSemaphoreId WaitIOSemId;
-       extern IpcSemaphoreId WaitCLSemId;
-
-       WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
-                                        1, IPCProtection, 0, 1);
-       if (WaitIOSemId < 0)
-           elog(FATAL, "InitBufferPool: IpcSemaphoreCreate(WaitIOSemId) failed");
-       WaitCLSemId = IpcSemaphoreCreate(IPCKeyGetWaitCLSemaphoreKey(key),
-                                        1, IPCProtection,
-                                      IpcSemaphoreDefaultStartValue, 1);
-       if (WaitCLSemId < 0)
-           elog(FATAL, "InitBufferPool: IpcSemaphoreCreate(WaitCLSemId) failed");
-   }
-#endif
    PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
    BufferLocks = (bits8 *) calloc(NBuffers, sizeof(bits8));
    BufferTagLastDirtied = (BufferTag *) calloc(NBuffers, sizeof(BufferTag));
@@ -262,7 +225,7 @@ InitBufferPool(IPCKey key)
  * ----------------------------------------------------
  */
 int
-BufferShmemSize()
+BufferShmemSize(void)
 {
    int         size = 0;
 
index 907e819474378f478981458e94b01a78d4f313b8..8ed03138fac13be36884ebf5653fa78c9da046d8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.94 2000/11/20 16:47:31 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.95 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -93,12 +93,6 @@ extern void AbortBufferIO(void);
 */
 #define BUFFER_IS_BROKEN(buf) ((buf->flags & BM_IO_ERROR) && !(buf->flags & BM_DIRTY))
 
-#ifndef HAS_TEST_AND_SET
-static void SignalIO(BufferDesc *buf);
-extern long *NWaitIOBackendP;  /* defined in buf_init.c */
-
-#endif  /* HAS_TEST_AND_SET */
-
 static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
                         bool bufferLockHeld);
 static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
@@ -1187,27 +1181,7 @@ BufferSync()
  *
  * Should be entered with buffer manager spinlock held; releases it before
  * waiting and re-acquires it afterwards.
- *
- * OLD NOTES:
- *     Because IO_IN_PROGRESS conflicts are
- *     expected to be rare, there is only one BufferIO
- *     lock in the entire system.  All processes block
- *     on this semaphore when they try to use a buffer
- *     that someone else is faulting in.  Whenever a
- *     process finishes an IO and someone is waiting for
- *     the buffer, BufferIO is signaled (SignalIO).  All
- *     waiting processes then wake up and check to see
- *     if their buffer is now ready.  This implementation
- *     is simple, but efficient enough if WaitIO is
- *     rarely called by multiple processes simultaneously.
- *
- * NEW NOTES:
- *     The above is true only on machines without test-and-set
- *     semaphores (which we hope are few, these days).  On better
- *     hardware, each buffer has a spinlock that we can wait on.
  */
-#ifdef HAS_TEST_AND_SET
-
 static void
 WaitIO(BufferDesc *buf, SPINLOCK spinlock)
 {
@@ -1224,43 +1198,6 @@ WaitIO(BufferDesc *buf, SPINLOCK spinlock)
    }
 }
 
-#else                          /* !HAS_TEST_AND_SET */
-
-IpcSemaphoreId WaitIOSemId;
-IpcSemaphoreId WaitCLSemId;
-
-static void
-WaitIO(BufferDesc *buf, SPINLOCK spinlock)
-{
-   bool        inProgress;
-
-   for (;;)
-   {
-
-       /* wait until someone releases IO lock */
-       (*NWaitIOBackendP)++;
-       SpinRelease(spinlock);
-       IpcSemaphoreLock(WaitIOSemId, 0, 1);
-       SpinAcquire(spinlock);
-       inProgress = (buf->flags & BM_IO_IN_PROGRESS);
-       if (!inProgress)
-           break;
-   }
-}
-
-/*
- * SignalIO
- */
-static void
-SignalIO(BufferDesc *buf)
-{
-   /* somebody better be waiting. */
-   Assert(buf->refcount > 1);
-   IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);
-   *NWaitIOBackendP = 0;
-}
-
-#endif  /* HAS_TEST_AND_SET */
 
 long       NDirectFileRead;    /* some I/O's are direct file access.
                                 * bypass bufmgr */
@@ -2297,11 +2234,7 @@ UnlockBuffers()
        Assert(BufferIsValid(i + 1));
        buf = &(BufferDescriptors[i]);
 
-#ifdef HAS_TEST_AND_SET
        S_LOCK(&(buf->cntx_lock));
-#else
-       IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
        if (BufferLocks[i] & BL_R_LOCK)
        {
@@ -2324,11 +2257,9 @@ UnlockBuffers()
            Assert(buf->w_lock);
            buf->w_lock = false;
        }
-#ifdef HAS_TEST_AND_SET
+
        S_UNLOCK(&(buf->cntx_lock));
-#else
-       IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
+
        BufferLocks[i] = 0;
    }
 }
@@ -2346,11 +2277,7 @@ LockBuffer(Buffer buffer, int mode)
    buf = &(BufferDescriptors[buffer - 1]);
    buflock = &(BufferLocks[buffer - 1]);
 
-#ifdef HAS_TEST_AND_SET
    S_LOCK(&(buf->cntx_lock));
-#else
-   IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
    if (mode == BUFFER_LOCK_UNLOCK)
    {
@@ -2380,15 +2307,9 @@ LockBuffer(Buffer buffer, int mode)
        Assert(!(*buflock & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK)));
        while (buf->ri_lock || buf->w_lock)
        {
-#ifdef HAS_TEST_AND_SET
            S_UNLOCK(&(buf->cntx_lock));
            s_lock_sleep(i++);
            S_LOCK(&(buf->cntx_lock));
-#else
-           IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-           s_lock_sleep(i++);
-           IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
        }
        (buf->r_locks)++;
        *buflock |= BL_R_LOCK;
@@ -2412,15 +2333,9 @@ LockBuffer(Buffer buffer, int mode)
                *buflock |= BL_RI_LOCK;
                buf->ri_lock = true;
            }
-#ifdef HAS_TEST_AND_SET
            S_UNLOCK(&(buf->cntx_lock));
            s_lock_sleep(i++);
            S_LOCK(&(buf->cntx_lock));
-#else
-           IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-           s_lock_sleep(i++);
-           IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
        }
        buf->w_lock = true;
        *buflock |= BL_W_LOCK;
@@ -2438,12 +2353,7 @@ LockBuffer(Buffer buffer, int mode)
    else
        elog(ERROR, "LockBuffer: unknown lock mode %d", mode);
 
-#ifdef HAS_TEST_AND_SET
    S_UNLOCK(&(buf->cntx_lock));
-#else
-   IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
-
 }
 
 /*
@@ -2471,7 +2381,6 @@ StartBufferIO(BufferDesc *buf, bool forInput)
    Assert(!InProgressBuf);
    Assert(!(buf->flags & BM_IO_IN_PROGRESS));
    buf->flags |= BM_IO_IN_PROGRESS;
-#ifdef HAS_TEST_AND_SET
 
    /*
     * There used to be
@@ -2485,7 +2394,7 @@ StartBufferIO(BufferDesc *buf, bool forInput)
     * happen -- tgl
     */
    S_LOCK(&(buf->io_in_progress_lock));
-#endif  /* HAS_TEST_AND_SET */
+
    InProgressBuf = buf;
    IsForInput = forInput;
 }
@@ -2502,12 +2411,7 @@ static void
 TerminateBufferIO(BufferDesc *buf)
 {
    Assert(buf == InProgressBuf);
-#ifdef HAS_TEST_AND_SET
    S_UNLOCK(&(buf->io_in_progress_lock));
-#else
-   if (buf->refcount > 1)
-       SignalIO(buf);
-#endif  /* HAS_TEST_AND_SET */
    InProgressBuf = (BufferDesc *) 0;
 }
 
index 883c150b92384ed83b2e9cbe1f009abba5aadba0..72b167977d52a387775f4bfa4d0759eaa6a2ba6b 100644 (file)
@@ -1,22 +1,22 @@
 /*-------------------------------------------------------------------------
  *
  * s_lock.c
- *   buffer manager interface routines
+ *   Spinlock support routines
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.25 2000/11/16 05:51:01 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.26 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
+#include "postgres.h"
 
 #include 
 #include 
 
-#include "postgres.h"
 #include "storage/s_lock.h"
 
 
index ff6bff29a1d82ead0266a4760dcc8e92f4f96bb5..9672510547a8a5917e3ea140e5eae6af74a8a327 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/xlog_bufmgr.c,v 1.4 2000/11/22 02:19:14 inoue Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/xlog_bufmgr.c,v 1.5 2000/11/28 23:27:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,12 +88,6 @@ extern void AbortBufferIO(void);
 */
 #define BUFFER_IS_BROKEN(buf) ((buf->flags & BM_IO_ERROR) && !(buf->flags & BM_DIRTY))
 
-#ifndef HAS_TEST_AND_SET
-static void SignalIO(BufferDesc *buf);
-extern long *NWaitIOBackendP;  /* defined in buf_init.c */
-
-#endif  /* HAS_TEST_AND_SET */
-
 static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
                         bool bufferLockHeld);
 static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
@@ -853,27 +847,7 @@ BufferSync()
  *
  * Should be entered with buffer manager spinlock held; releases it before
  * waiting and re-acquires it afterwards.
- *
- * OLD NOTES:
- *     Because IO_IN_PROGRESS conflicts are
- *     expected to be rare, there is only one BufferIO
- *     lock in the entire system.  All processes block
- *     on this semaphore when they try to use a buffer
- *     that someone else is faulting in.  Whenever a
- *     process finishes an IO and someone is waiting for
- *     the buffer, BufferIO is signaled (SignalIO).  All
- *     waiting processes then wake up and check to see
- *     if their buffer is now ready.  This implementation
- *     is simple, but efficient enough if WaitIO is
- *     rarely called by multiple processes simultaneously.
- *
- * NEW NOTES:
- *     The above is true only on machines without test-and-set
- *     semaphores (which we hope are few, these days).  On better
- *     hardware, each buffer has a spinlock that we can wait on.
  */
-#ifdef HAS_TEST_AND_SET
-
 static void
 WaitIO(BufferDesc *buf, SPINLOCK spinlock)
 {
@@ -890,43 +864,6 @@ WaitIO(BufferDesc *buf, SPINLOCK spinlock)
    }
 }
 
-#else                          /* !HAS_TEST_AND_SET */
-
-IpcSemaphoreId WaitIOSemId;
-IpcSemaphoreId WaitCLSemId;
-
-static void
-WaitIO(BufferDesc *buf, SPINLOCK spinlock)
-{
-   bool        inProgress;
-
-   for (;;)
-   {
-
-       /* wait until someone releases IO lock */
-       (*NWaitIOBackendP)++;
-       SpinRelease(spinlock);
-       IpcSemaphoreLock(WaitIOSemId, 0, 1);
-       SpinAcquire(spinlock);
-       inProgress = (buf->flags & BM_IO_IN_PROGRESS);
-       if (!inProgress)
-           break;
-   }
-}
-
-/*
- * SignalIO
- */
-static void
-SignalIO(BufferDesc *buf)
-{
-   /* somebody better be waiting. */
-   Assert(buf->refcount > 1);
-   IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);
-   *NWaitIOBackendP = 0;
-}
-
-#endif  /* HAS_TEST_AND_SET */
 
 long       NDirectFileRead;    /* some I/O's are direct file access.
                                 * bypass bufmgr */
@@ -1965,11 +1902,7 @@ UnlockBuffers()
        Assert(BufferIsValid(i + 1));
        buf = &(BufferDescriptors[i]);
 
-#ifdef HAS_TEST_AND_SET
        S_LOCK(&(buf->cntx_lock));
-#else
-       IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
        if (BufferLocks[i] & BL_R_LOCK)
        {
@@ -1992,11 +1925,9 @@ UnlockBuffers()
            Assert(buf->w_lock);
            buf->w_lock = false;
        }
-#ifdef HAS_TEST_AND_SET
+
        S_UNLOCK(&(buf->cntx_lock));
-#else
-       IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
+
        BufferLocks[i] = 0;
    }
 }
@@ -2014,11 +1945,7 @@ LockBuffer(Buffer buffer, int mode)
    buf = &(BufferDescriptors[buffer - 1]);
    buflock = &(BufferLocks[buffer - 1]);
 
-#ifdef HAS_TEST_AND_SET
    S_LOCK(&(buf->cntx_lock));
-#else
-   IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
 
    if (mode == BUFFER_LOCK_UNLOCK)
    {
@@ -2048,15 +1975,9 @@ LockBuffer(Buffer buffer, int mode)
        Assert(!(*buflock & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK)));
        while (buf->ri_lock || buf->w_lock)
        {
-#ifdef HAS_TEST_AND_SET
            S_UNLOCK(&(buf->cntx_lock));
            s_lock_sleep(i++);
            S_LOCK(&(buf->cntx_lock));
-#else
-           IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-           s_lock_sleep(i++);
-           IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
        }
        (buf->r_locks)++;
        *buflock |= BL_R_LOCK;
@@ -2080,15 +2001,9 @@ LockBuffer(Buffer buffer, int mode)
                *buflock |= BL_RI_LOCK;
                buf->ri_lock = true;
            }
-#ifdef HAS_TEST_AND_SET
            S_UNLOCK(&(buf->cntx_lock));
            s_lock_sleep(i++);
            S_LOCK(&(buf->cntx_lock));
-#else
-           IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-           s_lock_sleep(i++);
-           IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
        }
        buf->w_lock = true;
        *buflock |= BL_W_LOCK;
@@ -2109,12 +2024,7 @@ LockBuffer(Buffer buffer, int mode)
    else
        elog(ERROR, "LockBuffer: unknown lock mode %d", mode);
 
-#ifdef HAS_TEST_AND_SET
    S_UNLOCK(&(buf->cntx_lock));
-#else
-   IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock);
-#endif
-
 }
 
 /*
@@ -2142,7 +2052,6 @@ StartBufferIO(BufferDesc *buf, bool forInput)
    Assert(!InProgressBuf);
    Assert(!(buf->flags & BM_IO_IN_PROGRESS));
    buf->flags |= BM_IO_IN_PROGRESS;
-#ifdef HAS_TEST_AND_SET
 
    /*
     * There used to be
@@ -2156,7 +2065,7 @@ StartBufferIO(BufferDesc *buf, bool forInput)
     * happen -- tgl
     */
    S_LOCK(&(buf->io_in_progress_lock));
-#endif  /* HAS_TEST_AND_SET */
+
    InProgressBuf = buf;
    IsForInput = forInput;
 }
@@ -2173,12 +2082,7 @@ static void
 TerminateBufferIO(BufferDesc *buf)
 {
    Assert(buf == InProgressBuf);
-#ifdef HAS_TEST_AND_SET
    S_UNLOCK(&(buf->io_in_progress_lock));
-#else
-   if (buf->refcount > 1)
-       SignalIO(buf);
-#endif  /* HAS_TEST_AND_SET */
    InProgressBuf = (BufferDesc *) 0;
 }
 
index 98d90bc62e02eeadbefc0ad6d7ce077efddf541b..920f7f9bfeb7d7115bd11eee83a928dcbdbc20fb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.53 2000/11/21 21:16:01 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.54 2000/11/28 23:27:56 tgl Exp $
  *
  * NOTES
  *
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "storage/ipc.h"
 #include "storage/s_lock.h"
@@ -51,6 +52,7 @@
 #include 
 #endif
 
+
 /*
  * This flag is set during proc_exit() to change elog()'s behavior,
  * so that an elog() from an on_proc_exit routine cannot get us out
  */
 bool       proc_exit_inprogress = false;
 
-static int UsePrivateMemory = 0;
+static IpcSemaphoreId InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
+                          int numSems, int permission,
+                          int semStartValue, bool removeOnExit);
+static void CallbackSemaphoreKill(int status, Datum semId);
+static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size,
+                                    int permission);
+static void IpcMemoryDetach(int status, Datum shmaddr);
+static void IpcMemoryDelete(int status, Datum shmId);
+static void *PrivateMemoryCreate(uint32 size);
+static void PrivateMemoryDelete(int status, Datum memaddr);
 
-static void IpcMemoryDetach(int status, char *shmaddr);
 
 /* ----------------------------------------------------------------
  *                     exit() handling stuff
+ *
+ * These functions are in generally the same spirit as atexit(2),
+ * but provide some additional features we need --- in particular,
+ * we want to register callbacks to invoke when we are disconnecting
+ * from a broken shared-memory context but not exiting the postmaster.
+ *
+ * Callback functions can take zero, one, or two args: the first passed
+ * arg is the integer exitcode, the second is the Datum supplied when
+ * the callback was registered.
+ *
+ * XXX these functions probably ought to live in some other module.
  * ----------------------------------------------------------------
  */
 
@@ -73,43 +94,12 @@ static struct ONEXIT
 {
    void        (*function) ();
    Datum       arg;
-}          on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];
+}          on_proc_exit_list[MAX_ON_EXITS],
+           on_shmem_exit_list[MAX_ON_EXITS];
 
 static int on_proc_exit_index,
            on_shmem_exit_index;
 
-typedef struct _PrivateMemStruct
-{
-   int         id;
-   char       *memptr;
-} PrivateMem;
-
-static PrivateMem IpcPrivateMem[16];
-
-
-static int
-PrivateMemoryCreate(IpcMemoryKey memKey,
-                   uint32 size)
-{
-   static int  memid = 0;
-
-   UsePrivateMemory = 1;
-
-   IpcPrivateMem[memid].id = memid;
-   IpcPrivateMem[memid].memptr = malloc(size);
-   if (IpcPrivateMem[memid].memptr == NULL)
-       elog(ERROR, "PrivateMemoryCreate: not enough memory to malloc");
-   MemSet(IpcPrivateMem[memid].memptr, 0, size);       /* XXX PURIFY */
-
-   return memid++;
-}
-
-static char *
-PrivateMemoryAttach(IpcMemoryId memid)
-{
-   return IpcPrivateMem[memid].memptr;
-}
-
 
 /* ----------------------------------------------------------------
  *     proc_exit
@@ -156,9 +146,9 @@ proc_exit(int code)
 }
 
 /* ------------------
- * Run all of the on_shmem_exit routines but don't exit in the end.
+ * Run all of the on_shmem_exit routines --- but don't actually exit.
  * This is used by the postmaster to re-initialize shared memory and
- * semaphores after a backend dies horribly
+ * semaphores after a backend dies horribly.
  * ------------------
  */
 void
@@ -188,18 +178,16 @@ shmem_exit(int code)
  *     functions invoked by proc_exit().   -cim 2/6/90
  * ----------------------------------------------------------------
  */
-int
+void
 on_proc_exit(void (*function) (), Datum arg)
 {
    if (on_proc_exit_index >= MAX_ON_EXITS)
-       return -1;
+       elog(FATAL, "Out of on_proc_exit slots");
 
    on_proc_exit_list[on_proc_exit_index].function = function;
    on_proc_exit_list[on_proc_exit_index].arg = arg;
 
    ++on_proc_exit_index;
-
-   return 0;
 }
 
 /* ----------------------------------------------------------------
@@ -209,24 +197,25 @@ on_proc_exit(void (*function) (), Datum arg)
  *     functions invoked by shmem_exit().  -cim 2/6/90
  * ----------------------------------------------------------------
  */
-int
+void
 on_shmem_exit(void (*function) (), Datum arg)
 {
    if (on_shmem_exit_index >= MAX_ON_EXITS)
-       return -1;
+       elog(FATAL, "Out of on_shmem_exit slots");
 
    on_shmem_exit_list[on_shmem_exit_index].function = function;
    on_shmem_exit_list[on_shmem_exit_index].arg = arg;
 
    ++on_shmem_exit_index;
-
-   return 0;
 }
 
 /* ----------------------------------------------------------------
  *     on_exit_reset
  *
- *     this function clears all proc_exit() registered functions.
+ *     this function clears all on_proc_exit() and on_shmem_exit()
+ *     registered functions.  This is used just after forking a backend,
+ *     so that the backend doesn't believe it should call the postmaster's
+ *     on-exit routines when it exits...
  * ----------------------------------------------------------------
  */
 void
@@ -236,190 +225,135 @@ on_exit_reset(void)
    on_proc_exit_index = 0;
 }
 
-/****************************************************************************/
-/*  IPCPrivateSemaphoreKill(status, semId)                                 */
-/*                                                                         */
-/****************************************************************************/
-static void
-IPCPrivateSemaphoreKill(int status, int semId)
-{
-   union semun semun;
-   semun.val = 0;      /* unused */
-
-   if (semctl(semId, 0, IPC_RMID, semun) == -1)
-       elog(NOTICE, "IPCPrivateSemaphoreKill: semctl(%d, 0, IPC_RMID, ...) failed: %s",
-            semId, strerror(errno));
-}
-
-
-/****************************************************************************/
-/*  IPCPrivateMemoryKill(status, shmId)                                    */
-/*                                                                         */
-/****************************************************************************/
-static void
-IPCPrivateMemoryKill(int status, int shmId)
-{
-   if (UsePrivateMemory)
-   {
-       /* free ( IpcPrivateMem[shmId].memptr ); */
-   }
-   else
-   {
-       if (shmctl(shmId, IPC_RMID, (struct shmid_ds *) NULL) < 0)
-       {
-           elog(NOTICE, "IPCPrivateMemoryKill: shmctl(%d, %d, 0) failed: %m",
-                shmId, IPC_RMID);
-       }
-    }
-}
 
-/*
- * Note:
- * XXX This should be split into two different calls.  One should
- * XXX be used to create a semaphore set.  The other to "attach" a
- * XXX existing set.  It should be an error for the semaphore set
- * XXX to to already exist or for it not to, respectively.
+/* ----------------------------------------------------------------
+ *                     Semaphore support
  *
- *     Currently, the semaphore sets are "attached" and an error
- *     is detected only when a later shared memory attach fails.
+ * These routines represent a fairly thin layer on top of SysV semaphore
+ * functionality.
+ * ----------------------------------------------------------------
  */
 
-IpcSemaphoreId
-IpcSemaphoreCreate(IpcSemaphoreKey semKey,
-                  int semNum,
-                  int permission,
-                  int semStartValue,
-                  int removeOnExit)
+/* ----------------------------------------------------------------
+ * InternalIpcSemaphoreCreate(semKey, numSems, permission,
+ *                            semStartValue, removeOnExit)
+ *
+ * Attempt to create a new semaphore set with the specified key.
+ * Will fail (return -1) if such a set already exists.
+ * On success, a callback is optionally registered with on_shmem_exit
+ * to delete the semaphore set when on_shmem_exit is called.
+ *
+ * If we fail with a failure code other than collision-with-existing-set,
+ * print out an error and abort.  Other types of errors are not recoverable.
+ * ----------------------------------------------------------------
+ */
+static IpcSemaphoreId
+InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey,
+                          int numSems, int permission,
+                          int semStartValue, bool removeOnExit)
 {
    int         semId;
    int         i;
-   int         errStatus;
    u_short     array[IPC_NMAXSEM];
    union semun semun;
 
-   /* check arguments  */
-   if (semNum > IPC_NMAXSEM || semNum <= 0)
-       return (-1);
+   Assert(numSems > 0 && numSems <= IPC_NMAXSEM);
 
-   semId = semget(semKey, 0, 0);
+   semId = semget(semKey, numSems, IPC_CREAT | IPC_EXCL | permission);
 
-   if (semId == -1)
+   if (semId < 0)
    {
-#ifdef DEBUG_IPC
-       fprintf(stderr, "calling semget(%d, %d, 0%o)\n",
-           semKey, semNum, (unsigned)(IPC_CREAT|permission));
-#endif
+       /*
+        * Fail quietly if error indicates a collision with existing set.
+        * One would expect EEXIST, given that we said IPC_EXCL, but perhaps
+        * we could get a permission violation instead?
+        */
+       if (errno == EEXIST || errno == EACCES)
+           return -1;
+       /*
+        * Else complain and abort
+        */
+       fprintf(stderr, "IpcSemaphoreCreate: semget(key=%d, num=%d, 0%o) failed: %s\n",
+               (int) semKey, numSems, (IPC_CREAT|IPC_EXCL|permission),
+               strerror(errno));
 
-       semId = semget(semKey, semNum, IPC_CREAT | permission);
+       if (errno == ENOSPC)
+           fprintf(stderr,
+                   "\nThis error does *not* mean that you have run out of disk space.\n\n"
+                   "It occurs either because system limit for the maximum number of\n"
+                   "semaphore sets (SEMMNI), or the system wide maximum number of\n"
+                   "semaphores (SEMMNS), would be exceeded.  You need to raise the\n"
+                   "respective kernel parameter.  Look into the PostgreSQL documentation\n"
+                   "for details.\n\n");
 
-       if (semId < 0)
-       {
-           fprintf(stderr, "IpcSemaphoreCreate: semget(key=%d, num=%d, 0%o) failed: %s\n",
-                   semKey, semNum, (unsigned)(permission|IPC_CREAT),
-                   strerror(errno));
-
-           if (errno == ENOSPC)
-               fprintf(stderr,
-                       "\nThis error does *not* mean that you have run out of disk space.\n\n"
-                       "It occurs either because system limit for the maximum number of\n"
-                       "semaphore sets (SEMMNI), or the system wide maximum number of\n"
-                       "semaphores (SEMMNS), would be exceeded.  You need to raise the\n"
-                       "respective kernel parameter.  Look into the PostgreSQL documentation\n"
-                       "for details.\n\n");
-
-           return (-1);
-       }
-       for (i = 0; i < semNum; i++)
-           array[i] = semStartValue;
-       semun.array = array;
-       errStatus = semctl(semId, 0, SETALL, semun);
-       if (errStatus == -1)
-       {
-           fprintf(stderr, "IpcSemaphoreCreate: semctl(id=%d, 0, SETALL, ...) failed: %s\n",
-                   semId, strerror(errno));
+       proc_exit(1);
+   }
 
-           if (errno == ERANGE)
-               fprintf(stderr,
-                       "You possibly need to raise your kernel's SEMVMX value to be at least\n"
-                       "%d.  Look into the PostgreSQL documentation for details.\n",
-                       semStartValue);
+   /* Initialize new semas to specified start value */
+   for (i = 0; i < numSems; i++)
+       array[i] = semStartValue;
+   semun.array = array;
+   if (semctl(semId, 0, SETALL, semun) < 0)
+   {
+       fprintf(stderr, "IpcSemaphoreCreate: semctl(id=%d, 0, SETALL, ...) failed: %s\n",
+               semId, strerror(errno));
 
-           semctl(semId, 0, IPC_RMID, semun);
-           return (-1);
-       }
+       if (errno == ERANGE)
+           fprintf(stderr,
+                   "You possibly need to raise your kernel's SEMVMX value to be at least\n"
+                   "%d.  Look into the PostgreSQL documentation for details.\n",
+                   semStartValue);
 
-       if (removeOnExit)
-           on_shmem_exit(IPCPrivateSemaphoreKill, (Datum) semId);
+       IpcSemaphoreKill(semId);
+       proc_exit(1);
    }
 
-
-#ifdef DEBUG_IPC
-   fprintf(stderr, "IpcSemaphoreCreate returns %d\n", semId);
-   fflush(stdout);
-   fflush(stderr);
-#endif
+   /* Register on-exit routine to delete the new set */
+   if (removeOnExit)
+       on_shmem_exit(CallbackSemaphoreKill, Int32GetDatum(semId));
 
    return semId;
 }
 
-
 /****************************************************************************/
-/*  IpcSemaphoreSet()          - sets the initial value of the semaphore   */
+/*  IpcSemaphoreKill(semId)    - removes a semaphore set                   */
 /*                                                                         */
-/*     note: the xxx_return variables are only used for debugging.         */
 /****************************************************************************/
-#ifdef NOT_USED
-static int IpcSemaphoreSet_return;
-
 void
-IpcSemaphoreSet(int semId, int semno, int value)
+IpcSemaphoreKill(IpcSemaphoreId semId)
 {
-   int         errStatus;
    union semun semun;
 
-   semun.val = value;
-   errStatus = semctl(semId, semno, SETVAL, semun);
-   IpcSemaphoreSet_return = errStatus;
+   semun.val = 0;      /* unused, but keep compiler quiet */
 
-   if (errStatus == -1)
-        fprintf(stderr, "IpcSemaphoreSet: semctl(id=%d) failed: %s\n",
+   if (semctl(semId, 0, IPC_RMID, semun) < 0)
+       fprintf(stderr, "IpcSemaphoreKill: semctl(%d, 0, IPC_RMID, ...) failed: %s\n",
                semId, strerror(errno));
+   /* We used to report a failure via elog(NOTICE), but that's pretty
+    * pointless considering any client has long since disconnected ...
+    */
 }
 
-#endif /* NOT_USED */
-
 /****************************************************************************/
-/*  IpcSemaphoreKill(key)      - removes a semaphore                       */
-/*                                                                         */
+/*  CallbackSemaphoreKill(status, semId)                                   */
+/* (called as an on_shmem_exit callback, hence funny argument list)        */
 /****************************************************************************/
-void
-IpcSemaphoreKill(IpcSemaphoreKey key)
+static void
+CallbackSemaphoreKill(int status, Datum semId)
 {
-   int         semId;
-   union semun semun;
-   semun.val = 0;      /* unused */
-
-   /* kill semaphore if existent */
-
-   semId = semget(key, 0, 0);
-   if (semId != -1)
-       semctl(semId, 0, IPC_RMID, semun);
+   IpcSemaphoreKill(DatumGetInt32(semId));
 }
 
 /****************************************************************************/
-/*  IpcSemaphoreLock(semId, sem, lock) - locks a semaphore                 */
-/*                                                                         */
-/*     note: the xxx_return variables are only used for debugging.         */
+/*  IpcSemaphoreLock(semId, sem) - locks a semaphore                       */
 /****************************************************************************/
-static int IpcSemaphoreLock_return;
-
 void
-IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
+IpcSemaphoreLock(IpcSemaphoreId semId, int sem)
 {
    int         errStatus;
    struct sembuf sops;
 
-   sops.sem_op = lock;
+   sops.sem_op = -1;           /* decrement */
    sops.sem_flg = 0;
    sops.sem_num = sem;
 
@@ -427,11 +361,6 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
     *  Note: if errStatus is -1 and errno == EINTR then it means we
     *        returned from the operation prematurely because we were
     *        sent a signal.  So we try and lock the semaphore again.
-    *        I am not certain this is correct, but the semantics aren't
-    *        clear it fixes problems with parallel abort synchronization,
-    *        namely that after processing an abort signal, the semaphore
-    *        call returns with -1 (and errno == EINTR) before it should.
-    *        -cim 3/28/90
     * ----------------
     */
    do
@@ -439,8 +368,6 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
        errStatus = semop(semId, &sops, 1);
    } while (errStatus == -1 && errno == EINTR);
 
-   IpcSemaphoreLock_return = errStatus;
-
    if (errStatus == -1)
    {
         fprintf(stderr, "IpcSemaphoreLock: semop(id=%d) failed: %s\n",
@@ -450,19 +377,15 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
 }
 
 /****************************************************************************/
-/*  IpcSemaphoreUnlock(semId, sem, lock)       - unlocks a semaphore       */
-/*                                                                         */
-/*     note: the xxx_return variables are only used for debugging.         */
+/*  IpcSemaphoreUnlock(semId, sem)     - unlocks a semaphore               */
 /****************************************************************************/
-static int IpcSemaphoreUnlock_return;
-
 void
-IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
+IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem)
 {
    int         errStatus;
    struct sembuf sops;
 
-   sops.sem_op = -lock;
+   sops.sem_op = 1;            /* increment */
    sops.sem_flg = 0;
    sops.sem_num = sem;
 
@@ -470,12 +393,8 @@ IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
    /* ----------------
     *  Note: if errStatus is -1 and errno == EINTR then it means we
     *        returned from the operation prematurely because we were
-    *        sent a signal.  So we try and lock the semaphore again.
-    *        I am not certain this is correct, but the semantics aren't
-    *        clear it fixes problems with parallel abort synchronization,
-    *        namely that after processing an abort signal, the semaphore
-    *        call returns with -1 (and errno == EINTR) before it should.
-    *        -cim 3/28/90
+    *        sent a signal.  So we try and unlock the semaphore again.
+    *        Not clear this can really happen, but might as well cope.
     * ----------------
     */
    do
@@ -483,8 +402,6 @@ IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
        errStatus = semop(semId, &sops, 1);
    } while (errStatus == -1 && errno == EINTR);
 
-   IpcSemaphoreUnlock_return = errStatus;
-
    if (errStatus == -1)
    {
        fprintf(stderr, "IpcSemaphoreUnlock: semop(id=%d) failed: %s\n",
@@ -493,53 +410,115 @@ IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
    }
 }
 
+/****************************************************************************/
+/*  IpcSemaphoreTryLock(semId, sem)    - conditionally locks a semaphore   */
+/* Lock the semaphore if it's free, but don't block.                       */
+/****************************************************************************/
+bool
+IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem)
+{
+   int         errStatus;
+   struct sembuf sops;
+
+   sops.sem_op = -1;           /* decrement */
+   sops.sem_flg = IPC_NOWAIT;  /* but don't block */
+   sops.sem_num = sem;
+
+   /* ----------------
+    *  Note: if errStatus is -1 and errno == EINTR then it means we
+    *        returned from the operation prematurely because we were
+    *        sent a signal.  So we try and lock the semaphore again.
+    * ----------------
+    */
+   do
+   {
+       errStatus = semop(semId, &sops, 1);
+   } while (errStatus == -1 && errno == EINTR);
+
+   if (errStatus == -1)
+   {
+       /* Expect EAGAIN or EWOULDBLOCK (platform-dependent) */
+#ifdef EAGAIN
+       if (errno == EAGAIN)
+           return false;       /* failed to lock it */
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+       if (errno == EWOULDBLOCK)
+           return false;       /* failed to lock it */
+#endif
+       /* Otherwise we got trouble */
+        fprintf(stderr, "IpcSemaphoreTryLock: semop(id=%d) failed: %s\n",
+               semId, strerror(errno));
+       proc_exit(255);
+   }
+
+   return true;
+}
+
+/* Get the current value (semval) of the semaphore */
 int
-IpcSemaphoreGetCount(IpcSemaphoreId semId, int sem)
+IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
 {
-   int         semncnt;
    union semun dummy;          /* for Solaris */
    dummy.val = 0;      /* unused */
 
-   semncnt = semctl(semId, sem, GETNCNT, dummy);
-   return semncnt;
+   return semctl(semId, sem, GETVAL, dummy);
 }
 
-int
-IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
+/* Get the PID of the last process to do semop() on the semaphore */
+static pid_t
+IpcSemaphoreGetLastPID(IpcSemaphoreId semId, int sem)
 {
-   int         semval;
    union semun dummy;          /* for Solaris */
    dummy.val = 0;      /* unused */
 
-   semval = semctl(semId, sem, GETVAL, dummy);
-   return semval;
+   return semctl(semId, sem, GETPID, dummy);
 }
 
-/****************************************************************************/
-/*  IpcMemoryCreate(memKey)                                                */
-/*                                                                         */
-/*   - returns the memory identifier, if creation succeeds                 */
-/*     returns IpcMemCreationFailed, if failure                            */
-/****************************************************************************/
 
-IpcMemoryId
-IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
+/* ----------------------------------------------------------------
+ *                     Shared memory support
+ *
+ * These routines represent a fairly thin layer on top of SysV shared
+ * memory functionality.
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ * InternalIpcMemoryCreate(memKey, size, permission)
+ *
+ * Attempt to create a new shared memory segment with the specified key.
+ * Will fail (return NULL) if such a segment already exists.  If successful,
+ * attach the segment to the current process and return its attached address.
+ * On success, callbacks are registered with on_shmem_exit to detach and
+ * delete the segment when on_shmem_exit is called.
+ *
+ * If we fail with a failure code other than collision-with-existing-segment,
+ * print out an error and abort.  Other types of errors are not recoverable.
+ * ----------------------------------------------------------------
+ */
+static void *
+InternalIpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
 {
    IpcMemoryId shmid;
+   void       *memAddress;
 
-   if (memKey == PrivateIPCKey)
-   {
-       /* private */
-       shmid = PrivateMemoryCreate(memKey, size);
-   }
-   else
-
-       shmid = shmget(memKey, size, IPC_CREAT | permission);
+   shmid = shmget(memKey, size, IPC_CREAT | IPC_EXCL | permission);
 
    if (shmid < 0)
    {
-       fprintf(stderr, "IpcMemoryCreate: shmget(key=%d, size=%d, 0%o) failed: %s\n",
-               (int)memKey, size, (unsigned)(IPC_CREAT|permission),
+       /*
+        * Fail quietly if error indicates a collision with existing segment.
+        * One would expect EEXIST, given that we said IPC_EXCL, but perhaps
+        * we could get a permission violation instead?
+        */
+       if (errno == EEXIST || errno == EACCES)
+           return NULL;
+       /*
+        * Else complain and abort
+        */
+       fprintf(stderr, "IpcMemoryCreate: shmget(key=%d, size=%u, 0%o) failed: %s\n",
+               (int) memKey, size, (IPC_CREAT | IPC_EXCL | permission),
                strerror(errno));
 
        if (errno == EINVAL)
@@ -547,7 +526,7 @@ IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
                    "\nThis error can be caused by one of three things:\n\n"
                    "1. The maximum size for shared memory segments on your system was\n"
                    "   exceeded.  You need to raise the SHMMAX parameter in your kernel\n"
-                   "   to be at least %d bytes.\n\n"
+                   "   to be at least %u bytes.\n\n"
                    "2. The requested shared memory segment was too small for your system.\n"
                    "   You need to lower the SHMMIN parameter in your kernel.\n\n"
                    "3. The requested shared memory segment already exists but is of the\n"
@@ -567,179 +546,302 @@ IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
                    "reached.  The PostgreSQL Administrator's Guide contains more\n"
                    "information about shared memory configuration.\n\n");
 
-       return IpcMemCreationFailed;
+       proc_exit(1);
    }
 
+   /* Register on-exit routine to delete the new segment */
+   on_shmem_exit(IpcMemoryDelete, Int32GetDatum(shmid));
 
-   /* if (memKey == PrivateIPCKey) */
-   on_shmem_exit(IPCPrivateMemoryKill, (Datum) shmid);
+   /* OK, should be able to attach to the segment */
+   memAddress = shmat(shmid, 0, 0);
 
-   return shmid;
-}
-
-/****************************************************************************/
-/* IpcMemoryIdGet(memKey, size)    returns the shared memory Id            */
-/*                                 or IpcMemIdGetFailed                    */
-/****************************************************************************/
-IpcMemoryId
-IpcMemoryIdGet(IpcMemoryKey memKey, uint32 size)
-{
-   IpcMemoryId shmid;
-
-   shmid = shmget(memKey, size, 0);
-
-   if (shmid < 0)
+   if (memAddress == (void *) -1)
    {
-       fprintf(stderr, "IpcMemoryIdGet: shmget(key=%d, size=%d, 0) failed: %s\n",
-               memKey, size, strerror(errno));
-       return IpcMemIdGetFailed;
+        fprintf(stderr, "IpcMemoryCreate: shmat(id=%d) failed: %s\n",
+               shmid, strerror(errno));
+       proc_exit(1);
    }
 
-   return shmid;
+   /* Register on-exit routine to detach new segment before deleting */
+   on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress));
+
+   return memAddress;
 }
 
 /****************************************************************************/
 /* IpcMemoryDetach(status, shmaddr)    removes a shared memory segment     */
-/*                                     from a backend address space        */
-/* (only called by backends running under the postmaster)                  */
+/*                                     from process' address spaceq        */
+/* (called as an on_shmem_exit callback, hence funny argument list)        */
 /****************************************************************************/
 static void
-IpcMemoryDetach(int status, char *shmaddr)
+IpcMemoryDetach(int status, Datum shmaddr)
 {
-   if (shmdt(shmaddr) < 0)
-       elog(NOTICE, "IpcMemoryDetach: shmdt(0x%p) failed: %m", shmaddr);
+   if (shmdt(DatumGetPointer(shmaddr)) < 0)
+       fprintf(stderr, "IpcMemoryDetach: shmdt(%p) failed: %s\n",
+               DatumGetPointer(shmaddr), strerror(errno));
+   /* We used to report a failure via elog(NOTICE), but that's pretty
+    * pointless considering any client has long since disconnected ...
+    */
 }
 
 /****************************************************************************/
-/* IpcMemoryAttach(memId)    returns the adress of shared memory           */
-/*                           or IpcMemAttachFailed                         */
-/*                                                                         */
-/* CALL IT:  addr = (struct  *) IpcMemoryAttach(memId);   */
-/*                                                                         */
+/* IpcMemoryDelete(status, shmId)      deletes a shared memory segment     */
+/* (called as an on_shmem_exit callback, hence funny argument list)        */
 /****************************************************************************/
-char *
-IpcMemoryAttach(IpcMemoryId memId)
+static void
+IpcMemoryDelete(int status, Datum shmId)
 {
-   char       *memAddress;
+   if (shmctl(DatumGetInt32(shmId), IPC_RMID, (struct shmid_ds *) NULL) < 0)
+       fprintf(stderr, "IpcMemoryDelete: shmctl(%d, %d, 0) failed: %s\n",
+               DatumGetInt32(shmId), IPC_RMID, strerror(errno));
+   /* We used to report a failure via elog(NOTICE), but that's pretty
+    * pointless considering any client has long since disconnected ...
+    */
+}
 
-   if (UsePrivateMemory)
-       memAddress = (char *) PrivateMemoryAttach(memId);
-   else
-       memAddress = (char *) shmat(memId, 0, 0);
+/* ----------------------------------------------------------------
+ *                     private memory support
+ *
+ * Rather than allocating shmem segments with IPC_PRIVATE key, we
+ * just malloc() the requested amount of space.  This code emulates
+ * the needed shmem functions.
+ * ----------------------------------------------------------------
+ */
 
-   /* if ( *memAddress == -1) { XXX ??? */
-   if (memAddress == (char *) -1)
+static void *
+PrivateMemoryCreate(uint32 size)
+{
+   void       *memAddress;
+
+   memAddress = malloc(size);
+   if (!memAddress)
    {
-        fprintf(stderr, "IpcMemoryAttach: shmat(id=%d) failed: %s\n",
-               memId, strerror(errno));
-       return IpcMemAttachFailed;
+       fprintf(stderr, "PrivateMemoryCreate: malloc(%u) failed\n", size);
+       proc_exit(1);
    }
+   MemSet(memAddress, 0, size);        /* keep Purify quiet */
 
-   if (!UsePrivateMemory)
-       on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress));
+   /* Register on-exit routine to release storage */
+   on_shmem_exit(PrivateMemoryDelete, PointerGetDatum(memAddress));
 
-   return (char *) memAddress;
+   return memAddress;
 }
 
-
-/****************************************************************************/
-/* IpcMemoryKill(memKey)               removes a shared memory segment     */
-/* (only called by the postmaster and standalone backends)                 */
-/****************************************************************************/
-void
-IpcMemoryKill(IpcMemoryKey memKey)
+static void
+PrivateMemoryDelete(int status, Datum memaddr)
 {
-   IpcMemoryId shmid;
-
-   if (!UsePrivateMemory && (shmid = shmget(memKey, 0, 0)) >= 0)
-   {
-       if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL) < 0)
-       {
-           elog(NOTICE, "IpcMemoryKill: shmctl(%d, %d, 0) failed: %m",
-                shmid, IPC_RMID);
-       }
-   }
+   free(DatumGetPointer(memaddr));
 }
 
-#ifdef HAS_TEST_AND_SET
+
 /* ------------------
- * use hardware locks to replace semaphores for sequent machines
- * to avoid costs of swapping processes and to provide unlimited
- * supply of locks.
+ *             Routines to assign keys for new IPC objects
+ *
+ * The idea here is to detect and re-use keys that may have been assigned
+ * by a crashed postmaster or backend.
  * ------------------
  */
 
-/* used in spin.c */
-SLock     *SLockArray = NULL;
+static IpcMemoryKey NextShmemSegID = 0;
+static IpcSemaphoreKey NextSemaID = 0;
 
-static SLock **FreeSLockPP;
-static int *UnusedSLockIP;
-static slock_t *SLockMemoryLock;
-static IpcMemoryId SLockMemoryId = -1;
+/*
+ * (Re) initialize key assignment at startup of postmaster or standalone
+ * backend, also at postmaster reset.
+ */
+void
+IpcInitKeyAssignment(int port)
+{
+   NextShmemSegID = port * 1000;
+   NextSemaID = port * 1000;
+}
 
-struct ipcdummy
-{                              /* to get alignment/size right */
-   SLock      *free;
-   int         unused;
-   slock_t     memlock;
-   SLock       slocks[MAX_SPINS + 1];
-};
+/*
+ * Create a shared memory segment of the given size and initialize its
+ * standard header.  Dead Postgres segments are recycled if found,
+ * but we do not fail upon collision with non-Postgres shmem segments.
+ */
+PGShmemHeader *
+IpcMemoryCreate(uint32 size, bool private, int permission)
+{
+   void   *memAddress;
+   PGShmemHeader *hdr;
 
-#define SLOCKMEMORYSIZE        sizeof(struct ipcdummy)
+   /* Room for a header? */
+   Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
 
-void
-CreateAndInitSLockMemory(IPCKey key)
-{
-   int         id;
-   SLock      *slckP;
-
-   SLockMemoryId = IpcMemoryCreate(key,
-                                   SLOCKMEMORYSIZE,
-                                   0700);
-   AttachSLockMemory(key);
-   *FreeSLockPP = NULL;
-   *UnusedSLockIP = (int) FIRSTFREELOCKID;
-   for (id = 0; id < (int) FIRSTFREELOCKID; id++)
+   /* Loop till we find a free IPC key */
+   for (NextShmemSegID++ ; ; NextShmemSegID++)
    {
-       slckP = &(SLockArray[id]);
-       S_INIT_LOCK(&(slckP->locklock));
-       slckP->flag = NOLOCK;
-       slckP->nshlocks = 0;
-       S_INIT_LOCK(&(slckP->shlock));
-       S_INIT_LOCK(&(slckP->exlock));
-       S_INIT_LOCK(&(slckP->comlock));
-       slckP->next = NULL;
+       IpcMemoryId shmid;
+
+       /* Special case if creating a private segment --- just malloc() it */
+       if (private)
+       {
+           memAddress = PrivateMemoryCreate(size);
+           break;
+       }
+
+       /* Try to create new segment */
+       memAddress = InternalIpcMemoryCreate(NextShmemSegID, size, permission);
+       if (memAddress)
+           break;              /* successful create and attach */
+
+       /* See if it looks to be leftover from a dead Postgres process */
+       shmid = shmget(NextShmemSegID, sizeof(PGShmemHeader), 0);
+       if (shmid < 0)
+           continue;           /* failed: must be some other app's */
+       memAddress = shmat(shmid, 0, 0);
+       if (memAddress == (void *) -1)
+           continue;           /* failed: must be some other app's */
+       hdr = (PGShmemHeader *) memAddress;
+       if (hdr->magic != PGShmemMagic)
+       {
+           shmdt(memAddress);
+           continue;           /* segment belongs to a non-Postgres app */
+       }
+       /*
+        * If the creator PID is my own PID or does not belong to any
+        * extant process, it's safe to zap it.
+        */
+       if (hdr->creatorPID != getpid())
+       {
+           if (kill(hdr->creatorPID, 0) == 0 ||
+               errno != ESRCH)
+           {
+               shmdt(memAddress);
+               continue;       /* segment belongs to a live process */
+           }
+       }
+       /*
+        * The segment appears to be from a dead Postgres process, or
+        * from a previous cycle of life in this same process.  Zap it,
+        * if possible.  This probably shouldn't fail, but if it does,
+        * assume the segment belongs to someone else after all,
+        * and continue quietly.
+        */
+       shmdt(memAddress);
+       if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL) < 0)
+           continue;
+       /*
+        * Now try again to create the segment.
+        */
+       memAddress = InternalIpcMemoryCreate(NextShmemSegID, size, permission);
+       if (memAddress)
+           break;              /* successful create and attach */
+       /*
+        * Can only get here if some other process managed to create the
+        * same shmem key before we did.  Let him have that one,
+        * loop around to try next key.
+        */
    }
-   return;
-}
+   /*
+    * OK, we created a new segment.  Mark it as created by this process.
+    * The order of assignments here is critical so that another Postgres
+    * process can't see the header as valid but belonging to an invalid
+    * PID!
+    */
+   hdr = (PGShmemHeader *) memAddress;
+   hdr->creatorPID = getpid();
+   hdr->magic = PGShmemMagic;
+   /*
+    * Initialize space allocation status for segment.
+    */
+   hdr->totalsize = size;
+   hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
 
-void
-AttachSLockMemory(IPCKey key)
-{
-   struct ipcdummy *slockM;
-
-   if (SLockMemoryId == -1)
-       SLockMemoryId = IpcMemoryIdGet(key, SLOCKMEMORYSIZE);
-   if (SLockMemoryId == -1)
-       elog(FATAL, "SLockMemory not in shared memory");
-   slockM = (struct ipcdummy *) IpcMemoryAttach(SLockMemoryId);
-   if (slockM == IpcMemAttachFailed)
-       elog(FATAL, "AttachSLockMemory: could not attach segment");
-   FreeSLockPP = (SLock **) &(slockM->free);
-   UnusedSLockIP = (int *) &(slockM->unused);
-   SLockMemoryLock = (slock_t *) &(slockM->memlock);
-   S_INIT_LOCK(SLockMemoryLock);
-   SLockArray = (SLock *) &(slockM->slocks[0]);
-   return;
+   return hdr;
 }
 
-#ifdef NOT_USED
-bool
-LockIsFree(int lockid)
+/*
+ * Create a semaphore set with the given number of useful semaphores
+ * (an additional sema is actually allocated to serve as identifier).
+ * Dead Postgres sema sets are recycled if found, but we do not fail
+ * upon collision with non-Postgres sema sets.
+ */
+IpcSemaphoreId
+IpcSemaphoreCreate(int numSems, int permission,
+                  int semStartValue, bool removeOnExit)
 {
-   return SLockArray[lockid].flag == NOLOCK;
-}
+   IpcSemaphoreId  semId;
+   union semun semun;
 
-#endif
+   /* Loop till we find a free IPC key */
+   for (NextSemaID++ ; ; NextSemaID++)
+   {
+       pid_t   creatorPID;
+
+       /* Try to create new semaphore set */
+       semId = InternalIpcSemaphoreCreate(NextSemaID, numSems+1,
+                                          permission, semStartValue,
+                                          removeOnExit);
+       if (semId >= 0)
+           break;              /* successful create */
 
-#endif  /* HAS_TEST_AND_SET */
+       /* See if it looks to be leftover from a dead Postgres process */
+       semId = semget(NextSemaID, numSems+1, 0);
+       if (semId < 0)
+           continue;           /* failed: must be some other app's */
+       if (IpcSemaphoreGetValue(semId, numSems) != PGSemaMagic)
+           continue;           /* sema belongs to a non-Postgres app */
+       /*
+        * If the creator PID is my own PID or does not belong to any
+        * extant process, it's safe to zap it.
+        */
+       creatorPID = IpcSemaphoreGetLastPID(semId, numSems);
+       if (creatorPID <= 0)
+           continue;           /* oops, GETPID failed */
+       if (creatorPID != getpid())
+       {
+           if (kill(creatorPID, 0) == 0 ||
+               errno != ESRCH)
+               continue;       /* sema belongs to a live process */
+       }
+       /*
+        * The sema set appears to be from a dead Postgres process, or
+        * from a previous cycle of life in this same process.  Zap it,
+        * if possible.  This probably shouldn't fail, but if it does,
+        * assume the sema set belongs to someone else after all,
+        * and continue quietly.
+        */
+       semun.val = 0;          /* unused, but keep compiler quiet */
+       if (semctl(semId, 0, IPC_RMID, semun) < 0)
+           continue;
+       /*
+        * Now try again to create the sema set.
+        */
+       semId = InternalIpcSemaphoreCreate(NextSemaID, numSems+1,
+                                          permission, semStartValue,
+                                          removeOnExit);
+       if (semId >= 0)
+           break;              /* successful create */
+       /*
+        * Can only get here if some other process managed to create the
+        * same sema key before we did.  Let him have that one,
+        * loop around to try next key.
+        */
+   }
+   /*
+    * OK, we created a new sema set.  Mark it as created by this process.
+    * We do this by setting the spare semaphore to PGSemaMagic-1 and then
+    * incrementing it with semop().  That leaves it with value PGSemaMagic
+    * and sempid referencing this process.
+    */
+   semun.val = PGSemaMagic-1;
+   if (semctl(semId, numSems, SETVAL, semun) < 0)
+   {
+       fprintf(stderr, "IpcSemaphoreCreate: semctl(id=%d, %d, SETVAL, %d) failed: %s\n",
+               semId, numSems, PGSemaMagic-1, strerror(errno));
+
+       if (errno == ERANGE)
+           fprintf(stderr,
+                   "You possibly need to raise your kernel's SEMVMX value to be at least\n"
+                   "%d.  Look into the PostgreSQL documentation for details.\n",
+                   PGSemaMagic);
+
+       proc_exit(1);
+   }
+   IpcSemaphoreUnlock(semId, numSems);
+
+   return semId;
+}
index 5c7e88af73e42d1069b27a163e469a9c62e6c5d7..7a5813df57d0952ee7c2eb964a278cce6ed2ce06 100644 (file)
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.34 2000/11/21 21:16:01 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.35 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-#include 
-
 #include "postgres.h"
 
+#include 
+
 #include "miscadmin.h"
 #include "access/xlog.h"
 #include "storage/bufmgr.h"
+#include "storage/proc.h"
 #include "storage/sinval.h"
+#include "storage/spin.h"
 
-/*
- * SystemPortAddressCreateMemoryKey
- *     Returns a memory key given a port address.
- */
-IPCKey
-SystemPortAddressCreateIPCKey(SystemPortAddress address)
-{
-   Assert(address < 32768);    /* XXX */
-
-   return SystemPortAddressGetIPCKey(address);
-}
 
 /*
  * CreateSharedMemoryAndSemaphores
  *     Creates and initializes shared memory and semaphores.
+ *
+ * This is called by the postmaster or by a standalone backend.
+ * It is NEVER called by a backend forked from the postmaster;
+ * for such a backend, the shared memory is already ready-to-go.
+ *
+ * If "private" is true then we only need private memory, not shared
+ * memory.  This is true for a standalone backend, false for a postmaster.
  */
-/**************************************************
-
-  CreateSharedMemoryAndSemaphores
-  is called exactly *ONCE* by the postmaster.
-  It is *NEVER* called by the postgres backend,
-  except in the case of a standalone backend.
-
-  0) destroy any existing semaphores for both buffer
-  and lock managers.
-  1) create the appropriate *SHARED* memory segments
-  for the two resource managers.
-  2) create shared semaphores as needed.
-
-  **************************************************/
-
 void
-CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends)
+CreateSharedMemoryAndSemaphores(bool private, int maxBackends)
 {
    int         size;
-
-#ifdef HAS_TEST_AND_SET
-
-   /*
-    * Create shared memory for slocks
-    */
-   CreateAndInitSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
-#endif
-
-   /*
-    * Kill and create the buffer manager buffer pool (and semaphore)
-    */
-   CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key));
+   PGShmemHeader *seghdr;
 
    /*
-    * Size of the primary shared-memory block is estimated via
+    * Size of the Postgres shared-memory block is estimated via
     * moderately-accurate estimates for the big hogs, plus 100K for the
     * stuff that's too small to bother with estimating.
     */
-   size = BufferShmemSize() + LockShmemSize(maxBackends) + XLOGShmemSize();
+   size = BufferShmemSize() + LockShmemSize(maxBackends) +
+       XLOGShmemSize() + SLockShmemSize() + SInvalShmemSize(maxBackends);
 #ifdef STABLE_MEMORY_STORAGE
    size += MMShmemSize();
 #endif
    size += 100000;
-   /* might as well round it off to a multiple of a K or so... */
-   size += 1024 - (size % 1024);
+   /* might as well round it off to a multiple of a typical page size */
+   size += 8192 - (size % 8192);
 
    if (DebugLvl > 1)
-   {
-       fprintf(stderr, "binding ShmemCreate(key=%x, size=%d)\n",
-               IPCKeyGetBufferMemoryKey(key), size);
-   }
-   ShmemCreate(IPCKeyGetBufferMemoryKey(key), size);
-   ShmemIndexReset();
-   InitShmem(key, size);
-   XLOGShmemInit();
-   InitBufferPool(key);
+       fprintf(stderr, "invoking IpcMemoryCreate(size=%d)\n", size);
 
-   /* ----------------
-    *  do the lock table stuff
-    * ----------------
+   /*
+    * Create the shmem segment
     */
-   InitLocks();
-   if (InitLockTable() == INVALID_TABLEID)
-       elog(FATAL, "Couldn't create the lock table");
+   seghdr = IpcMemoryCreate(size, private, IPCProtection);
 
-   /* ----------------
-    *  do process table stuff
-    * ----------------
+   /*
+    * First initialize spinlocks --- needed by InitShmemAllocation()
     */
-   InitProcGlobal(key, maxBackends);
-
-   CreateSharedInvalidationState(key, maxBackends);
-}
-
+   CreateSpinlocks(seghdr);
 
-/*
- * AttachSharedMemoryAndSemaphores
- *     Attachs existant shared memory and semaphores.
- */
-void
-AttachSharedMemoryAndSemaphores(IPCKey key)
-{
-   /* ----------------
-    *  create rather than attach if using private key
-    * ----------------
+   /*
+    * Set up shmem.c hashtable
     */
-   if (key == PrivateIPCKey)
-   {
-       CreateSharedMemoryAndSemaphores(key, 16);
-       return;
-   }
+   InitShmemAllocation(seghdr);
 
-#ifdef HAS_TEST_AND_SET
-   /* ----------------
-    *  attach the slock shared memory
-    * ----------------
-    */
-   AttachSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
-#endif
-   /* ----------------
-    *  attach the buffer manager buffer pool (and semaphore)
-    * ----------------
+   /*
+    * Set up xlog and buffers
     */
-   InitShmem(key, 0);
-   InitBufferPool(key);
+   XLOGShmemInit();
+   InitBufferPool();
 
-   /* ----------------
-    *  initialize lock table stuff
-    * ----------------
+   /*
+    * Set up lock manager
     */
    InitLocks();
    if (InitLockTable() == INVALID_TABLEID)
-       elog(FATAL, "Couldn't attach to the lock table");
+       elog(FATAL, "Couldn't create the lock table");
+
+   /*
+    * Set up process table
+    */
+   InitProcGlobal(maxBackends);
 
-   AttachSharedInvalidationState(key);
+   /*
+    * Set up shared-inval messaging
+    */
+   CreateSharedInvalidationState(maxBackends);
 }
index c5048a389b1ade3bb88cc2ad0d7e9908349e428a..1592294708752bf92e8822eea4b4bda217d9de89 100644 (file)
@@ -8,14 +8,14 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.54 2000/11/21 21:16:01 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.55 2000/11/28 23:27:56 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 backends via fork().  The routines in this file are used for
+ * by each backend via fork().  The routines in this file are used for
  * allocating and binding to shared memory data structures.
  *
  * NOTES:
  *
  *     See InitSem() in sem.c for an example of how to use the
  * shmem index.
- *
  */
 
 #include "postgres.h"
+
 #include "access/transam.h"
 #include "utils/tqual.h"
 
 /* shared memory global variables */
 
-unsigned long ShmemBase = 0;   /* start and end address of shared memory */
-static unsigned long ShmemEnd = 0;
-static unsigned long ShmemSize = 0;        /* current size (and default) */
+static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
+
+SHMEM_OFFSET ShmemBase;            /* start address of shared memory */
+
+static SHMEM_OFFSET ShmemEnd;  /* end+1 address of shared memory */
 
 SPINLOCK   ShmemLock;          /* lock for shared memory allocation */
 
 SPINLOCK   ShmemIndexLock;     /* lock for shmem index access */
 
-static unsigned long *ShmemFreeStart = NULL;   /* pointer to the OFFSET
-                                                * of first free shared
-                                                * memory */
-static unsigned long *ShmemIndexOffset = NULL; /* start of the shmem
-                                                * index table (for
-                                                * bootstrap) */
-static int ShmemBootstrap = FALSE;     /* flag becomes true when shared
-                                        * mem is created by POSTMASTER */
-
-static HTAB *ShmemIndex = NULL;
-
-/* ---------------------
- * ShmemIndexReset() - Resets the shmem index to NULL....
- * useful when the postmaster destroys existing shared memory
- * and creates all new segments after a backend crash.
- * ----------------------
- */
-void
-ShmemIndexReset(void)
-{
-   ShmemIndex = (HTAB *) NULL;
-}
+static HTAB *ShmemIndex = NULL;    /* primary index hashtable for shmem */
 
-/*
- * CreateSharedRegion()
- *
- * This routine is called once by the postmaster to
- * initialize the shared buffer pool.  Assume there is
- * only one postmaster so no synchronization is necessary
- * until after this routine completes successfully.
- *
- * key is a unique identifier for the shmem region.
- * size is the size of the region.
- */
-static IpcMemoryId ShmemId;
+static bool ShmemBootstrap = false;    /* bootstrapping shmem index? */
 
-void
-ShmemCreate(unsigned int key, unsigned int size)
-{
-   if (size)
-       ShmemSize = size;
-   /* create shared mem region */
-   if ((ShmemId = IpcMemoryCreate(key, ShmemSize, IPCProtection))
-       == IpcMemCreationFailed)
-   {
-       elog(FATAL, "ShmemCreate: cannot create region");
-       exit(1);
-   }
-
-   /*
-    * ShmemBootstrap is true if shared memory has been created, but not
-    * yet initialized.  Only the postmaster/creator-of-all-things should
-    * have this flag set.
-    */
-   ShmemBootstrap = TRUE;
-}
 
 /*
- * InitShmem() -- map region into process address space
- *     and initialize shared data structures.
- *
+ * InitShmemAllocation() --- set up shared-memory allocation and index table.
  */
-int
-InitShmem(unsigned int key, unsigned int size)
+void
+InitShmemAllocation(PGShmemHeader *seghdr)
 {
-   Pointer     sharedRegion;
-   unsigned long currFreeSpace;
-
    HASHCTL     info;
    int         hash_flags;
    ShmemIndexEnt *result,
                item;
    bool        found;
-   IpcMemoryId shmid;
-
-   /* if zero key, use default memory size */
-   if (size)
-       ShmemSize = size;
-
-   /* default key is 0 */
-
-   /* attach to shared memory region (SysV or BSD OS specific) */
-   if (ShmemBootstrap && key == PrivateIPCKey)
-       /* if we are running backend alone */
-       shmid = ShmemId;
-   else
-       shmid = IpcMemoryIdGet(IPCKeyGetBufferMemoryKey(key), ShmemSize);
-   sharedRegion = IpcMemoryAttach(shmid);
-   if (sharedRegion == NULL)
-   {
-       elog(FATAL, "AttachSharedRegion: couldn't attach to shmem\n");
-       return FALSE;
-   }
-
-   /* get pointers to the dimensions of shared memory */
-   ShmemBase = (unsigned long) sharedRegion;
-   ShmemEnd = (unsigned long) sharedRegion + ShmemSize;
-
-   /* First long in shared memory is the available-space pointer */
-   ShmemFreeStart = (unsigned long *) ShmemBase;
-   /* next is a shmem pointer to the shmem index */
-   ShmemIndexOffset = ShmemFreeStart + 1;
-   /* next is ShmemVariableCache */
-   ShmemVariableCache = (VariableCache) (ShmemIndexOffset + 1);
-
-   /* here is where to start dynamic allocation */
-   currFreeSpace = MAXALIGN(sizeof(*ShmemFreeStart) +
-                            sizeof(*ShmemIndexOffset) +
-                            sizeof(*ShmemVariableCache));
 
-   /*
-    * bootstrap initialize spin locks so we can start to use the
-    * allocator and shmem index.
-    */
-   InitSpinLocks();
+   /* Set up basic pointers to shared memory */
+   ShmemSegHdr = seghdr;
+   ShmemBase = (SHMEM_OFFSET) seghdr;
+   ShmemEnd = ShmemBase + seghdr->totalsize;
 
    /*
-    * We have just allocated additional space for two spinlocks. Now
-    * setup the global free space count
+    * Since ShmemInitHash calls ShmemInitStruct, which expects the
+    * ShmemIndex hashtable to exist already, we have a bit of a circularity
+    * problem in initializing the ShmemIndex itself.  We set ShmemBootstrap
+    * to tell ShmemInitStruct to fake it.
     */
-   if (ShmemBootstrap)
-   {
-       *ShmemFreeStart = currFreeSpace;
-       memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
-   }
-
-   /* if ShmemFreeStart is NULL, then the allocator won't work */
-   Assert(*ShmemFreeStart);
+   ShmemIndex = (HTAB *) NULL;
+   ShmemBootstrap = true;
 
-   /* create OR attach to the shared memory shmem index */
+   /* create the shared memory shmem index */
    info.keysize = SHMEM_INDEX_KEYSIZE;
    info.datasize = SHMEM_INDEX_DATASIZE;
    hash_flags = HASH_ELEM;
@@ -211,60 +115,43 @@ InitShmem(unsigned int key, unsigned int size)
    ShmemIndex = ShmemInitHash("ShmemIndex",
                               SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
                               &info, hash_flags);
-
    if (!ShmemIndex)
-   {
-       elog(FATAL, "InitShmem: couldn't initialize Shmem Index");
-       return FALSE;
-   }
+       elog(FATAL, "InitShmemAllocation: couldn't initialize Shmem Index");
 
    /*
-    * Now, check the shmem index for an entry to the shmem index.  If
-    * there is an entry there, someone else created the table. Otherwise,
-    * we did and we have to initialize it.
+    * Now, create an entry in the hashtable for the index itself.
     */
    MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE);
    strncpy(item.key, "ShmemIndex", SHMEM_INDEX_KEYSIZE);
 
    result = (ShmemIndexEnt *)
        hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
-
-
    if (!result)
-   {
-       elog(FATAL, "InitShmem: corrupted shmem index");
-       return FALSE;
-   }
-
-   if (!found)
-   {
+       elog(FATAL, "InitShmemAllocation: corrupted shmem index");
 
-       /*
-        * bootstrapping shmem: we have to initialize the shmem index now.
-        */
+   Assert(ShmemBootstrap && !found);
 
-       Assert(ShmemBootstrap);
-       result->location = MAKE_OFFSET(ShmemIndex->hctl);
-       *ShmemIndexOffset = result->location;
-       result->size = SHMEM_INDEX_SIZE;
+   result->location = MAKE_OFFSET(ShmemIndex->hctl);
+   result->size = SHMEM_INDEX_SIZE;
 
-       ShmemBootstrap = FALSE;
+   ShmemBootstrap = false;
 
-   }
-   else
-       Assert(!ShmemBootstrap);
-   /* now release the lock acquired in ShmemHashInit */
+   /* now release the lock acquired in ShmemInitStruct */
    SpinRelease(ShmemIndexLock);
 
-   Assert(result->location == MAKE_OFFSET(ShmemIndex->hctl));
-
-   return TRUE;
+   /*
+    * Initialize ShmemVariableCache for transaction manager.
+    */
+   ShmemVariableCache = (VariableCache)
+       ShmemAlloc(sizeof(*ShmemVariableCache));
+   memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
 }
 
 /*
- * ShmemAlloc -- allocate max-aligned byte string from shared memory
+ * ShmemAlloc -- allocate max-aligned chunk from shared memory
+ *
+ * Assumes ShmemLock and ShmemSegHdr are initialized.
  *
- * Assumes ShmemLock and ShmemFreeStart are initialized.
  * Returns: real pointer to memory or NULL if we are out
  *     of space.  Has to return a real pointer in order
  *     to be compatible with malloc().
@@ -272,7 +159,7 @@ InitShmem(unsigned int key, unsigned int size)
 void *
 ShmemAlloc(Size size)
 {
-   unsigned long tmpFree;
+   uint32      newFree;
    void       *newSpace;
 
    /*
@@ -280,15 +167,15 @@ ShmemAlloc(Size size)
     */
    size = MAXALIGN(size);
 
-   Assert(*ShmemFreeStart);
+   Assert(ShmemSegHdr);
 
    SpinAcquire(ShmemLock);
 
-   tmpFree = *ShmemFreeStart + size;
-   if (tmpFree <= ShmemSize)
+   newFree = ShmemSegHdr->freeoffset + size;
+   if (newFree <= ShmemSegHdr->totalsize)
    {
-       newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
-       *ShmemFreeStart += size;
+       newSpace = (void *) MAKE_PTR(ShmemSegHdr->freeoffset);
+       ShmemSegHdr->freeoffset = newFree;
    }
    else
        newSpace = NULL;
@@ -306,7 +193,7 @@ ShmemAlloc(Size size)
  *
  * Returns TRUE if the pointer is valid.
  */
-int
+bool
 ShmemIsValid(unsigned long addr)
 {
    return (addr < ShmemEnd) && (addr >= ShmemBase);
@@ -394,16 +281,15 @@ ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr)
    sprintf(item.key, "PID %d", pid);
 
    SpinAcquire(ShmemIndexLock);
+
    result = (ShmemIndexEnt *)
        hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
 
    if (!result)
    {
-
        SpinRelease(ShmemIndexLock);
        elog(ERROR, "ShmemInitPID: ShmemIndex corrupted");
        return FALSE;
-
    }
 
    if (found)
@@ -438,19 +324,19 @@ ShmemPIDDestroy(int pid)
    sprintf(item.key, "PID %d", pid);
 
    SpinAcquire(ShmemIndexLock);
+
    result = (ShmemIndexEnt *)
        hash_search(ShmemIndex, (char *) &item, HASH_REMOVE, &found);
 
    if (found)
        location = result->location;
+
    SpinRelease(ShmemIndexLock);
 
    if (!result)
    {
-
        elog(ERROR, "ShmemPIDDestroy: PID table corrupted");
        return INVALID_OFFSET;
-
    }
 
    if (found)
@@ -487,53 +373,31 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr)
 
    if (!ShmemIndex)
    {
-#ifdef USE_ASSERT_CHECKING
-       char       *strname = "ShmemIndex";
-
-#endif
-
        /*
-        * If the shmem index doesn't exist, we fake it.
+        * If the shmem index doesn't exist, we are bootstrapping: we must
+        * be trying to init the shmem index itself.
         *
-        * If we are creating the first shmem index, then let shmemalloc()
-        * allocate the space for a new HTAB.  Otherwise, find the old one
-        * and return that.  Notice that the ShmemIndexLock is held until
-        * the shmem index has been completely initialized.
+        * Notice that the ShmemIndexLock is held until the shmem index has
+        * been completely initialized.
         */
-       Assert(strcmp(name, strname) == 0);
-       if (ShmemBootstrap)
-       {
-           /* in POSTMASTER/Single process */
-
-           *foundPtr = FALSE;
-           return ShmemAlloc(size);
-       }
-       else
-       {
-           Assert(*ShmemIndexOffset);
-
-           *foundPtr = TRUE;
-           return (void *) MAKE_PTR(*ShmemIndexOffset);
-       }
-
-
-   }
-   else
-   {
-       /* look it up in the shmem index */
-       result = (ShmemIndexEnt *)
-           hash_search(ShmemIndex, (char *) &item, HASH_ENTER, foundPtr);
+       Assert(strcmp(name, "ShmemIndex") == 0);
+       Assert(ShmemBootstrap);
+       *foundPtr = FALSE;
+       return ShmemAlloc(size);
    }
 
+   /* look it up in the shmem index */
+   result = (ShmemIndexEnt *)
+       hash_search(ShmemIndex, (char *) &item, HASH_ENTER, foundPtr);
+
    if (!result)
    {
        SpinRelease(ShmemIndexLock);
-
        elog(ERROR, "ShmemInitStruct: Shmem Index corrupted");
        return NULL;
-
    }
-   else if (*foundPtr)
+
+   if (*foundPtr)
    {
 
        /*
index fb2e4804dd3c23b8f4e865b791947cb11bcb4aab..c87fcd3660292bfb876fdbda63f37cdfcfc0ab85 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.23 2000/11/12 20:51:51 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.24 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 SPINLOCK   SInvalLock = (SPINLOCK) NULL;
 
 /****************************************************************************/
-/* CreateSharedInvalidationState()      Create a buffer segment            */
+/* CreateSharedInvalidationState()      Initialize SI buffer               */
 /*                                                                         */
 /* should be called only by the POSTMASTER                                 */
 /****************************************************************************/
 void
-CreateSharedInvalidationState(IPCKey key, int maxBackends)
+CreateSharedInvalidationState(int maxBackends)
 {
-   int         status;
-
-   /* SInvalLock gets set in spin.c, during spinlock init */
-   status = SISegmentInit(true, IPCKeyGetSIBufferMemoryBlock(key),
-                          maxBackends);
-
-   if (status == -1)
-       elog(FATAL, "CreateSharedInvalidationState: failed segment init");
-}
-
-/****************************************************************************/
-/* AttachSharedInvalidationState(key)   Attach to existing buffer segment  */
-/*                                                                         */
-/* should be called by each backend during startup                         */
-/****************************************************************************/
-void
-AttachSharedInvalidationState(IPCKey key)
-{
-   int         status;
-
-   if (key == PrivateIPCKey)
-   {
-       CreateSharedInvalidationState(key, 16);
-       return;
-   }
-   /* SInvalLock gets set in spin.c, during spinlock init */
-   status = SISegmentInit(false, IPCKeyGetSIBufferMemoryBlock(key), 0);
-
-   if (status == -1)
-       elog(FATAL, "AttachSharedInvalidationState: failed segment init");
+   /* SInvalLock must be initialized already, during spinlock init */
+   SIBufferInit(maxBackends);
 }
 
 /*
- * InitSharedInvalidationState
+ * InitBackendSharedInvalidationState
  *     Initialize new backend's state info in buffer segment.
- *     Must be called after AttachSharedInvalidationState().
  */
 void
-InitSharedInvalidationState(void)
+InitBackendSharedInvalidationState(void)
 {
    SpinAcquire(SInvalLock);
    if (!SIBackendInit(shmInvalBuffer))
index f4b2998343314e6eeb30188171d28074e3077b03..c7612759793fcd6831bcad9440b98d761853426d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.35 2000/11/12 20:51:51 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.36 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 SISeg     *shmInvalBuffer;
 
-static void SISegmentAttach(IpcMemoryId shmid);
-static void SISegInit(SISeg *segP, int maxBackends);
 static void CleanupInvalidationState(int status, Datum arg);
 static void SISetProcStateInvalid(SISeg *segP);
 
-/*
- * SISegmentInit
- *     Create a new SI memory segment, or attach to an existing one
- *
- * This is called with createNewSegment = true by the postmaster (or by
- * a standalone backend), and subsequently with createNewSegment = false
- * by backends started by the postmaster.
- *
- * Note: maxBackends param is only valid when createNewSegment is true
- */
-int
-SISegmentInit(bool createNewSegment, IPCKey key, int maxBackends)
-{
-   int         segSize;
-   IpcMemoryId shmId;
-
-   if (createNewSegment)
-   {
-       /* Kill existing segment, if any */
-       IpcMemoryKill(key);
-
-       /*
-        * Figure space needed. Note sizeof(SISeg) includes the first
-        * ProcState entry.
-        */
-       segSize = sizeof(SISeg) + sizeof(ProcState) * (maxBackends - 1);
-
-       /* Get a shared segment */
-       shmId = IpcMemoryCreate(key, segSize, IPCProtection);
-       if (shmId < 0)
-       {
-           perror("SISegmentInit: segment create failed");
-           return -1;          /* an error */
-       }
-
-       /* Attach to the shared cache invalidation segment */
-       /* sets the global variable shmInvalBuffer */
-       SISegmentAttach(shmId);
-
-       /* Init shared memory contents */
-       SISegInit(shmInvalBuffer, maxBackends);
-   }
-   else
-   {
-       /* find existing segment */
-       shmId = IpcMemoryIdGet(key, 0);
-       if (shmId < 0)
-       {
-           perror("SISegmentInit: segment get failed");
-           return -1;          /* an error */
-       }
-
-       /* Attach to the shared cache invalidation segment */
-       /* sets the global variable shmInvalBuffer */
-       SISegmentAttach(shmId);
-   }
-   return 1;
-}
 
 /*
- * SISegmentAttach
- *     Attach to specified shared memory segment
+ * SInvalShmemSize --- return shared-memory space needed
  */
-static void
-SISegmentAttach(IpcMemoryId shmid)
+int
+SInvalShmemSize(int maxBackends)
 {
-   shmInvalBuffer = (SISeg *) IpcMemoryAttach(shmid);
-
-   if (shmInvalBuffer == IpcMemAttachFailed)
-   {
-       /* XXX use validity function */
-       elog(FATAL, "SISegmentAttach: Could not attach segment: %m");
-   }
+   /*
+    * Figure space needed. Note sizeof(SISeg) includes the first
+    * ProcState entry.
+    */
+   return sizeof(SISeg) + sizeof(ProcState) * (maxBackends - 1);
 }
 
 /*
- * SISegInit
- *     Initialize contents of a new shared memory sinval segment
+ * SIBufferInit
+ *     Create and initialize a new SI message buffer
  */
-static void
-SISegInit(SISeg *segP, int maxBackends)
+void
+SIBufferInit(int maxBackends)
 {
+   int         segSize;
+   SISeg      *segP;
    int         i;
 
+   /* Allocate space in shared memory */
+   segSize = SInvalShmemSize(maxBackends);
+   shmInvalBuffer = segP = (SISeg *) ShmemAlloc(segSize);
+
    /* Clear message counters, save size of procState array */
    segP->minMsgNum = 0;
    segP->maxMsgNum = 0;
index 674ee06a9a34f3959c4123b6adcafa171d26100b..a93ae69e0327f71c7920c8b16d64347f5d0c49f9 100644 (file)
@@ -3,31 +3,24 @@
  * spin.c
  *   routines for managing spin locks
  *
+ * POSTGRES has two kinds of locks: semaphores (which put the
+ * process to sleep) and spinlocks (which are supposed to be
+ * short term locks).  Spinlocks are implemented via test-and-set (TAS)
+ * instructions if possible, else via semaphores.  The semaphore method
+ * is too slow to be useful :-(
+ *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.25 2000/05/31 00:28:29 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.26 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-/*
- * POSTGRES has two kinds of locks: semaphores (which put the
- * process to sleep) and spinlocks (which are supposed to be
- * short term locks).  Currently both are implemented as SysV
- * semaphores, but presumably this can change if we move to
- * a machine with a test-and-set (TAS) instruction.  Its probably
- * a good idea to think about (and allocate) short term and long
- * term semaphores separately anyway.
- *
- * NOTE: These routines are not supposed to be widely used in Postgres.
- *      They are preserved solely for the purpose of porting Mark Sullivan's
- *      buffer manager to Postgres.
- */
-#include 
 #include "postgres.h"
 
+#include 
 #ifndef HAS_TEST_AND_SET
 #include 
 #endif
 #include "storage/proc.h"
 #include "storage/s_lock.h"
 
-
-/* globals used in this file */
-IpcSemaphoreId SpinLockId;
-
-#ifdef HAS_TEST_AND_SET
-/* real spin lock implementations */
-
-void
-CreateSpinlocks(IPCKey key)
-{
-   /* the spin lock shared memory must have been created by now */
-   return;
-}
-
-void
-InitSpinLocks(void)
-{
-   extern SPINLOCK ShmemLock;
-   extern SPINLOCK ShmemIndexLock;
-   extern SPINLOCK BufMgrLock;
-   extern SPINLOCK LockMgrLock;
-   extern SPINLOCK ProcStructLock;
-   extern SPINLOCK SInvalLock;
-   extern SPINLOCK OidGenLockId;
-   extern SPINLOCK XidGenLockId;
-   extern SPINLOCK ControlFileLockId;
+/* Probably should move these to an appropriate header file */
+extern SPINLOCK ShmemLock;
+extern SPINLOCK ShmemIndexLock;
+extern SPINLOCK BufMgrLock;
+extern SPINLOCK LockMgrLock;
+extern SPINLOCK ProcStructLock;
+extern SPINLOCK SInvalLock;
+extern SPINLOCK OidGenLockId;
+extern SPINLOCK XidGenLockId;
+extern SPINLOCK ControlFileLockId;
 
 #ifdef STABLE_MEMORY_STORAGE
-   extern SPINLOCK MMCacheLock;
+extern SPINLOCK MMCacheLock;
 
 #endif
 
-   /* These six spinlocks have fixed location is shmem */
+
+/*
+ * Initialize identifiers for permanent spinlocks during startup
+ *
+ * The same identifiers are used for both TAS and semaphore implementations,
+ * although in one case they are indexes into a shmem array and in the other
+ * they are semaphore numbers.
+ */
+static void
+InitSpinLockIDs(void)
+{
    ShmemLock = (SPINLOCK) SHMEMLOCKID;
    ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
    BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
@@ -81,11 +68,18 @@ InitSpinLocks(void)
 #ifdef STABLE_MEMORY_STORAGE
    MMCacheLock = (SPINLOCK) MMCACHELOCKID;
 #endif
-
-   return;
 }
 
 
+#ifdef HAS_TEST_AND_SET
+
+/* real spin lock implementation */
+
+typedef struct slock
+{
+   slock_t     shlock;
+} SLock;
+
 #ifdef LOCK_DEBUG
 bool Trace_spinlocks = false;
 
@@ -93,193 +87,268 @@ inline static void
 PRINT_SLDEBUG(const char * where, SPINLOCK lockid, const SLock * lock)
 {
     if (Trace_spinlocks)
-        elog(DEBUG,
-             "%s: id=%d (locklock=%d, flag=%d, nshlocks=%d, shlock=%d, exlock=%d)",
-             where, lockid,
-             lock->locklock, lock->flag, lock->nshlocks, lock->shlock, lock->exlock);
+        elog(DEBUG, "%s: id=%d", where, lockid);
 }
 #else  /* not LOCK_DEBUG */
 #define PRINT_SLDEBUG(a,b,c)
 #endif /* not LOCK_DEBUG */
 
 
-/* from ipc.c */
-extern SLock *SLockArray;
+static SLock *SLockArray = NULL;
+
+#define SLOCKMEMORYSIZE        ((int) MAX_SPINS * sizeof(SLock))
+
+/*
+ * SLockShmemSize --- return shared-memory space needed
+ */
+int
+SLockShmemSize(void)
+{
+   return MAXALIGN(SLOCKMEMORYSIZE);
+}
+
+/*
+ * CreateSpinlocks --- create and initialize spinlocks during startup
+ */
+void
+CreateSpinlocks(PGShmemHeader *seghdr)
+{
+   int         id;
+
+   /*
+    * We must allocate the space "by hand" because shmem.c isn't up yet
+    */
+   SLockArray = (SLock *) (((char *) seghdr) + seghdr->freeoffset);
+   seghdr->freeoffset += MAXALIGN(SLOCKMEMORYSIZE);
+   Assert(seghdr->freeoffset <= seghdr->totalsize);
+
+   /*
+    * Initialize all spinlocks to "unlocked" state
+    */
+   for (id = 0; id < (int) MAX_SPINS; id++)
+   {
+       SLock      *slckP = &(SLockArray[id]);
+
+       S_INIT_LOCK(&(slckP->shlock));
+   }
+
+   /*
+    * Assign indexes for fixed spinlocks
+    */
+   InitSpinLockIDs();
+}
 
 void
 SpinAcquire(SPINLOCK lockid)
 {
-   SLock      *slckP;
+   SLock      *slckP = &(SLockArray[lockid]);
 
-   /* This used to be in ipc.c, but move here to reduce function calls */
-   slckP = &(SLockArray[lockid]);
    PRINT_SLDEBUG("SpinAcquire", lockid, slckP);
-ex_try_again:
-   S_LOCK(&(slckP->locklock));
-   switch (slckP->flag)
-   {
-       case NOLOCK:
-           slckP->flag = EXCLUSIVELOCK;
-           S_LOCK(&(slckP->exlock));
-           S_LOCK(&(slckP->shlock));
-           S_UNLOCK(&(slckP->locklock));
-            PRINT_SLDEBUG("OUT", lockid, slckP);
-           break;
-       case SHAREDLOCK:
-       case EXCLUSIVELOCK:
-           S_UNLOCK(&(slckP->locklock));
-           S_LOCK(&(slckP->exlock));
-           S_UNLOCK(&(slckP->exlock));
-           goto ex_try_again;
-   }
+   S_LOCK(&(slckP->shlock));
    PROC_INCR_SLOCK(lockid);
-    PRINT_SLDEBUG("SpinAcquire/success", lockid, slckP);
+    PRINT_SLDEBUG("SpinAcquire/done", lockid, slckP);
 }
 
 void
 SpinRelease(SPINLOCK lockid)
 {
-   SLock      *slckP;
-
-   /* This used to be in ipc.c, but move here to reduce function calls */
-   slckP = &(SLockArray[lockid]);
+   SLock      *slckP = &(SLockArray[lockid]);
 
    /*
     * Check that we are actually holding the lock we are releasing. This
     * can be done only after MyProc has been initialized.
     */
     Assert(!MyProc || MyProc->sLocks[lockid] > 0);
-   Assert(slckP->flag != NOLOCK);
-
 
    PROC_DECR_SLOCK(lockid);
     PRINT_SLDEBUG("SpinRelease", lockid, slckP);
-   S_LOCK(&(slckP->locklock));
-   /* -------------
-    *  give favor to read processes
-    * -------------
+   S_UNLOCK(&(slckP->shlock));
+    PRINT_SLDEBUG("SpinRelease/done", lockid, slckP);
+}
+
+#else /* !HAS_TEST_AND_SET */
+
+/*
+ * No TAS, so spinlocks are implemented using SysV semaphores.
+ *
+ * We support two slightly different APIs here: SpinAcquire/SpinRelease
+ * work with SPINLOCK integer indexes for the permanent spinlocks, which
+ * are all assumed to live in the first spinlock semaphore set.  There
+ * is also an emulation of the s_lock.h TAS-spinlock macros; for that case,
+ * typedef slock_t stores the semId and sem number of the sema to use.
+ * The semas needed are created by CreateSpinlocks and doled out by
+ * s_init_lock_sema.
+ *
+ * Since many systems have a rather small SEMMSL limit on semas per set,
+ * we allocate the semaphores required in sets of SPINLOCKS_PER_SET semas.
+ * This value is deliberately made equal to PROC_NSEMS_PER_SET so that all
+ * sema sets allocated by Postgres will be the same size; that eases the
+ * semaphore-recycling logic in IpcSemaphoreCreate().
+ *
+ * Note that the SpinLockIds array is not in shared memory; it is filled
+ * by the postmaster and then inherited through fork() by backends.  This
+ * is OK because its contents do not change after system startup.
+ */
+
+#define SPINLOCKS_PER_SET  PROC_NSEMS_PER_SET
+
+static IpcSemaphoreId *SpinLockIds = NULL;
+
+static int numSpinSets = 0;        /* number of sema sets used */
+static int numSpinLocks = 0;   /* total number of semas allocated */
+static int nextSpinLock = 0;   /* next free spinlock index */
+
+static void SpinFreeAllSemaphores(void);
+
+/*
+ * SLockShmemSize --- return shared-memory space needed
+ */
+int
+SLockShmemSize(void)
+{
+   return 0;
+}
+
+/*
+ * CreateSpinlocks --- create and initialize spinlocks during startup
+ */
+void
+CreateSpinlocks(PGShmemHeader *seghdr)
+{
+   int     i;
+
+   if (SpinLockIds == NULL)
+   {
+       /*
+        * Compute number of spinlocks needed.  If this logic gets any more
+        * complicated, it should be distributed into the affected modules,
+        * similar to the way shmem space estimation is handled.
+        *
+        * For now, though, we just need the fixed spinlocks (MAX_SPINS),
+        * two spinlocks per shared disk buffer, and four spinlocks for XLOG.
+        */
+       numSpinLocks = (int) MAX_SPINS + 2 * NBuffers + 4;
+
+       /* might as well round up to a multiple of SPINLOCKS_PER_SET */
+       numSpinSets = (numSpinLocks - 1) / SPINLOCKS_PER_SET + 1;
+       numSpinLocks = numSpinSets * SPINLOCKS_PER_SET;
+
+       SpinLockIds = (IpcSemaphoreId *)
+           malloc(numSpinSets * sizeof(IpcSemaphoreId));
+       Assert(SpinLockIds != NULL);
+   }
+
+   for (i = 0; i < numSpinSets; i++)
+       SpinLockIds[i] = -1;
+
+   /*
+    * Arrange to delete semas on exit --- set this up now so that we
+    * will clean up if allocation fails.  We use our own freeproc,
+    * rather than IpcSemaphoreCreate's removeOnExit option, because
+    * we don't want to fill up the on_shmem_exit list with a separate
+    * entry for each semaphore set.
     */
-   slckP->flag = NOLOCK;
-   if (slckP->nshlocks > 0)
+   on_shmem_exit(SpinFreeAllSemaphores, 0);
+
+   /* Create sema sets and set all semas to count 1 */
+   for (i = 0; i < numSpinSets; i++)
    {
-       while (slckP->nshlocks > 0)
-       {
-           S_UNLOCK(&(slckP->shlock));
-           S_LOCK(&(slckP->comlock));
-       }
-       S_UNLOCK(&(slckP->shlock));
+       SpinLockIds[i] = IpcSemaphoreCreate(SPINLOCKS_PER_SET,
+                                           IPCProtection,
+                                           1,
+                                           false);
    }
-   else
-       S_UNLOCK(&(slckP->shlock));
-   S_UNLOCK(&(slckP->exlock));
-   S_UNLOCK(&(slckP->locklock));
-    PRINT_SLDEBUG("SpinRelease/released", lockid, slckP);
+
+   /*
+    * Assign indexes for fixed spinlocks
+    */
+   Assert(MAX_SPINS <= SPINLOCKS_PER_SET);
+   InitSpinLockIDs();
+
+   /* Init counter for allocating dynamic spinlocks */
+   nextSpinLock = MAX_SPINS;
 }
 
-#else /* !HAS_TEST_AND_SET */
-/* Spinlocks are implemented using SysV semaphores */
+/*
+ * SpinFreeAllSemaphores -
+ *   called at shmem_exit time, ie when exiting the postmaster or
+ *   destroying shared state for a failed set of backends.
+ *   Free up all the semaphores allocated for spinlocks.
+ */
+static void
+SpinFreeAllSemaphores(void)
+{
+   int         i;
 
-static bool AttachSpinLocks(IPCKey key);
-static bool SpinIsLocked(SPINLOCK lock);
+   for (i = 0; i < numSpinSets; i++)
+   {
+       if (SpinLockIds[i] >= 0)
+           IpcSemaphoreKill(SpinLockIds[i]);
+   }
+}
 
 /*
- * SpinAcquire -- try to grab a spinlock
+ * SpinAcquire -- grab a fixed spinlock
  *
  * FAILS if the semaphore is corrupted.
  */
 void
 SpinAcquire(SPINLOCK lock)
 {
-   IpcSemaphoreLock(SpinLockId, lock, IpcExclusiveLock);
+   IpcSemaphoreLock(SpinLockIds[0], lock);
    PROC_INCR_SLOCK(lock);
 }
 
 /*
- * SpinRelease -- release a spin lock
+ * SpinRelease -- release a fixed spin lock
  *
  * FAILS if the semaphore is corrupted
  */
 void
 SpinRelease(SPINLOCK lock)
 {
-   Assert(SpinIsLocked(lock));
-   PROC_DECR_SLOCK(lock);
-   IpcSemaphoreUnlock(SpinLockId, lock, IpcExclusiveLock);
-}
-
-static bool
-SpinIsLocked(SPINLOCK lock)
-{
+#ifdef USE_ASSERT_CHECKING
+   /* Check it's locked */
    int         semval;
 
-   semval = IpcSemaphoreGetValue(SpinLockId, lock);
-   return semval < IpcSemaphoreDefaultStartValue;
+   semval = IpcSemaphoreGetValue(SpinLockIds[0], lock);
+   Assert(semval < 1);
+#endif
+   PROC_DECR_SLOCK(lock);
+   IpcSemaphoreUnlock(SpinLockIds[0], lock);
 }
 
 /*
- * CreateSpinlocks -- Create a sysV semaphore array for
- *     the spinlocks
- *
+ * s_lock.h hardware-spinlock emulation
  */
+
 void
-CreateSpinlocks(IPCKey key)
+s_init_lock_sema(volatile slock_t *lock)
 {
-
-   SpinLockId = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
-                                   IpcSemaphoreDefaultStartValue, 1);
-
-   if (SpinLockId <= 0)
-       elog(STOP, "CreateSpinlocks: cannot create spin locks");
-
-   return;
+   if (nextSpinLock >= numSpinLocks)
+       elog(FATAL, "s_init_lock_sema: not enough semaphores");
+   lock->semId = SpinLockIds[nextSpinLock / SPINLOCKS_PER_SET];
+   lock->sem = nextSpinLock % SPINLOCKS_PER_SET;
+   nextSpinLock++;
 }
 
-/*
- * InitSpinLocks -- Spinlock bootstrapping
- *
- * We need several spinlocks for bootstrapping:
- * ShmemIndexLock (for the shmem index table) and
- * ShmemLock (for the shmem allocator), BufMgrLock (for buffer
- * pool exclusive access), LockMgrLock (for the lock table), and
- * ProcStructLock (a spin lock for the shared process structure).
- * If there's a Sony WORM drive attached, we also have a spinlock
- * (SJCacheLock) for it.  Same story for the main memory storage mgr.
- *
- */
 void
-InitSpinLocks(void)
+s_unlock_sema(volatile slock_t *lock)
 {
-   extern SPINLOCK ShmemLock;
-   extern SPINLOCK ShmemIndexLock;
-   extern SPINLOCK BufMgrLock;
-   extern SPINLOCK LockMgrLock;
-   extern SPINLOCK ProcStructLock;
-   extern SPINLOCK SInvalLock;
-   extern SPINLOCK OidGenLockId;
-   extern SPINLOCK XidGenLockId;
-   extern SPINLOCK ControlFileLockId;
-
-#ifdef STABLE_MEMORY_STORAGE
-   extern SPINLOCK MMCacheLock;
-
-#endif
-
-   /* These five (or six) spinlocks have fixed location is shmem */
-   ShmemLock = (SPINLOCK) SHMEMLOCKID;
-   ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
-   BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
-   LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
-   ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
-   SInvalLock = (SPINLOCK) SINVALLOCKID;
-   OidGenLockId = (SPINLOCK) OIDGENLOCKID;
-   XidGenLockId = (SPINLOCK) XIDGENLOCKID;
-   ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
+   IpcSemaphoreUnlock(lock->semId, lock->sem);
+}
 
-#ifdef STABLE_MEMORY_STORAGE
-   MMCacheLock = (SPINLOCK) MMCACHELOCKID;
-#endif
+bool
+s_lock_free_sema(volatile slock_t *lock)
+{
+   return IpcSemaphoreGetValue(lock->semId, lock->sem) > 0;
+}
 
-   return;
+int
+tas_sema(volatile slock_t *lock)
+{
+   /* Note that TAS macros return 0 if *success* */
+   return ! IpcSemaphoreTryLock(lock->semId, lock->sem);
 }
 
 #endif /* !HAS_TEST_AND_SET */
index 14325e53183d7f91bd7d04c6c9be7d2f1d233680..cf99be3b11500ede5e97e354b75552712acc5de5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.72 2000/11/08 22:10:00 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.73 2000/11/28 23:27:56 tgl Exp $
  *
  * NOTES
  *   Outside modules can create a lock table and acquire/release
@@ -56,6 +56,7 @@ static char *lock_types[] =
    "AccessExclusiveLock"
 };
 
+static char *DeadLockMessage = "Deadlock detected.\n\tSee the lock(l) manual page for a possible cause.";
 
 
 #ifdef LOCK_DEBUG
@@ -943,8 +944,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
                  lock) != NO_ERROR)
    {
        /* -------------------
-        * This could have happend as a result of a deadlock,
-        * see HandleDeadLock().
+        * We failed as a result of a deadlock, see HandleDeadLock().
         * Decrement the lock nHolding and holders fields as
         * we are no longer waiting on this lock.
         * -------------------
@@ -957,8 +957,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
        if (lock->activeHolders[lockmode] == lock->holders[lockmode])
            lock->waitMask &= BITS_OFF[lockmode];
        SpinRelease(lockMethodTable->ctl->masterLock);
-       elog(ERROR, "WaitOnLock: error on wakeup - Aborting this transaction");
-
+       elog(ERROR, DeadLockMessage);
        /* not reached */
    }
 
index 2da1495cd3b5416a164a5dd6dda444af67d62567..0193a7ad2e73746f200a1aa8afa8a713b86897b5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.83 2000/10/07 14:39:13 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.84 2000/11/28 23:27:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,7 @@
  *     This is so that we can support more backends. (system-wide semaphore
  *     sets run out pretty fast.)                -ay 4/95
  *
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.83 2000/10/07 14:39:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.84 2000/11/28 23:27:56 tgl Exp $
  */
 #include "postgres.h"
 
@@ -91,10 +91,8 @@ static PROC_HDR *ProcGlobal = NULL;
 PROC      *MyProc = NULL;
 
 static void ProcKill(int exitStatus, Datum pid);
-static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);
-static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
-
-static char *DeadLockMessage = "Deadlock detected -- See the lock(l) manual page for a possible cause.";
+static void ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum);
+static void ProcFreeSem(IpcSemaphoreId semId, int semNum);
 
 /*
  * InitProcGlobal -
@@ -116,7 +114,7 @@ static char *DeadLockMessage = "Deadlock detected -- See the lock(l) manual page
  *   rather than later.
  */
 void
-InitProcGlobal(IPCKey key, int maxBackends)
+InitProcGlobal(int maxBackends)
 {
    bool        found = false;
 
@@ -135,39 +133,35 @@ InitProcGlobal(IPCKey key, int maxBackends)
        int         i;
 
        ProcGlobal->freeProcs = INVALID_OFFSET;
-       ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
-       for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+       for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
+       {
+           ProcGlobal->procSemIds[i] = -1;
            ProcGlobal->freeSemMap[i] = 0;
+       }
 
        /*
         * Arrange to delete semas on exit --- set this up now so that we
-        * will clean up if pre-allocation fails...
+        * will clean up if pre-allocation fails.  We use our own freeproc,
+        * rather than IpcSemaphoreCreate's removeOnExit option, because
+        * we don't want to fill up the on_shmem_exit list with a separate
+        * entry for each semaphore set.
         */
        on_shmem_exit(ProcFreeAllSemaphores, 0);
 
        /*
-        * Pre-create the semaphores for the first maxBackends processes,
-        * unless we are running as a standalone backend.
+        * Pre-create the semaphores for the first maxBackends processes.
         */
-       if (key != PrivateIPCKey)
+       Assert(maxBackends > 0 && maxBackends <= MAXBACKENDS);
+
+       for (i = 0; i < ((maxBackends-1)/PROC_NSEMS_PER_SET+1); i++)
        {
-           for (i = 0;
-                i < (maxBackends + PROC_NSEMS_PER_SET - 1) / PROC_NSEMS_PER_SET;
-                i++)
-           {
-               IPCKey      semKey = ProcGlobal->currKey + i;
-               int         semId;
-
-               semId = IpcSemaphoreCreate(semKey,
-                                          PROC_NSEMS_PER_SET,
-                                          IPCProtection,
-                                          IpcSemaphoreDefaultStartValue,
-                                          0);
-               if (semId < 0)
-                   elog(FATAL, "InitProcGlobal: IpcSemaphoreCreate failed");
-               /* mark this sema set allocated */
-               ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET);
-           }
+           IpcSemaphoreId      semId;
+
+           semId = IpcSemaphoreCreate(PROC_NSEMS_PER_SET,
+                                      IPCProtection,
+                                      1,
+                                      false);
+           ProcGlobal->procSemIds[i] = semId;
        }
    }
 }
@@ -178,7 +172,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
  * ------------------------
  */
 void
-InitProcess(IPCKey key)
+InitProcess(void)
 {
    bool        found = false;
    unsigned long location,
@@ -186,7 +180,7 @@ InitProcess(IPCKey key)
 
    SpinAcquire(ProcStructLock);
 
-   /* attach to the free list */
+   /* attach to the ProcGlobal structure */
    ProcGlobal = (PROC_HDR *)
        ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
    if (!found)
@@ -199,10 +193,9 @@ InitProcess(IPCKey key)
    {
        SpinRelease(ProcStructLock);
        elog(ERROR, "ProcInit: you already exist");
-       return;
    }
 
-   /* try to get a proc from the free list first */
+   /* try to get a proc struct from the free list first */
 
    myOffset = ProcGlobal->freeProcs;
 
@@ -243,36 +236,22 @@ InitProcess(IPCKey key)
 
    if (IsUnderPostmaster)
    {
-       IPCKey      semKey;
-       int         semNum;
-       int         semId;
-       union semun semun;
-
-       ProcGetNewSemKeyAndNum(&semKey, &semNum);
+       IpcSemaphoreId  semId;
+       int             semNum;
+       union semun     semun;
 
-       /*
-        * Note: because of the pre-allocation done in InitProcGlobal,
-        * this call should always attach to an existing semaphore. It
-        * will (try to) create a new group of semaphores only if the
-        * postmaster tries to start more backends than it said it would.
-        */
-       semId = IpcSemaphoreCreate(semKey,
-                                  PROC_NSEMS_PER_SET,
-                                  IPCProtection,
-                                  IpcSemaphoreDefaultStartValue,
-                                  0);
+       ProcGetNewSemIdAndNum(&semId, &semNum);
 
        /*
         * we might be reusing a semaphore that belongs to a dead backend.
         * So be careful and reinitialize its value here.
         */
-       semun.val = IpcSemaphoreDefaultStartValue;
+       semun.val = 1;
        semctl(semId, semNum, SETVAL, semun);
 
-       IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
+       IpcSemaphoreLock(semId, semNum);
        MyProc->sem.semId = semId;
        MyProc->sem.semNum = semNum;
-       MyProc->sem.semKey = semKey;
    }
    else
        MyProc->sem.semId = -1;
@@ -304,7 +283,7 @@ InitProcess(IPCKey key)
     */
    location = MAKE_OFFSET(MyProc);
    if ((!ShmemPIDLookup(MyProcPid, &location)) || (location != MAKE_OFFSET(MyProc)))
-       elog(STOP, "InitProc: ShmemPID table broken");
+       elog(STOP, "InitProcess: ShmemPID table broken");
 
    MyProc->errType = NO_ERROR;
    SHMQueueElemInit(&(MyProc->links));
@@ -363,10 +342,7 @@ ProcReleaseLocks()
 /*
  * ProcRemove -
  *   used by the postmaster to clean up the global tables. This also frees
- *   up the semaphore used for the lmgr of the process. (We have to do
- *   this is the postmaster instead of doing a IpcSemaphoreKill on exiting
- *   the process because the semaphore set is shared among backends and
- *   we don't want to remove other's semaphores on exit.)
+ *   up the semaphore used for the lmgr of the process.
  */
 bool
 ProcRemove(int pid)
@@ -383,7 +359,7 @@ ProcRemove(int pid)
 
    SpinAcquire(ProcStructLock);
 
-   ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
+   ProcFreeSem(proc->sem.semId, proc->sem.semNum);
 
    proc->links.next = ProcGlobal->freeProcs;
    ProcGlobal->freeProcs = MAKE_OFFSET(proc);
@@ -490,6 +466,7 @@ ProcQueueInit(PROC_QUEUE *queue)
  *
  */
 static bool lockWaiting = false;
+
 void
 SetWaitingForLock(bool waiting)
 {
@@ -514,12 +491,12 @@ SetWaitingForLock(bool waiting)
        }
    }
 }
+
 void
 LockWaitCancel(void)
 {
-/* BeOS doesn't have setitimer, but has set_alarm */
 #ifndef __BEOS__   
-struct itimerval timeval,
+   struct itimerval timeval,
                dummy;
 
    if (!lockWaiting)
@@ -529,6 +506,7 @@ struct itimerval timeval,
    MemSet(&timeval, 0, sizeof(struct itimerval));
    setitimer(ITIMER_REAL, &timeval, &dummy);
 #else
+   /* BeOS doesn't have setitimer, but has set_alarm */
    if (!lockWaiting)
        return;
    lockWaiting = false;
@@ -547,6 +525,8 @@ struct itimerval timeval,
  * semaphore is cleared by default, so the first time we try
  * to acquire it, we sleep.
  *
+ * Result is NO_ERROR if we acquired the lock, STATUS_ERROR if not (deadlock).
+ *
  * ASSUME: that no one will fiddle with the queue until after
  *     we release the spin lock.
  *
@@ -566,7 +546,6 @@ ProcSleep(PROC_QUEUE *waitQueue,/* lock->waitProcs */
    int         aheadHolders[MAX_LOCKMODES];
    bool        selfConflict = (lockctl->conflictTab[token] & myMask),
                prevSame = false;
-   bool        deadlock_checked = false;
 #ifndef __BEOS__
    struct itimerval timeval,
                dummy;
@@ -595,8 +574,8 @@ ProcSleep(PROC_QUEUE *waitQueue,/* lock->waitProcs */
            /* is he waiting for me ? */
            if (lockctl->conflictTab[proc->token] & MyProc->holdLock)
            {
+               /* Yes, report deadlock failure */
                MyProc->errType = STATUS_ERROR;
-               elog(NOTICE, DeadLockMessage);
                goto rt;
            }
            /* being waiting for him - go past */
@@ -642,10 +621,16 @@ ins:;
    lock->waitMask |= myMask;
    SpinRelease(spinlock);
 
+   MyProc->errType = NO_ERROR;     /* initialize result for success */
+
    /* --------------
-    * We set this so we can wake up periodically and check for a deadlock.
-    * If a deadlock is detected, the handler releases the processes
-    * semaphore and aborts the current transaction.
+    * Set timer so we can wake up after awhile and check for a deadlock.
+    * If a deadlock is detected, the handler releases the process's
+    * semaphore and sets MyProc->errType = STATUS_ERROR, allowing us to
+    * know that we must report failure rather than success.
+    *
+    * By delaying the check until we've waited for a bit, we can avoid
+    * running the rather expensive deadlock-check code in most cases.
     *
     * Need to zero out struct to set the interval and the micro seconds fields
     * to 0.
@@ -655,49 +640,42 @@ ins:;
    MemSet(&timeval, 0, sizeof(struct itimerval));
    timeval.it_value.tv_sec = DeadlockTimeout / 1000;
    timeval.it_value.tv_usec = (DeadlockTimeout % 1000) * 1000;
+   if (setitimer(ITIMER_REAL, &timeval, &dummy))
+       elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
 #else
-    /* usecs */
-    time_interval = DeadlockTimeout * 1000000;
+    time_interval = DeadlockTimeout * 1000000; /* usecs */
+   if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
+       elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
 #endif
 
    SetWaitingForLock(true);
-   do
-   {
-       MyProc->errType = NO_ERROR;     /* reset flag after deadlock check */
 
-       if (!deadlock_checked)
-#ifndef __BEOS__
-           if (setitimer(ITIMER_REAL, &timeval, &dummy))
-#else
-            if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
-#endif
-               elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
-       deadlock_checked = true;
-
-       /* --------------
-        * if someone wakes us between SpinRelease and IpcSemaphoreLock,
-        * IpcSemaphoreLock will not block.  The wakeup is "saved" by
-        * the semaphore implementation.
-        * --------------
-        */
-       IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum,
-                        IpcExclusiveLock);
-   } while (MyProc->errType == STATUS_NOT_FOUND);      /* sleep after deadlock
-                                                        * check */
+   /* --------------
+    * If someone wakes us between SpinRelease and IpcSemaphoreLock,
+    * IpcSemaphoreLock will not block.  The wakeup is "saved" by
+    * the semaphore implementation.  Note also that if HandleDeadLock
+    * is invoked but does not detect a deadlock, IpcSemaphoreLock()
+    * will continue to wait.  There used to be a loop here, but it
+    * was useless code...
+    * --------------
+    */
+   IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum);
+
    lockWaiting = false;
 
    /* ---------------
-    * We were awoken before a timeout - now disable the timer
+    * Disable the timer, if it's still running
     * ---------------
     */
 #ifndef __BEOS__
    timeval.it_value.tv_sec = 0;
    timeval.it_value.tv_usec = 0;
    if (setitimer(ITIMER_REAL, &timeval, &dummy))
+       elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
 #else
     if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
+       elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
 #endif
-       elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
 
    /* ----------------
     * We were assumed to be in a critical section when we went
@@ -742,7 +720,7 @@ ProcWakeup(PROC *proc, int errType)
 
    proc->errType = errType;
 
-   IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
+   IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum);
 
    return retProc;
 }
@@ -855,27 +833,11 @@ HandleDeadLock(SIGNAL_ARGS)
     * Before we are awoken the process releasing the lock grants it to
     * us so we know that we don't have to wait anymore.
     *
-    * Damn these names are LONG! -mer
+    * We check by looking to see if we've been unlinked from the wait queue.
+    * This is quicker than checking our semaphore's state, since no kernel
+    * call is needed, and it is safe because we hold the locktable lock.
     * ---------------------
     */
-   if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
-       IpcSemaphoreDefaultStartValue)
-   {
-       UnlockLockTable();
-       return;
-   }
-
-   /*
-    * you would think this would be unnecessary, but...
-    *
-    * this also means we've been removed already.  in some ports (e.g.,
-    * sparc and aix) the semop(2) implementation is such that we can
-    * actually end up in this handler after someone has removed us from
-    * the queue and bopped the semaphore *but the test above fails to
-    * detect the semaphore update* (presumably something weird having to
-    * do with the order in which the semaphore wakeup signal and SIGALRM
-    * get handled).
-    */
    if (MyProc->links.prev == INVALID_OFFSET ||
        MyProc->links.next == INVALID_OFFSET)
    {
@@ -888,19 +850,18 @@ HandleDeadLock(SIGNAL_ARGS)
         DumpAllLocks();
 #endif
 
-   MyProc->errType = STATUS_NOT_FOUND;
    if (!DeadLockCheck(MyProc, MyProc->waitLock))
    {
+       /* No deadlock, so keep waiting */
        UnlockLockTable();
        return;
    }
 
-   mywaitlock = MyProc->waitLock;
-
    /* ------------------------
     * Get this process off the lock's wait queue
     * ------------------------
     */
+   mywaitlock = MyProc->waitLock;
    Assert(mywaitlock->waitProcs.size > 0);
    lockWaiting = false;
    --mywaitlock->waitProcs.size;
@@ -908,12 +869,10 @@ HandleDeadLock(SIGNAL_ARGS)
    SHMQueueElemInit(&(MyProc->links));
 
    /* ------------------
-    * Unlock my semaphore so that the count is right for next time.
-    * I was awoken by a signal, not by someone unlocking my semaphore.
+    * Unlock my semaphore so that the interrupted ProcSleep() call can finish.
     * ------------------
     */
-   IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum,
-                      IpcExclusiveLock);
+   IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum);
 
    /* -------------
     * Set MyProc->errType to STATUS_ERROR so that we abort after
@@ -928,9 +887,6 @@ HandleDeadLock(SIGNAL_ARGS)
     * conditions.  i don't claim to understand this...
     */
    UnlockLockTable();
-
-   elog(NOTICE, DeadLockMessage);
-   return;
 }
 
 void
@@ -959,31 +915,32 @@ ProcReleaseSpins(PROC *proc)
  *****************************************************************************/
 
 /*
- * ProcGetNewSemKeyAndNum -
+ * ProcGetNewSemIdAndNum -
  *   scan the free semaphore bitmap and allocate a single semaphore from
- *   a semaphore set. (If the semaphore set doesn't exist yet,
- *   IpcSemaphoreCreate will create it. Otherwise, we use the existing
- *   semaphore set.)
+ *   a semaphore set.
  */
 static void
-ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
+ProcGetNewSemIdAndNum(IpcSemaphoreId *semId, int *semNum)
 {
    int         i;
+   IpcSemaphoreId *procSemIds = ProcGlobal->procSemIds;
    int32      *freeSemMap = ProcGlobal->freeSemMap;
-   int32       fullmask = (1 << (PROC_NSEMS_PER_SET + 1)) - 1;
+   int32       fullmask = (1 << PROC_NSEMS_PER_SET) - 1;
 
    /*
     * we hold ProcStructLock when entering this routine. We scan through
     * the bitmap to look for a free semaphore.
     */
 
-   for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+   for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
    {
        int         mask = 1;
        int         j;
 
        if (freeSemMap[i] == fullmask)
            continue;           /* this set is fully allocated */
+       if (procSemIds[i] < 0)
+           continue;           /* this set hasn't been initialized */
 
        for (j = 0; j < PROC_NSEMS_PER_SET; j++)
        {
@@ -991,12 +948,11 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
            {
 
                /*
-                * a free semaphore found. Mark it as allocated. Also set
-                * the bit indicating whole set is allocated.
+                * a free semaphore found. Mark it as allocated.
                 */
-               freeSemMap[i] |= mask + (1 << PROC_NSEMS_PER_SET);
+               freeSemMap[i] |= mask;
 
-               *key = ProcGlobal->currKey + i;
+               *semId = procSemIds[i];
                *semNum = j;
                return;
            }
@@ -1005,7 +961,7 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
    }
 
    /* if we reach here, all the semaphores are in use. */
-   elog(ERROR, "InitProc: cannot allocate a free semaphore");
+   elog(ERROR, "ProcGetNewSemIdAndNum: cannot allocate a free semaphore");
 }
 
 /*
@@ -1013,23 +969,22 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
  *   free up our semaphore in the semaphore set.
  */
 static void
-ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
+ProcFreeSem(IpcSemaphoreId semId, int semNum)
 {
-   int         mask;
+   int32       mask;
    int         i;
-   int32      *freeSemMap = ProcGlobal->freeSemMap;
 
-   i = semKey - ProcGlobal->currKey;
    mask = ~(1 << semNum);
-   freeSemMap[i] &= mask;
 
-   /*
-    * Formerly we'd release a semaphore set if it was now completely
-    * unused, but now we keep the semaphores to ensure we won't run out
-    * when starting new backends --- cf. InitProcGlobal.  Note that the
-    * PROC_NSEMS_PER_SET+1'st bit of the freeSemMap entry remains set to
-    * indicate it is still allocated; ProcFreeAllSemaphores() needs that.
-    */
+   for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
+   {
+       if (ProcGlobal->procSemIds[i] == semId)
+       {
+           ProcGlobal->freeSemMap[i] &= mask;
+           return;
+       }
+   }
+   fprintf(stderr, "ProcFreeSem: no ProcGlobal entry for semId %d\n", semId);
 }
 
 /*
@@ -1039,14 +994,13 @@ ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
  *   Free up all the semaphores allocated to the lmgrs of the backends.
  */
 static void
-ProcFreeAllSemaphores()
+ProcFreeAllSemaphores(void)
 {
    int         i;
-   int32      *freeSemMap = ProcGlobal->freeSemMap;
 
-   for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+   for (i = 0; i < PROC_SEM_MAP_ENTRIES; i++)
    {
-       if (freeSemMap[i] != 0)
-           IpcSemaphoreKill(ProcGlobal->currKey + i);
+       if (ProcGlobal->procSemIds[i] >= 0)
+           IpcSemaphoreKill(ProcGlobal->procSemIds[i]);
    }
 }
index bee4f7e9219063ac0870f3617f4f45ceb0a5be76..0454ffc8486a4316c17c4bf99cd66a96a6b03bbf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.72 2000/11/16 22:30:39 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.73 2000/11/28 23:27:57 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -45,7 +45,6 @@
 static void ReverifyMyDatabase(const char *name);
 static void InitCommunication(void);
 
-static IPCKey PostgresIpcKey;
 
 /*** InitPostgres support ***/
 
@@ -141,7 +140,7 @@ ReverifyMyDatabase(const char *name)
  * --------------------------------
  */
 static void
-InitCommunication()
+InitCommunication(void)
 {
    /* ----------------
     *  initialize shared memory and semaphores appropriately.
@@ -151,26 +150,11 @@ InitCommunication()
    {
        /* ----------------
         *  we're running a postgres backend by itself with
-        *  no front end or postmaster.
+        *  no front end or postmaster.  Create private "shmem"
+        *  and semaphores.  Setting MaxBackends = 16 is arbitrary.
         * ----------------
         */
-       char       *ipc_key;    /* value of environment variable */
-       IPCKey      key;
-
-       ipc_key = getenv("IPC_KEY");
-
-       if (!PointerIsValid(ipc_key))
-       {
-           /* Normal standalone backend */
-           key = PrivateIPCKey;
-       }
-       else
-       {
-           /* Allow standalone's IPC key to be set */
-           key = atoi(ipc_key);
-       }
-       PostgresIpcKey = key;
-       AttachSharedMemoryAndSemaphores(key);
+       CreateSharedMemoryAndSemaphores(true, 16);
    }
 }
 
@@ -295,7 +279,7 @@ InitPostgres(const char *dbname, const char *username)
    /*
     * Set up my per-backend PROC struct in shared memory.
     */
-   InitProcess(PostgresIpcKey);
+   InitProcess();
 
    /*
     * Initialize my entry in the shared-invalidation manager's array of
@@ -307,7 +291,7 @@ InitPostgres(const char *dbname, const char *username)
     */
    MyBackendId = InvalidBackendId;
 
-   InitSharedInvalidationState();
+   InitBackendSharedInvalidationState();
 
    if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
        elog(FATAL, "cinit2: bad backend id %d", MyBackendId);
@@ -365,11 +349,11 @@ BaseInit(void)
     */
    InitCommunication();
    DebugFileOpen();
+
    smgrinit();
 
    EnablePortalManager();      /* memory for portal/transaction stuff */
 
    /* initialize the local buffer manager */
    InitLocalBuffer();
-
 }
index fc15e59859b8e9386212c06edb14c432fc5ceb3a..ae41711887848dcddc68d07e588aee8b726e722b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: buf_internals.h,v 1.43 2000/11/08 22:10:02 tgl Exp $
+ * $Id: buf_internals.h,v 1.44 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "storage/buf.h"
 #include "storage/lmgr.h"
+#include "storage/s_lock.h"
 
 /* Buf Mgr constants */
 /* in bufmgr.c */
@@ -100,11 +101,9 @@ typedef struct sbufdesc
    BufFlags    flags;          /* see bit definitions above */
    unsigned    refcount;       /* # of times buffer is pinned */
 
-#ifdef HAS_TEST_AND_SET
-   /* can afford a dedicated lock if test-and-set locks are available */
-   slock_t     io_in_progress_lock;
+   slock_t     io_in_progress_lock; /* to block for I/O to complete */
    slock_t     cntx_lock;      /* to lock access to page context */
-#endif  /* HAS_TEST_AND_SET */
+
    unsigned    r_locks;        /* # of shared locks */
    bool        ri_lock;        /* read-intent lock */
    bool        w_lock;         /* context exclusively locked */
index 22c0ccde7d5c607f25af84dbc0a91498caef9616..275146eea80f6b9e377f80fee094bf3be9934e2e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bufmgr.h,v 1.43 2000/11/08 22:10:02 tgl Exp $
+ * $Id: bufmgr.h,v 1.44 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,7 +154,7 @@ extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
                     BlockNumber blockNum);
 extern int FlushBuffer(Buffer buffer, bool sync, bool release);
 
-extern void InitBufferPool(IPCKey key);
+extern void InitBufferPool(void);
 extern void PrintBufferUsage(FILE *statfp);
 extern void ResetBufferUsage(void);
 extern void ResetBufferPool(bool isCommit);
index eea082a574eb0f1c12a1af875862f3ad73693792..b633297d5f675b25ea65e530b554168d51b4d60b 100644 (file)
@@ -7,14 +7,10 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: ipc.h,v 1.42 2000/10/07 14:39:17 momjian Exp $
- *
- * NOTES
- *   This file is very architecture-specific.  This stuff should actually
- *   be factored into the port/ directories.
+ * $Id: ipc.h,v 1.43 2000/11/28 23:27:57 tgl Exp $
  *
  * Some files that would normally need to include only sys/ipc.h must
- * instead included this file because on Ultrix, sys/ipc.h is not designed
+ * instead include this file because on Ultrix, sys/ipc.h is not designed
  * to be included multiple times.  This file (by virtue of the ifndef IPC_H)
  * is.
  *-------------------------------------------------------------------------
 
 #include 
 #ifdef HAVE_SYS_IPC_H
-#include            /* For IPC_PRIVATE */
+#include 
 #endif /* HAVE_SYS_IPC_H */
 
-#include "config.h"
-
 #ifndef HAVE_UNION_SEMUN
 union semun
 {
@@ -38,79 +32,41 @@ union semun
    struct semid_ds *buf;
    unsigned short *array;
 };
-
 #endif
 
-typedef uint16 SystemPortAddress;
-
-/* semaphore definitions */
+/* generic IPC definitions */
 
 #define IPCProtection  (0600)  /* access/modify by user only */
 
-#define IPC_NMAXSEM        25      /* maximum number of semaphores */
-#define IpcSemaphoreDefaultStartValue  255
-#define IpcSharedLock                                  (-1)
-#define IpcExclusiveLock                         (-255)
-
-#define IpcUnknownStatus       (-1)
-#define IpcInvalidArgument     (-2)
-#define IpcSemIdExist          (-3)
-#define IpcSemIdNotExist       (-4)
-
-typedef uint32 IpcSemaphoreKey; /* semaphore key */
-typedef int IpcSemaphoreId;
-
-/* shared memory definitions */
-
-#define IpcMemCreationFailed   (-1)
-#define IpcMemIdGetFailed      (-2)
-#define IpcMemAttachFailed     0
-
-typedef uint32 IPCKey;
-
-#define PrivateIPCKey  IPC_PRIVATE
-#define DefaultIPCKey  17317
+/* semaphore definitions */
 
-typedef uint32 IpcMemoryKey;   /* shared memory key */
-typedef int IpcMemoryId;
+typedef uint32 IpcSemaphoreKey; /* semaphore key passed to semget(2) */
+typedef int IpcSemaphoreId;        /* semaphore ID returned by semget(2) */
 
+#define IPC_NMAXSEM        32      /* maximum number of semaphores per semID */
 
-/* ipc.c */
-extern bool proc_exit_inprogress;
+#define PGSemaMagic  537       /* must be less than SEMVMX */
 
-extern void proc_exit(int code);
-extern void shmem_exit(int code);
-extern int on_shmem_exit(void (*function) (), Datum arg);
-extern int on_proc_exit(void (*function) (), Datum arg);
-extern void on_exit_reset(void);
+/* shared memory definitions */
 
-extern IpcSemaphoreId IpcSemaphoreCreate(IpcSemaphoreKey semKey,
-                  int semNum, int permission, int semStartValue,
-                  int removeOnExit);
-extern void IpcSemaphoreKill(IpcSemaphoreKey key);
-extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock);
-extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock);
-extern int IpcSemaphoreGetCount(IpcSemaphoreId semId, int sem);
-extern int IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem);
-extern IpcMemoryId IpcMemoryCreate(IpcMemoryKey memKey, uint32 size,
-               int permission);
-extern IpcMemoryId IpcMemoryIdGet(IpcMemoryKey memKey, uint32 size);
-extern char *IpcMemoryAttach(IpcMemoryId memId);
-extern void IpcMemoryKill(IpcMemoryKey memKey);
-extern void CreateAndInitSLockMemory(IPCKey key);
-extern void AttachSLockMemory(IPCKey key);
+typedef uint32 IpcMemoryKey;   /* shared memory key passed to shmget(2) */
+typedef int IpcMemoryId;       /* shared memory ID returned by shmget(2) */
 
+typedef struct                 /* standard header for all Postgres shmem */
+{
+   int32       magic;          /* magic # to identify Postgres segments */
+#define PGShmemMagic  679834892
+   pid_t       creatorPID;     /* PID of creating process */
+   uint32      totalsize;      /* total size of segment */
+   uint32      freeoffset;     /* offset to first free space */
+} PGShmemHeader;
 
-#ifdef HAS_TEST_AND_SET
 
-#define NOLOCK         0
-#define SHAREDLOCK     1
-#define EXCLUSIVELOCK  2
+/* spinlock definitions */
 
 typedef enum _LockId_
 {
    BUFMGRLOCKID,
-   LOCKLOCKID,
    OIDGENLOCKID,
    XIDGENLOCKID,
    CNTLFILELOCKID,
@@ -118,100 +74,40 @@ typedef enum _LockId_
    SHMEMINDEXLOCKID,
    LOCKMGRLOCKID,
    SINVALLOCKID,
-
-#ifdef STABLE_MEMORY_STORAGE
-   MMCACHELOCKID,
-#endif
-
    PROCSTRUCTLOCKID,
-   FIRSTFREELOCKID
-} _LockId_;
-
-#define MAX_SPINS      FIRSTFREELOCKID
-
-typedef struct slock
-{
-   slock_t     locklock;
-   unsigned char flag;
-   short       nshlocks;
-   slock_t     shlock;
-   slock_t     exlock;
-   slock_t     comlock;
-   struct slock *next;
-} SLock;
-
-#else                          /* HAS_TEST_AND_SET */
-
-typedef enum _LockId_
-{
-   SHMEMLOCKID,
-   SHMEMINDEXLOCKID,
-   BUFMGRLOCKID,
-   LOCKMGRLOCKID,
-   SINVALLOCKID,
 
 #ifdef STABLE_MEMORY_STORAGE
    MMCACHELOCKID,
 #endif
 
-   PROCSTRUCTLOCKID,
-   OIDGENLOCKID,
-   XIDGENLOCKID,
-   CNTLFILELOCKID,
-   FIRSTFREELOCKID
+   MAX_SPINS                   /* must be last item! */
 } _LockId_;
 
-#define MAX_SPINS      FIRSTFREELOCKID
 
-#endif  /* HAS_TEST_AND_SET */
+/* ipc.c */
+extern bool proc_exit_inprogress;
 
-/*
- * the following are originally in ipci.h but the prototypes have circular
- * dependencies and most files include both ipci.h and ipc.h anyway, hence
- * combined.
- *
- */
+extern void proc_exit(int code);
+extern void shmem_exit(int code);
+extern void on_proc_exit(void (*function) (), Datum arg);
+extern void on_shmem_exit(void (*function) (), Datum arg);
+extern void on_exit_reset(void);
 
-/*
- * Note:
- *     These must not hash to DefaultIPCKey or PrivateIPCKey.
- */
-#define SystemPortAddressGetIPCKey(address) \
-       (28597 * (address) + 17491)
+extern void IpcInitKeyAssignment(int port);
 
-/*
- * these keys are originally numbered from 1 to 12 consecutively but not
- * all are used. The unused ones are removed.          - ay 4/95.
- */
-#define IPCKeyGetBufferMemoryKey(key) \
-       ((key == PrivateIPCKey) ? key : 1 + (key))
-
-#define IPCKeyGetSIBufferMemoryBlock(key) \
-       ((key == PrivateIPCKey) ? key : 7 + (key))
-
-#define IPCKeyGetSLockSharedMemoryKey(key) \
-       ((key == PrivateIPCKey) ? key : 10 + (key))
-
-#define IPCKeyGetSpinLockSemaphoreKey(key) \
-       ((key == PrivateIPCKey) ? key : 11 + (key))
-#define IPCKeyGetWaitIOSemaphoreKey(key) \
-       ((key == PrivateIPCKey) ? key : 12 + (key))
-#define IPCKeyGetWaitCLSemaphoreKey(key) \
-       ((key == PrivateIPCKey) ? key : 13 + (key))
-
-/* --------------------------
- * NOTE: This macro must always give the highest numbered key as every backend
- * process forked off by the postmaster will be trying to acquire a semaphore
- * with a unique key value starting at key+14 and incrementing up. Each
- * backend uses the current key value then increments it by one.
- * --------------------------
- */
-#define IPCGetProcessSemaphoreInitKey(key) \
-       ((key == PrivateIPCKey) ? key : 14 + (key))
+extern IpcSemaphoreId IpcSemaphoreCreate(int numSems, int permission,
+                                        int semStartValue,
+                                        bool removeOnExit);
+extern void IpcSemaphoreKill(IpcSemaphoreId semId);
+extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem);
+extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem);
+extern bool IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem);
+extern int IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem);
+
+extern PGShmemHeader *IpcMemoryCreate(uint32 size, bool private,
+                                     int permission);
 
 /* ipci.c */
-extern IPCKey SystemPortAddressCreateIPCKey(SystemPortAddress address);
-extern void CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends);
-extern void AttachSharedMemoryAndSemaphores(IPCKey key);
+extern void CreateSharedMemoryAndSemaphores(bool private, int maxBackends);
 
 #endif  /* IPC_H */
index 71a59cb9cc72df16ad5042b60b5b3f9e79c0cc0d..f859dc0762f222adb032d052752f6f5be3d50834 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lmgr.h,v 1.25 2000/06/08 22:37:54 momjian Exp $
+ * $Id: lmgr.h,v 1.26 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,4 @@ extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
 extern void XactLockTableInsert(TransactionId xid);
 extern void XactLockTableWait(TransactionId xid);
 
-/* proc.c */
-extern void InitProcGlobal(IPCKey key, int maxBackends);
-
 #endif  /* LMGR_H */
index edc6359fc43e4e2d8d044e1ca9a6875a988eb17f..41305d80831ddd01b6bf09e31305c65c0e761b15 100644 (file)
@@ -1,13 +1,13 @@
 /*-------------------------------------------------------------------------
  *
  * proc.h
- *
+ *   per-process shared memory data structures
  *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: proc.h,v 1.31 2000/05/31 00:28:38 petere Exp $
+ * $Id: proc.h,v 1.32 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,9 +23,8 @@ extern int DeadlockTimeout;
 typedef struct
 {
    int         sleeplock;
-   int         semNum;
    IpcSemaphoreId semId;
-   IpcSemaphoreKey semKey;
+   int         semNum;
 } SEMA;
 
 /*
@@ -33,7 +32,6 @@ typedef struct
  */
 typedef struct proc
 {
-
    /* proc->links MUST BE THE FIRST ELEMENT OF STRUCT (see ProcWakeup()) */
 
    SHM_QUEUE   links;          /* proc can be waiting for one event(lock) */
@@ -63,34 +61,6 @@ typedef struct proc
                                 * transaction */
 } PROC;
 
-
-/*
- * PROC_NSEMS_PER_SET is the number of semaphores in each sys-V semaphore set
- * we allocate.  It must be *less than* 32 (or however many bits in an int
- * on your machine), or our free-semaphores bitmap won't work.  You also must
- * not set it higher than your kernel's SEMMSL (max semaphores per set)
- * parameter, which is often around 25.
- *
- * MAX_PROC_SEMS is the maximum number of per-process semaphores (those used
- * by the lock mgr) we can keep track of.  It must be a multiple of
- * PROC_NSEMS_PER_SET.
- */
-#define  PROC_NSEMS_PER_SET        16
-#define  MAX_PROC_SEMS         (((MAXBACKENDS-1)/PROC_NSEMS_PER_SET+1)*PROC_NSEMS_PER_SET)
-
-typedef struct procglobal
-{
-   SHMEM_OFFSET freeProcs;
-   IPCKey      currKey;
-   int32       freeSemMap[MAX_PROC_SEMS / PROC_NSEMS_PER_SET];
-
-   /*
-    * In each freeSemMap entry, the PROC_NSEMS_PER_SET least-significant
-    * bits flag whether individual semaphores are in use, and the next
-    * higher bit is set to show that the entire set is allocated.
-    */
-} PROC_HDR;
-
 extern PROC *MyProc;
 
 #define PROC_INCR_SLOCK(lock) \
@@ -115,16 +85,46 @@ do { \
 
 extern SPINLOCK ProcStructLock;
 
+
+/*
+ * There is one ProcGlobal struct for the whole installation.
+ *
+ * PROC_NSEMS_PER_SET is the number of semaphores in each sys-V semaphore set
+ * we allocate.  It must be no more than 32 (or however many bits in an int
+ * on your machine), or our free-semaphores bitmap won't work.  It also must
+ * be *less than* your kernel's SEMMSL (max semaphores per set) parameter,
+ * which is often around 25.  (Less than, because we allocate one extra sema
+ * in each set for identification purposes.)
+ *
+ * PROC_SEM_MAP_ENTRIES is the number of semaphore sets we need to allocate
+ * to keep track of up to MAXBACKENDS backends.
+ */
+#define  PROC_NSEMS_PER_SET        16
+#define  PROC_SEM_MAP_ENTRIES  ((MAXBACKENDS-1)/PROC_NSEMS_PER_SET+1)
+
+typedef struct procglobal
+{
+   /* Head of list of free PROC structures */
+   SHMEM_OFFSET freeProcs;
+
+   /* Info about semaphore sets used for per-process semaphores */
+   IpcSemaphoreId procSemIds[PROC_SEM_MAP_ENTRIES];
+   int32       freeSemMap[PROC_SEM_MAP_ENTRIES];
+
+   /*
+    * In each freeSemMap entry, bit i is set if the i'th semaphore of the
+    * set is allocated to a process.  (i counts from 0 at the LSB)
+    */
+} PROC_HDR;
+
 /*
  * Function Prototypes
  */
-extern void InitProcess(IPCKey key);
+extern void InitProcGlobal(int maxBackends);
+extern void InitProcess(void);
 extern void ProcReleaseLocks(void);
 extern bool ProcRemove(int pid);
 
-/* extern bool ProcKill(int exitStatus, int pid); */
-/* make static in storage/lmgr/proc.c -- jolly */
-
 extern void ProcQueueInit(PROC_QUEUE *queue);
 extern int ProcSleep(PROC_QUEUE *queue, LOCKMETHODCTL *lockctl, int token,
          LOCK *lock);
index 9f0fd7c68e3f703bac3db352e4bc9d8e5f6fd3ba..d50e3564bb7eb0cc9007a13f5b250199883d1eb2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.73 2000/10/22 22:15:03 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.74 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,7 +26,7 @@
  *     void S_LOCK_FREE(slock_t *lock)
  *         Tests if the lock is free. Returns non-zero if free, 0 if locked.
  *
- *     The S_LOCK() macro  implements a primitive but still useful random
+ *     The S_LOCK() macro implements a primitive but still useful random
  *     backoff to avoid hordes of busywaiting lockers chewing CPU.
  *
  *     Effectively:
@@ -64,7 +64,7 @@
  *     manual for POWER in any case.
  *
  */
-#if !defined(S_LOCK_H)
+#ifndef S_LOCK_H
 #define S_LOCK_H
 
 #include "storage/ipc.h"
@@ -403,8 +403,8 @@ extern void s_lock(volatile slock_t *lock, const char *file, const int line);
 
 #define S_LOCK(lock) \
    do { \
-       if (TAS((volatile slock_t *) lock)) \
-           s_lock((volatile slock_t *) lock, __FILE__, __LINE__); \
+       if (TAS((volatile slock_t *) (lock))) \
+           s_lock((volatile slock_t *) (lock), __FILE__, __LINE__); \
    } while (0)
 #endif  /* S_LOCK */
 
@@ -421,12 +421,46 @@ extern void s_lock(volatile slock_t *lock, const char *file, const int line);
 #endif  /* S_INIT_LOCK */
 
 #if !defined(TAS)
-int            tas(volatile slock_t *lock);        /* port/.../tas.s, or
+extern int tas(volatile slock_t *lock);        /* port/.../tas.s, or
                                                 * s_lock.c */
 
-#define TAS(lock)      tas((volatile slock_t *) lock)
+#define TAS(lock)      tas((volatile slock_t *) (lock))
 #endif  /* TAS */
 
+
+#else   /* !HAS_TEST_AND_SET */
+
+/*
+ * Fake spinlock implementation using SysV semaphores --- slow and prone
+ * to fall foul of kernel limits on number of semaphores, so don't use this
+ * unless you must!
+ */
+
+typedef struct
+{
+   /* reference to semaphore used to implement this spinlock */
+   IpcSemaphoreId  semId;
+   int             sem;
+} slock_t;
+
+extern bool s_lock_free_sema(volatile slock_t *lock);
+extern void s_unlock_sema(volatile slock_t *lock);
+extern void s_init_lock_sema(volatile slock_t *lock);
+extern int tas_sema(volatile slock_t *lock);
+
+extern void s_lock(volatile slock_t *lock, const char *file, const int line);
+
+#define S_LOCK(lock) \
+   do { \
+       if (TAS((volatile slock_t *) (lock))) \
+           s_lock((volatile slock_t *) (lock), __FILE__, __LINE__); \
+   } while (0)
+
+#define S_LOCK_FREE(lock)   s_lock_free_sema(lock)
+#define S_UNLOCK(lock)   s_unlock_sema(lock)
+#define S_INIT_LOCK(lock)   s_init_lock_sema(lock)
+#define TAS(lock)   tas_sema(lock)
+
 #endif  /* HAS_TEST_AND_SET */
-#endif  /* S_LOCK_H */
 
+#endif  /* S_LOCK_H */
index 35545f95191fab380f68e6d6e857507df8d2a8ee..8b2cc4487f0aa400e79275a4ec36190e288535ed 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: shmem.h,v 1.23 2000/06/28 03:33:27 tgl Exp $
+ * $Id: shmem.h,v 1.24 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/hsearch.h"
 
 
-/* The shared memory region can start at a different address
+/*
+ * The shared memory region can start at a different address
  * in every process.  Shared memory "pointers" are actually
  * offsets relative to the start of the shared memory region(s).
+ *
+ * In current usage, this is not actually a problem, but we keep
+ * the code that used to handle it...
  */
 typedef unsigned long SHMEM_OFFSET;
 
 #define INVALID_OFFSET (-1)
 #define BAD_LOCATION (-1)
 
-/* start of the lowest shared memory region.  For now, assume that
- * there is only one shared memory region
+/*
+ * Start of the primary shared memory region, in this process' address space.
+ * The macros in this header file can only cope with offsets into this
+ * shared memory region!
  */
 extern SHMEM_OFFSET ShmemBase;
 
@@ -39,14 +45,14 @@ extern SHMEM_OFFSET ShmemBase;
 
 /* coerce a pointer into a shmem offset */
 #define MAKE_OFFSET(xx_ptr)\
-  (SHMEM_OFFSET) (((unsigned long)(xx_ptr))-ShmemBase)
+  ((SHMEM_OFFSET) (((unsigned long)(xx_ptr))-ShmemBase))
 
 #define SHM_PTR_VALID(xx_ptr)\
-  (((unsigned long)xx_ptr) > ShmemBase)
+  (((unsigned long)(xx_ptr)) > ShmemBase)
 
 /* cannot have an offset to ShmemFreeStart (offset 0) */
 #define SHM_OFFSET_VALID(xx_offs)\
-  ((xx_offs != 0) && (xx_offs != INVALID_OFFSET))
+  (((xx_offs) != 0) && ((xx_offs) != INVALID_OFFSET))
 
 
 extern SPINLOCK ShmemLock;
@@ -60,11 +66,9 @@ typedef struct SHM_QUEUE
 } SHM_QUEUE;
 
 /* shmem.c */
-extern void ShmemIndexReset(void);
-extern void ShmemCreate(unsigned int key, unsigned int size);
-extern int InitShmem(unsigned int key, unsigned int size);
+extern void InitShmemAllocation(PGShmemHeader *seghdr);
 extern void *ShmemAlloc(Size size);
-extern int ShmemIsValid(unsigned long addr);
+extern bool ShmemIsValid(unsigned long addr);
 extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
              HASHCTL *infoP, int hash_flags);
 extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
index 4c80f760faa508899d6865a99f7fccdc0e92c257..1cadb54fd246f4201d96c1f83e7197674ee15eae 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: sinval.h,v 1.15 2000/11/12 20:51:52 tgl Exp $
+ * $Id: sinval.h,v 1.16 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,9 +19,9 @@
 
 extern SPINLOCK SInvalLock;
 
-extern void CreateSharedInvalidationState(IPCKey key, int maxBackends);
-extern void AttachSharedInvalidationState(IPCKey key);
-extern void InitSharedInvalidationState(void);
+extern int SInvalShmemSize(int maxBackends);
+extern void CreateSharedInvalidationState(int maxBackends);
+extern void InitBackendSharedInvalidationState(void);
 extern void RegisterSharedInvalid(int cacheId, Index hashIndex,
                      ItemPointer pointer);
 extern void InvalidateSharedInvalid(void (*invalFunction) (),
index b9704d34e4d9753056cbcbf360d43a7de124cb46..c31caf53bf5e7e641233a9afcd851f41fe77e97f 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: sinvaladt.h,v 1.23 2000/11/12 20:51:52 tgl Exp $
+ * $Id: sinvaladt.h,v 1.24 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,15 +107,13 @@ typedef struct SISeg
 } SISeg;
 
 
-extern SISeg *shmInvalBuffer;  /* pointer to the shared buffer segment,
-                                * set by SISegmentAttach() */
+extern SISeg *shmInvalBuffer;  /* pointer to the shared inval buffer */
 
 
 /*
  * prototypes for functions in sinvaladt.c
  */
-extern int SISegmentInit(bool createNewSegment, IPCKey key,
-             int maxBackends);
+extern void SIBufferInit(int maxBackends);
 extern int SIBackendInit(SISeg *segP);
 
 extern bool SIInsertDataEntry(SISeg *segP, SharedInvalidData *data);
index 656e1097a239a5fa5e63acafff0c677af0c64dce..53efabcadb1edab4da5505b17f69fc8f496d9294 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: spin.h,v 1.12 2000/05/31 00:28:38 petere Exp $
+ * $Id: spin.h,v 1.13 2000/11/28 23:27:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * two implementations of spin locks
  *
- * sequent, sparc, sun3: real spin locks. uses a TAS instruction; see
- * src/storage/ipc/s_lock.c for details.
- *
- * default: fake spin locks using semaphores.  see spin.c
+ * Where TAS instruction is available: real spin locks.
+ * See src/storage/ipc/s_lock.c for details.
  *
+ * Otherwise: fake spin locks using semaphores.  see spin.c
  */
 
 typedef int SPINLOCK;
@@ -32,8 +31,10 @@ typedef int SPINLOCK;
 extern bool Trace_spinlocks;
 #endif
 
-extern void CreateSpinlocks(IPCKey key);
-extern void InitSpinLocks(void);
+
+extern int SLockShmemSize(void);
+extern void CreateSpinlocks(PGShmemHeader *seghdr);
+
 extern void SpinAcquire(SPINLOCK lockid);
 extern void SpinRelease(SPINLOCK lockid);