{
// 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()) {
--- /dev/null
+/*
+ * $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
+}
#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); }
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
noinst_LTLIBRARIES = libipc.la
libipc_la_SOURCES = \
+ AtomicWord.cc \
AtomicWord.h \
FdNotes.cc \
FdNotes.h \
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;
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
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
};
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
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
};
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))
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
};
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;
}
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
};