Oops, only wanted datetime.c changes in there. lock stuff reversed out.
authorBruce Momjian <bruce@momjian.us>
Sat, 29 Dec 2001 21:30:32 +0000 (21:30 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 29 Dec 2001 21:30:32 +0000 (21:30 +0000)
src/backend/storage/lmgr/lwlock.c

index a3a61a3a36e64ac27f8ff4ed32e8b9f0304b01b8..918c300dba30ca5d79089f3e44278f0d17f97e6e 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lwlock.c,v 1.6 2001/12/29 21:28:18 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lwlock.c,v 1.7 2001/12/29 21:30:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -195,8 +195,7 @@ void
 LWLockAcquire(LWLockId lockid, LWLockMode mode)
 {
    volatile LWLock *lock = LWLockArray + lockid;
-   PROC       *proc = MyProc;
-   int         extraWaits = 0;
+   bool        mustwait;
 
    PRINT_LWDEBUG("LWLockAcquire", lockid, lock);
 
@@ -207,57 +206,43 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode)
     */
    HOLD_INTERRUPTS();
 
-   /*
-    * Loop here to try to acquire lock after each time we are signaled
-    * by LWLockRelease.
-    *
-    * NOTE: it might seem better to have LWLockRelease actually grant us
-    * the lock, rather than retrying and possibly having to go back to
-    * sleep.  But in practice that is no good because it means a process
-    * swap for every lock acquisition when two or more processes are
-    * contending for the same lock.  Since LWLocks are normally used to
-    * protect not-very-long sections of computation, a process needs to
-    * be able to acquire and release the same lock many times during a
-    * single process dispatch cycle, even in the presence of contention.
-    * The efficiency of being able to do that outweighs the inefficiency of
-    * sometimes wasting a dispatch cycle because the lock is not free when a
-    * released waiter gets to run.  See pgsql-hackers archives for 29-Dec-01.
-    */
-   for (;;)
-   {
-       bool        mustwait;
-
-       /* Acquire mutex.  Time spent holding mutex should be short! */
-       SpinLockAcquire_NoHoldoff(&lock->mutex);
+   /* Acquire mutex.  Time spent holding mutex should be short! */
+   SpinLockAcquire_NoHoldoff(&lock->mutex);
 
-       /* If I can get the lock, do so quickly. */
-       if (mode == LW_EXCLUSIVE)
+   /* If I can get the lock, do so quickly. */
+   if (mode == LW_EXCLUSIVE)
+   {
+       if (lock->exclusive == 0 && lock->shared == 0)
        {
-           if (lock->exclusive == 0 && lock->shared == 0)
-           {
-               lock->exclusive++;
-               mustwait = false;
-           }
-           else
-               mustwait = true;
+           lock->exclusive++;
+           mustwait = false;
        }
        else
+           mustwait = true;
+   }
+   else
+   {
+       /*
+        * If there is someone waiting (presumably for exclusive access),
+        * queue up behind him even though I could get the lock.  This
+        * prevents a stream of read locks from starving a writer.
+        */
+       if (lock->exclusive == 0 && lock->head == NULL)
        {
-           if (lock->exclusive == 0)
-           {
-               lock->shared++;
-               mustwait = false;
-           }
-           else
-               mustwait = true;
+           lock->shared++;
+           mustwait = false;
        }
+       else
+           mustwait = true;
+   }
 
-       if (!mustwait)
-           break;              /* got the lock */
+   if (mustwait)
+   {
+       /* Add myself to wait queue */
+       PROC       *proc = MyProc;
+       int         extraWaits = 0;
 
        /*
-        * Add myself to wait queue.
-        *
         * If we don't have a PROC structure, there's no way to wait. This
         * should never occur, since MyProc should only be null during
         * shared memory initialization.
@@ -282,9 +267,9 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode)
         *
         * Since we share the process wait semaphore with the regular lock
         * manager and ProcWaitForSignal, and we may need to acquire an
-        * LWLock while one of those is pending, it is possible that we get
-        * awakened for a reason other than being signaled by LWLockRelease.
-        * If so, loop back and wait again.  Once we've gotten the LWLock,
+        * LWLock while one of those is pending, it is possible that we
+        * get awakened for a reason other than being granted the LWLock.
+        * If so, loop back and wait again.  Once we've gotten the lock,
         * re-increment the sema by the number of additional signals
         * received, so that the lock manager or signal manager will see
         * the received signal when it next waits.
@@ -302,21 +287,23 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode)
 
        LOG_LWDEBUG("LWLockAcquire", lockid, "awakened");
 
-       /* Now loop back and try to acquire lock again. */
+       /*
+        * The awakener already updated the lock struct's state, so we
+        * don't need to do anything more to it.  Just need to fix the
+        * semaphore count.
+        */
+       while (extraWaits-- > 0)
+           IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum);
+   }
+   else
+   {
+       /* Got the lock without waiting */
+       SpinLockRelease_NoHoldoff(&lock->mutex);
    }
-
-   /* We are done updating shared state of the lock itself. */
-   SpinLockRelease_NoHoldoff(&lock->mutex);
 
    /* Add lock to list of locks held by this backend */
    Assert(num_held_lwlocks < MAX_SIMUL_LWLOCKS);
    held_lwlocks[num_held_lwlocks++] = lockid;
-
-   /*
-    * Fix the process wait semaphore's count for any absorbed wakeups.
-    */
-   while (extraWaits-- > 0)
-       IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum);
 }
 
 /*
@@ -357,7 +344,12 @@ LWLockConditionalAcquire(LWLockId lockid, LWLockMode mode)
    }
    else
    {
-       if (lock->exclusive == 0)
+       /*
+        * If there is someone waiting (presumably for exclusive access),
+        * queue up behind him even though I could get the lock.  This
+        * prevents a stream of read locks from starving a writer.
+        */
+       if (lock->exclusive == 0 && lock->head == NULL)
        {
            lock->shared++;
            mustwait = false;
@@ -435,17 +427,20 @@ LWLockRelease(LWLockId lockid)
        if (lock->exclusive == 0 && lock->shared == 0)
        {
            /*
-            * Remove the to-be-awakened PROCs from the queue.  If the
-            * front waiter wants exclusive lock, awaken him only.
-            * Otherwise awaken as many waiters as want shared access.
+            * Remove the to-be-awakened PROCs from the queue, and update
+            * the lock state to show them as holding the lock.
             */
            proc = head;
-           if (!proc->lwExclusive)
+           if (proc->lwExclusive)
+               lock->exclusive++;
+           else
            {
+               lock->shared++;
                while (proc->lwWaitLink != NULL &&
                       !proc->lwWaitLink->lwExclusive)
                {
                    proc = proc->lwWaitLink;
+                   lock->shared++;
                }
            }
            /* proc is now the last PROC to be released */