]> granicus.if.org Git - postgresql/commitdiff
When building with LWLOCK_STATS, initialize the stats in LWLockWaitUntilFree.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 7 Feb 2012 07:38:25 +0000 (09:38 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 7 Feb 2012 08:11:54 +0000 (10:11 +0200)
If LWLockWaitUntilFree was called before the first LWLockAcquire call, you
would either crash because of access to uninitialized array or account the
acquisition incorrectly. LWLockConditionalAcquire doesn't have this problem
because it doesn't update the lwlock stats.

In practice, this never happens because there is no codepath where you would
call LWLockWaitUntilfree before LWLockAcquire after a new process is
launched. But that's just accidental, there's no guarantee that that's
always going to be true in the future.

Spotted by Jeff Janes.

src/backend/storage/lmgr/lwlock.c

index 6511faf985d213c834c341e72d2da7876c1757a6..5d2873100de5130f268edd503040e4804bb44778 100644 (file)
@@ -123,6 +123,22 @@ LOG_LWDEBUG(const char *where, LWLockId lockid, const char *msg)
 
 #ifdef LWLOCK_STATS
 
+static void init_lwlock_stats(void);
+static void print_lwlock_stats(int code, Datum arg);
+
+static void
+init_lwlock_stats(void)
+{
+       int                *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
+       int                     numLocks = LWLockCounter[1];
+
+       sh_acquire_counts = calloc(numLocks, sizeof(int));
+       ex_acquire_counts = calloc(numLocks, sizeof(int));
+       block_counts = calloc(numLocks, sizeof(int));
+       counts_for_pid = MyProcPid;
+       on_shmem_exit(print_lwlock_stats, 0);
+}
+
 static void
 print_lwlock_stats(int code, Datum arg)
 {
@@ -332,16 +348,7 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode)
 #ifdef LWLOCK_STATS
        /* Set up local count state first time through in a given process */
        if (counts_for_pid != MyProcPid)
-       {
-               int                *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
-               int                     numLocks = LWLockCounter[1];
-
-               sh_acquire_counts = calloc(numLocks, sizeof(int));
-               ex_acquire_counts = calloc(numLocks, sizeof(int));
-               block_counts = calloc(numLocks, sizeof(int));
-               counts_for_pid = MyProcPid;
-               on_shmem_exit(print_lwlock_stats, 0);
-       }
+               init_lwlock_stats();
        /* Count lock acquisition attempts */
        if (mode == LW_EXCLUSIVE)
                ex_acquire_counts[lockid]++;
@@ -588,6 +595,12 @@ LWLockWaitUntilFree(LWLockId lockid, LWLockMode mode)
 
        PRINT_LWDEBUG("LWLockWaitUntilFree", lockid, lock);
 
+#ifdef LWLOCK_STATS
+       /* Set up local count state first time through in a given process */
+       if (counts_for_pid != MyProcPid)
+               init_lwlock_stats();
+#endif
+
        /* Ensure we will have room to remember the lock */
        if (num_held_lwlocks >= MAX_SIMUL_LWLOCKS)
                elog(ERROR, "too many LWLocks taken");