Trunk r12255 made Clang compiler happy by removing flexible nonPod[] arrays.
Unfortunately, it also moved shared memory items into local memory (in some
cases uninitialized).
This change provides a Clang-friendly flexible array replacement while keeping
items in the shared memory (and using placement-new initialization). The code
may have become even less readable, but hopefully more portable.
N.B. Flexible arrays were introdiced in C99 standard, after C++ was
standardized in 1998. They are not yet in any revised C++ standard, but most
C++ compilers support them, at least for PODs.
Request.h \
Response.h \
\
+ mem/FlexibleArray.h \
mem/Page.cc \
mem/Page.h \
mem/PagePool.cc \
/* QueueReaders */
-Ipc::QueueReaders::QueueReaders(const int aCapacity): theCapacity(aCapacity)
+Ipc::QueueReaders::QueueReaders(const int aCapacity): theCapacity(aCapacity),
+ theReaders(theCapacity)
{
Must(theCapacity > 0);
- theReaders=new QueueReader[theCapacity];
-}
-
-Ipc::QueueReaders::~QueueReaders()
-{
- delete[] theReaders;
}
size_t
#include "Debug.h"
#include "base/InstanceId.h"
#include "ipc/AtomicWord.h"
+#include "ipc/mem/FlexibleArray.h"
#include "ipc/mem/Pointer.h"
#include "util.h"
{
public:
QueueReaders(const int aCapacity);
- ~QueueReaders();
size_t sharedMemorySize() const;
static size_t SharedMemorySize(const int capacity);
const int theCapacity; /// number of readers
- QueueReader *theReaders; /// readers
-private:
- QueueReaders(); //not implemented
- QueueReaders& operator =(const QueueReaders&); //not implemented
- QueueReaders(const QueueReaders&); //not implemented
+ Ipc::Mem::FlexibleArray<QueueReader> theReaders; /// readers
};
/**
Ipc::StoreMap::freeLocked(Slot &s, bool keepLocked)
{
if (s.state == Slot::Readable && cleaner)
- cleaner->cleanReadable(&s - shared->slots);
+ cleaner->cleanReadable(&s - shared->slots.raw());
s.waitingToBeFreed = false;
s.state = Slot::Empty;
if (!keepLocked)
s.lock.unlockExclusive();
--shared->count;
- debugs(54, 5, HERE << " freed slot at " << (&s - shared->slots) <<
+ debugs(54, 5, HERE << " freed slot at " << (&s - shared->slots.raw()) <<
" in map [" << path << ']');
}
/* Ipc::StoreMap::Shared */
Ipc::StoreMap::Shared::Shared(const int aLimit, const size_t anExtrasSize):
- limit(aLimit), extrasSize(anExtrasSize), count(0)
+ limit(aLimit), extrasSize(anExtrasSize), count(0), slots(aLimit)
{
- slots=new Slot[limit];
-}
-
-Ipc::StoreMap::Shared::~Shared()
-{
- delete[] slots;
}
size_t
#define SQUID_IPC_STORE_MAP_H
#include "ipc/ReadWriteLock.h"
+#include "ipc/mem/FlexibleArray.h"
#include "ipc/mem/Pointer.h"
#include "typedefs.h"
Shared(const int aLimit, const size_t anExtrasSize);
size_t sharedMemorySize() const;
static size_t SharedMemorySize(const int limit, const size_t anExtrasSize);
- ~Shared();
const int limit; ///< maximum number of map slots
const size_t extrasSize; ///< size of slot extra data
Atomic::Word count; ///< current number of map slots
- Slot *slots; ///< slots storage
- private:
- Shared(); //disabled
- Shared &operator=(const Shared&); //disabled
- Shared(const Shared&); //disabled
+ Ipc::Mem::FlexibleArray<Slot> slots; ///< slots storage
};
public:
--- /dev/null
+/*
+ */
+
+#ifndef SQUID_IPC_MEM_FLEXIBLE_ARRAY_H
+#define SQUID_IPC_MEM_FLEXIBLE_ARRAY_H
+
+// sometimes required for placement-new operator to be declared
+#include <new>
+
+namespace Ipc
+{
+
+namespace Mem
+{
+
+/// A "flexible array" of Items inside some shared memory space.
+/// A portable equivalent of a "Item items[];" data member.
+/// Some compilers such as Clang can only handle flexible arrays of PODs,
+/// and the current C++ standard does not allow flexible arrays at all.
+template <class Item>
+class FlexibleArray
+{
+public:
+ explicit FlexibleArray(const int capacity) {
+ if (capacity > 1) // the first item is initialized automatically
+ new (items+1) Item[capacity-1];
+ }
+
+ Item &operator [](const int idx) { return items[idx]; }
+ const Item &operator [](const int idx) const { return items[idx]; }
+
+ //const Item *operator ()() const { return items; }
+ //Item *operator ()() { return items; }
+
+ Item *raw() { return items; }
+
+private:
+ Item items[1]; // ensures proper alignment of array elements
+};
+
+} // namespace Mem
+
+} // namespace Ipc
+
+#endif /* SQUID_IPC_MEM_FLEXIBLE_ARRAY_H */
Ipc::Mem::PageStack::PageStack(const uint32_t aPoolId, const unsigned int aCapacity, const size_t aPageSize):
thePoolId(aPoolId), theCapacity(aCapacity), thePageSize(aPageSize),
theSize(theCapacity),
- theLastReadable(prev(theSize)), theFirstWritable(next(theLastReadable))
+ theLastReadable(prev(theSize)), theFirstWritable(next(theLastReadable)),
+ theItems(aCapacity)
{
- theItems=new Item[theSize];
// initially, all pages are free
for (Offset i = 0; i < theSize; ++i)
theItems[i] = i + 1; // skip page number zero to keep numbers positive
}
-Ipc::Mem::PageStack::~PageStack()
-{
- delete[] theItems;
-}
-
/*
* TODO: We currently rely on the theLastReadable hint during each
* loop iteration. We could also use hint just for the start position:
#define SQUID_IPC_MEM_PAGE_STACK_H
#include "ipc/AtomicWord.h"
+#include "ipc/mem/FlexibleArray.h"
namespace Ipc
{
typedef uint32_t Value; ///< stack item type (a free page number)
PageStack(const uint32_t aPoolId, const unsigned int aCapacity, const size_t aPageSize);
- ~PageStack();
unsigned int capacity() const { return theCapacity; }
size_t pageSize() const { return thePageSize; }
Atomic::WordT<Offset> theFirstWritable;
typedef Atomic::WordT<Value> Item;
- Item *theItems; ///< page number storage
+ Ipc::Mem::FlexibleArray<Item> theItems; ///< page number storage
};
} // namespace Mem