From: Dmitry Kurochkin Date: Fri, 28 Oct 2011 01:01:41 +0000 (-0600) Subject: Provide "fake" AtomicWordT implementation for non-SMP configurations. X-Git-Tag: BumpSslServerFirst.take01~62 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=794d4c0c74c08a105ebdac9043fd8288e09683b3;p=thirdparty%2Fsquid.git Provide "fake" AtomicWordT implementation for non-SMP configurations. 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. --- diff --git a/src/MemStore.cc b/src/MemStore.cc index 42d82b9724..f3f31af3b3 100644 --- a/src/MemStore.cc +++ b/src/MemStore.cc @@ -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 index 0000000000..ec039aa211 --- /dev/null +++ b/src/ipc/AtomicWord.cc @@ -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 +} diff --git a/src/ipc/AtomicWord.h b/src/ipc/AtomicWord.h index 8279b79364..7a8eb1f984 100644 --- a/src/ipc/AtomicWord.h +++ b/src/ipc/AtomicWord.h @@ -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 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 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 AtomicWord; +typedef WordT Word; + +} // namespace Atomic + +} // namespace Ipc #endif // SQUID_IPC_ATOMIC_WORD_H diff --git a/src/ipc/Makefile.am b/src/ipc/Makefile.am index bf35d8a1c2..9e2f7dcfda 100644 --- a/src/ipc/Makefile.am +++ b/src/ipc/Makefile.am @@ -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 \ diff --git a/src/ipc/Queue.h b/src/ipc/Queue.h index 5f80b3aa2c..ff46a6c1e6 100644 --- a/src/ipc/Queue.h +++ b/src/ipc/Queue.h @@ -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 AtomicSignedMsec; + typedef Atomic::WordT 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 diff --git a/src/ipc/ReadWriteLock.h b/src/ipc/ReadWriteLock.h index 4d8f57202c..9bcad4042f 100644 --- a/src/ipc/ReadWriteLock.h +++ b/src/ipc/ReadWriteLock.h @@ -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 }; diff --git a/src/ipc/StoreMap.h b/src/ipc/StoreMap.h index f6b1bef35e..fe4458d6d4 100644 --- a/src/ipc/StoreMap.h +++ b/src/ipc/StoreMap.h @@ -22,7 +22,7 @@ public: public: mutable ReadWriteLock lock; ///< protects slot data below - AtomicWordT waitingToBeFreed; ///< may be accessed w/o a lock + Atomic::WordT 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 }; diff --git a/src/ipc/mem/PagePool.cc b/src/ipc/mem/PagePool.cc index e903fec4fb..187cc71206 100644 --- a/src/ipc/mem/PagePool.cc +++ b/src/ipc/mem/PagePool.cc @@ -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( + theLevels(reinterpret_cast( reinterpret_cast(pageIndex.getRaw()) + pageIndex->stackSize())), theBuf(reinterpret_cast(theLevels + PageId::maxPurpose)) diff --git a/src/ipc/mem/PagePool.h b/src/ipc/mem/PagePool.h index e6d808a639..b2eab2dcfb 100644 --- a/src/ipc/mem/PagePool.h +++ b/src/ipc/mem/PagePool.h @@ -47,7 +47,7 @@ public: private: Ipc::Mem::Pointer 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 }; diff --git a/src/ipc/mem/PageStack.cc b/src/ipc/mem/PageStack.cc index d3c4d7ae18..353ab90794 100644 --- a/src/ipc/mem/PageStack.cc +++ b/src/ipc/mem/PageStack.cc @@ -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; } diff --git a/src/ipc/mem/PageStack.h b/src/ipc/mem/PageStack.h index ddb1ba9ed0..1eb27e30f6 100644 --- a/src/ipc/mem/PageStack.h +++ b/src/ipc/mem/PageStack.h @@ -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 theSize; + Atomic::WordT theSize; /// last readable item index; just a hint, not a guarantee - AtomicWordT theLastReadable; + Atomic::WordT theLastReadable; /// first writable item index; just a hint, not a guarantee - AtomicWordT theFirstWritable; + Atomic::WordT theFirstWritable; - typedef AtomicWordT Item; + typedef Atomic::WordT Item; Item theItems[]; ///< page number storage };