Fix LWLockAssign() so that it can safely be executed after postmaster
authorTom Lane
Fri, 7 Oct 2005 21:42:38 +0000 (21:42 +0000)
committerTom Lane
Fri, 7 Oct 2005 21:42:38 +0000 (21:42 +0000)
initialization.  Add spinlocking, fix EXEC_BACKEND unsafeness.

src/backend/storage/ipc/shmem.c
src/backend/storage/lmgr/lwlock.c

index 76b3ef26cc4d49eabe216f44bdeb8d4c325de411..d7498389b562a7c97dea5e97945d84ad1cd45713 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.85 2005/08/20 23:26:20 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.86 2005/10/07 21:42:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -71,8 +71,7 @@ SHMEM_OFFSET ShmemBase;           /* start address of shared memory */
 
 static SHMEM_OFFSET ShmemEnd;  /* end+1 address of shared memory */
 
-NON_EXEC_STATIC slock_t *ShmemLock;        /* spinlock for shared memory
-                                        * allocation */
+slock_t *ShmemLock;        /* spinlock for shared memory and LWLock allocation */
 
 NON_EXEC_STATIC slock_t *ShmemIndexLock;       /* spinlock for ShmemIndex */
 
index d649e0bd71216166d0fd9ef243e4fb15e77636bf..8b7565a6aa7299957a14ab5cdb685b270758768d 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.31 2005/10/07 20:11:03 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.32 2005/10/07 21:42:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "storage/spin.h"
 
 
+/* We use the ShmemLock spinlock to protect LWLockAssign */
+extern slock_t *ShmemLock;
+
+
 typedef struct LWLock
 {
    slock_t     mutex;          /* Protects LWLock and queue of PGPROCs */
@@ -65,9 +69,6 @@ typedef union LWLockPadded
  */
 NON_EXEC_STATIC LWLockPadded *LWLockArray = NULL;
 
-/* shared counter for dynamic allocation of LWLockIds */
-static int *LWLockCounter;
-
 
 /*
  * We use this structure to keep track of locked LWLocks for release
@@ -159,7 +160,7 @@ LWLockShmemSize(void)
    /* Space for the LWLock array. */
    size = mul_size(numLocks, sizeof(LWLockPadded));
 
-   /* Space for shared allocation counter, plus room for alignment. */
+   /* Space for dynamic allocation counter, plus room for alignment. */
    size = add_size(size, 2 * sizeof(int) + LWLOCK_PADDED_SIZE);
 
    return size;
@@ -175,12 +176,16 @@ CreateLWLocks(void)
    int         numLocks = NumLWLocks();
    Size        spaceLocks = LWLockShmemSize();
    LWLockPadded *lock;
+   int        *LWLockCounter;
    char       *ptr;
    int         id;
 
    /* Allocate space */
    ptr = (char *) ShmemAlloc(spaceLocks);
 
+   /* Leave room for dynamic allocation counter */
+   ptr += 2 * sizeof(int);
+
    /* Ensure desired alignment of LWLock array */
    ptr += LWLOCK_PADDED_SIZE - ((unsigned long) ptr) % LWLOCK_PADDED_SIZE;
 
@@ -200,9 +205,10 @@ CreateLWLocks(void)
    }
 
    /*
-    * Initialize the dynamic-allocation counter at the end of the array
+    * Initialize the dynamic-allocation counter, which is stored just before
+    * the first LWLock.
     */
-   LWLockCounter = (int *) lock;
+   LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
    LWLockCounter[0] = (int) NumFixedLWLocks;
    LWLockCounter[1] = numLocks;
 }
@@ -211,16 +217,27 @@ CreateLWLocks(void)
 /*
  * LWLockAssign - assign a dynamically-allocated LWLock number
  *
- * NB: we do not currently try to interlock this.  Could perhaps use
- * ShmemLock spinlock if there were any need to assign LWLockIds after
- * shmem setup.
+ * We interlock this using the same spinlock that is used to protect
+ * ShmemAlloc().  Interlocking is not really necessary during postmaster
+ * startup, but it is needed if any user-defined code tries to allocate
+ * LWLocks after startup.
  */
 LWLockId
 LWLockAssign(void)
 {
+   LWLockId    result;
+   int        *LWLockCounter;
+
+   LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
+   SpinLockAcquire(ShmemLock);
    if (LWLockCounter[0] >= LWLockCounter[1])
-       elog(FATAL, "no more LWLockIds available");
-   return (LWLockId) (LWLockCounter[0]++);
+   {
+       SpinLockRelease(ShmemLock);
+       elog(ERROR, "no more LWLockIds available");
+   }
+   result = (LWLockId) (LWLockCounter[0]++);
+   SpinLockRelease(ShmemLock);
+   return result;
 }