]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/ipc/ReadWriteLock.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ipc / ReadWriteLock.cc
index 4732df4e2b03abca4443ff33f6b34253a8adbfd1..de6894a7c5a1f6346529ed8d38a2be15b91e55ee 100644 (file)
 /*
- * DEBUG: section 54    Interprocess Communication
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 54    Interprocess Communication */
+
 #include "squid.h"
-#include "Store.h"
 #include "ipc/ReadWriteLock.h"
+#include "Store.h"
+
+void Ipc::AssertFlagIsSet(std::atomic_flag &flag)
+{
+    // If the flag was false, then we set it to true and assert. A true flag
+    // may help keep other processes away from this broken entry.
+    // Otherwise, we just set an already set flag, which is probably a no-op.
+    assert(flag.test_and_set(std::memory_order_relaxed));
+}
 
 bool
 Ipc::ReadWriteLock::lockShared()
 {
-    ++readers; // this locks "new" writers out
-    if (!writers || appending) // there are no old writers or sharing is OK
+    ++readLevel; // this locks "new" writers out
+    if (!writeLevel || appending) { // nobody is writing, or sharing is OK
+        ++readers;
         return true;
-    --readers;
+    }
+    --readLevel;
     return false;
 }
 
 bool
 Ipc::ReadWriteLock::lockExclusive()
 {
-    if (!writers++) { // we are the first writer + this locks "new" readers out
-        if (!readers) // there are no old readers
+    if (!writeLevel++) { // we are the first writer + lock "new" readers out
+        if (!readLevel) { // no old readers and nobody is becoming one
+            writing = true;
             return true;
+        }
+    }
+    --writeLevel;
+    return false;
+}
+
+bool
+Ipc::ReadWriteLock::lockHeaders()
+{
+    if (lockShared()) {
+        if (!updating.test_and_set(std::memory_order_acquire))
+            return true; // we got here first
+        // the updating lock was already set by somebody else
+        unlockShared();
     }
-    --writers;
     return false;
 }
 
 void
 Ipc::ReadWriteLock::unlockShared()
 {
-    assert(readers-- > 0);
+    assert(readers > 0);
+    --readers;
+    --readLevel;
 }
 
 void
 Ipc::ReadWriteLock::unlockExclusive()
 {
-    appending = 0;
-    assert(writers-- > 0);
+    assert(writing);
+    appending = false;
+    writing = false;
+    --writeLevel;
+}
+
+void
+Ipc::ReadWriteLock::unlockHeaders()
+{
+    AssertFlagIsSet(updating);
+    updating.clear(std::memory_order_release);
+    unlockShared();
 }
 
 void
 Ipc::ReadWriteLock::switchExclusiveToShared()
 {
-    ++readers; // must be done before we release exclusive control
+    assert(writing);
+    ++readLevel; // must be done before we release exclusive control
+    ++readers;
     unlockExclusive();
 }
 
 void
 Ipc::ReadWriteLock::startAppending()
 {
-    assert(writers > 0);
-    appending++;
+    assert(writing);
+    appending = true;
 }
 
 void
@@ -60,9 +104,9 @@ Ipc::ReadWriteLock::updateStats(ReadWriteLockStats &stats) const
     if (readers) {
         ++stats.readable;
         stats.readers += readers;
-    } else if (writers) {
+    } else if (writing) {
         ++stats.writeable;
-        stats.writers += writers;
+        ++stats.writers;
         stats.appenders += appending;
     } else {
         ++stats.idle;
@@ -102,3 +146,4 @@ Ipc::ReadWriteLockStats::dump(StoreEntry &e) const
                           appenders, appPerc);
     }
 }
+