]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Provide "fake" AtomicWordT implementation for non-SMP configurations.
authorDmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Fri, 28 Oct 2011 01:01:41 +0000 (19:01 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Fri, 28 Oct 2011 01:01:41 +0000 (19:01 -0600)
While we can not provide real AtomicWordT implementation on the systems where
atomic operations are not available, we can use a "fake" one if Squid is
running in non-SMP mode.  Before the change, the "fake" implementation was
always asserting, which is too restrictive and leads to test failures on
systems without atomic operations.

The new implementation works under conditions similar to "fake" shared memory
segments and allows SMP-using code (e.g. Rock store) to work in non-SMP mode.
In particular, it allows tests to pass on such systems.

AtomicWordT was renamed to WordT and moved to Ipc::Atomic namespace to allow
Ipc::Atomic::Enabled() to be declared outside of the AtomicWordT template
class.  This lets us define the Enabled() method in AtomicWord.cc which avoids
dragging protos.h #include into the AtomicWord.h header.

src/MemStore.cc
src/ipc/AtomicWord.cc [new file with mode: 0644]
src/ipc/AtomicWord.h
src/ipc/Makefile.am
src/ipc/Queue.h
src/ipc/ReadWriteLock.h
src/ipc/StoreMap.h
src/ipc/mem/PagePool.cc
src/ipc/mem/PagePool.h
src/ipc/mem/PageStack.cc
src/ipc/mem/PageStack.h

index 42d82b9724c8085ba209b59fe22b2d3863f2d6d6..f3f31af3b33a9a02de9de20a8c79ca50333b0d5a 100644 (file)
@@ -397,10 +397,10 @@ void MemStoreRr::run(const RunnerRegistry &r)
 {
     // decide whether to use a shared memory cache if the user did not specify
     if (!Config.memShared.configured()) {
-        Config.memShared.configure(AtomicOperationsSupported &&
+        Config.memShared.configure(Ipc::Atomic::Enabled() &&
                                    Ipc::Mem::Segment::Enabled() && UsingSmp() &&
                                    Config.memMaxSize > 0);
-    } else if (Config.memShared && !AtomicOperationsSupported) {
+    } else if (Config.memShared && !Ipc::Atomic::Enabled()) {
         // bail if the user wants shared memory cache but we cannot support it
         fatal("memory_cache_shared is on, but no support for atomic operations detected");
     } else if (Config.memShared && !Ipc::Mem::Segment::Enabled()) {
diff --git a/src/ipc/AtomicWord.cc b/src/ipc/AtomicWord.cc
new file mode 100644 (file)
index 0000000..ec039aa
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 54    Interprocess Communication
+ *
+ */
+
+#include "config.h"
+#include "ipc/AtomicWord.h"
+#include "protos.h"
+
+bool Ipc::Atomic::Enabled() {
+#if HAVE_ATOMIC_OPS
+    return true;
+#else
+    return !UsingSmp();
+#endif
+}
index 8279b7936418f829d3f97044b5394103d6689273..7a8eb1f984902a157b0f6ade3ed4ca7a89d7ff0b 100644 (file)
@@ -6,17 +6,27 @@
 #ifndef SQUID_IPC_ATOMIC_WORD_H
 #define SQUID_IPC_ATOMIC_WORD_H
 
+namespace Ipc
+{
+
+namespace Atomic
+{
+
+/// Whether atomic operations support is available
+bool Enabled();
+
 #if HAVE_ATOMIC_OPS
+
 /// Supplies atomic operations for an integral Value in memory shared by kids.
 /// Used to implement non-blocking shared locks, queues, tables, and pools.
 template <class ValueType>
-class AtomicWordT
+class WordT
 {
 public:
     typedef ValueType Value;
 
-    AtomicWordT() {} // leave value unchanged
-    AtomicWordT(Value aValue): value(aValue) {} // XXX: unsafe
+    WordT() {} // leave value unchanged
+    WordT(Value aValue): value(aValue) {} // XXX: unsafe
 
     Value operator +=(int delta) { return __sync_add_and_fetch(&value, delta); }
     Value operator -=(int delta) { return __sync_sub_and_fetch(&value, delta); }
@@ -38,51 +48,54 @@ public:
     operator Value () const { return get(); }
 
 private:
+
     Value value;
 };
 
-enum { AtomicOperationsSupported = 1 };
-
 #else
-/// A wrapper to provide AtomicWordT API (and asserting implementation)
+
+/// A wrapper to provide AtomicWordT API (and implementation asserting in SMP mode)
 /// where we do not support atomic operations. This avoids ifdefs in core code.
 template <class ValueType>
-class AtomicWordT
+class WordT
 {
 public:
     typedef ValueType Value;
 
-    AtomicWordT() {} // leave value unchanged
-    AtomicWordT(Value aValue): value(aValue) {} // XXX: unsafe
+    WordT() {} // leave value unchanged
+    WordT(Value aValue): value(aValue) {} // XXX: unsafe
 
-    Value operator +=(int) { assert(false); return *this; }
+    Value operator +=(int delta) { assert(Enabled()); return value += delta; }
     Value operator ++() { return *this += 1; }
     Value operator --() { return *this += -1; }
-    Value operator ++(int) { assert(false); return *this; }
-    Value operator --(int) { assert(false); return *this; }
+    Value operator ++(int) { assert(Enabled()); return value++; }
+    Value operator --(int) { assert(Enabled()); return value--; }
 
     bool swap_if(const int comparand, const int replacement)
-    { assert(false); return false; }
+    { assert(Enabled()); return value == comparand ? value = replacement, true : false; }
 
     /// v1 = value; value &= v2; return v1;
     Value fetchAndAnd(const Value v2)
-    { assert(false); return value; }
+    { assert(Enabled()); const Value v1 = value; value &= v2; return v1; }
 
     // TODO: no need for __sync_bool_compare_and_swap here?
-    bool operator ==(int v2) { assert(false); return false; }
+    bool operator ==(const int v2) { assert(Enabled()); return value == v2; }
 
     // TODO: no need for __sync_fetch_and_add here?
-    Value get() const { assert(false); return value; }
+    Value get() const { assert(Enabled()); return value; }
     operator Value () const { return get(); }
 
 private:
+
     Value value;
 };
 
-enum { AtomicOperationsSupported = 0 };
-
 #endif /* HAVE_ATOMIC_OPS */
 
-typedef AtomicWordT<int> AtomicWord;
+typedef WordT<int> Word;
+
+} // namespace Atomic
+
+} // namespace Ipc
 
 #endif // SQUID_IPC_ATOMIC_WORD_H
index bf35d8a1c29ab0fdfbd997b8004cbf972dd39d39..9e2f7dcfda5a5c3e0aa8fe477d9fd60877390d47 100644 (file)
@@ -4,6 +4,7 @@ include $(top_srcdir)/src/TestHeaders.am
 noinst_LTLIBRARIES = libipc.la
 
 libipc_la_SOURCES = \
+       AtomicWord.cc \
        AtomicWord.h \
        FdNotes.cc \
        FdNotes.h \
index 5f80b3aa2c0a17d92a22d322006890db5d58a2fe..ff46a6c1e6640a03896a2f962660aaec96fd0871 100644 (file)
@@ -42,15 +42,15 @@ public:
     void clearSignal() { unblock(); popSignal.swap_if(1,0); }
 
 private:
-    AtomicWord popBlocked; ///< whether the reader is blocked on pop()
-    AtomicWord popSignal; ///< whether writer has sent and reader has not received notification
+    Atomic::Word popBlocked; ///< whether the reader is blocked on pop()
+    Atomic::Word popSignal; ///< whether writer has sent and reader has not received notification
 
 public:
-    typedef AtomicWord Rate; ///< pop()s per second
+    typedef Atomic::Word Rate; ///< pop()s per second
     Rate rateLimit; ///< pop()s per second limit if positive
 
     // we need a signed atomic type because balance may get negative
-    typedef AtomicWordT<int> AtomicSignedMsec;
+    typedef Atomic::WordT<int> AtomicSignedMsec;
     typedef AtomicSignedMsec Balance;
     /// how far ahead the reader is compared to a perfect read/sec event rate
     Balance balance;
@@ -115,7 +115,7 @@ private:
     unsigned int theIn; ///< input index, used only in push()
     unsigned int theOut; ///< output index, used only in pop()
 
-    AtomicWord theSize; ///< number of items in the queue
+    Atomic::Word theSize; ///< number of items in the queue
     const unsigned int theMaxItemSize; ///< maximum item size
     const int theCapacity; ///< maximum number of items, i.e. theBuffer size
 
index 4d8f57202c83a5e148c210603b1e6b101a6e720c..9bcad4042fd9425cbcf6e8d323b26f3ef669764a 100644 (file)
@@ -26,8 +26,8 @@ public:
     void updateStats(ReadWriteLockStats &stats) const;
 
 public:
-    mutable AtomicWord readers; ///< number of users trying to read
-    AtomicWord writers; ///< number of writers trying to modify protected data
+    mutable Atomic::Word readers; ///< number of users trying to read
+    Atomic::Word writers; ///< number of writers trying to modify protected data
 };
 
 
index f6b1bef35e521ad5f350ec3dc563486bce7ea481..fe4458d6d45f731b775aebb961f3fbaaa2796629 100644 (file)
@@ -22,7 +22,7 @@ public:
 
 public:
     mutable ReadWriteLock lock; ///< protects slot data below
-    AtomicWordT<uint8_t> waitingToBeFreed; ///< may be accessed w/o a lock
+    Atomic::WordT<uint8_t> waitingToBeFreed; ///< may be accessed w/o a lock
 
     uint64_t key[2]; ///< StoreEntry key
 
@@ -65,7 +65,7 @@ public:
 
         const int limit; ///< maximum number of map slots
         const size_t extrasSize; ///< size of slot extra data
-        AtomicWord count; ///< current number of map slots
+        Atomic::Word count; ///< current number of map slots
         Slot slots[]; ///< slots storage
     };
 
index e903fec4fb57a479b800c1ae7d55e308e5be7fa7..187cc712061fc380d496c27fa846e30e33ebe1a9 100644 (file)
@@ -24,7 +24,7 @@ Ipc::Mem::PagePool::Init(const char *const id, const unsigned int capacity, cons
 
 Ipc::Mem::PagePool::PagePool(const char *const id):
         pageIndex(shm_old(PageStack)(id)),
-        theLevels(reinterpret_cast<AtomicWord *>(
+        theLevels(reinterpret_cast<Atomic::Word *>(
                       reinterpret_cast<char *>(pageIndex.getRaw()) +
                       pageIndex->stackSize())),
         theBuf(reinterpret_cast<char *>(theLevels + PageId::maxPurpose))
index e6d808a639802e52347d23daa1e49a5e00b2d734..b2eab2dcfb2d39e81489c6615937c517104dc278 100644 (file)
@@ -47,7 +47,7 @@ public:
 private:
     Ipc::Mem::Pointer<PageStack> pageIndex; ///< free pages index
     /// number of shared memory pages used now for each purpose
-    AtomicWord *const theLevels;
+    Atomic::Word *const theLevels;
     char *const theBuf; ///< pages storage
 };
 
index d3c4d7ae18add3d33429f0634f49fbb38945aedb..353ab90794526633b853b77141faf58651a58769 100644 (file)
@@ -113,7 +113,7 @@ Ipc::Mem::PageStack::sharedMemorySize() const
 size_t
 Ipc::Mem::PageStack::SharedMemorySize(const uint32_t, const unsigned int capacity, const size_t pageSize)
 {
-    const size_t levelsSize = PageId::maxPurpose * sizeof(AtomicWord);
+    const size_t levelsSize = PageId::maxPurpose * sizeof(Atomic::Word);
     const size_t pagesDataSize = capacity * pageSize;
     return StackSize(capacity) + pagesDataSize + levelsSize;
 }
index ddb1ba9ed076a58ac9f4f44e7bf8fe04f12defb0..1eb27e30f62a0e2ba053a149813193f394d87534 100644 (file)
@@ -59,14 +59,14 @@ private:
     const Offset theCapacity; ///< stack capacity, i.e. theItems size
     const size_t thePageSize; ///< page size, used to calculate shared memory size
     /// lower bound for the number of free pages (may get negative!)
-    AtomicWordT<Offset> theSize;
+    Atomic::WordT<Offset> theSize;
 
     /// last readable item index; just a hint, not a guarantee
-    AtomicWordT<Offset> theLastReadable;
+    Atomic::WordT<Offset> theLastReadable;
     /// first writable item index; just a hint, not a guarantee
-    AtomicWordT<Offset> theFirstWritable;
+    Atomic::WordT<Offset> theFirstWritable;
 
-    typedef AtomicWordT<Value> Item;
+    typedef Atomic::WordT<Value> Item;
     Item theItems[]; ///< page number storage
 };