#include "config.h"
#include "ipc/mem/Page.h"
-// TODO: implement
+#if HAVE_IOSTREAM
+#include <iostream>
+#endif
+
+
+std::ostream &Ipc::Mem::operator <<(std::ostream &os, const PageId &page)
+{
+ return os << "sh_page" << page.pool << '.' << page.number;
+}
/// Shared memory page identifier, address, or handler
class PageId {
public:
- PageId(): segment(0), number(0) {}
+ PageId(): pool(0), number(0) {}
- // uint32_t pool; ///< page pool ID within Squid; unused for now
- uint32_t segment; ///< memory segment ID within the pool
+ uint32_t pool; ///< page pool ID within Squid
+ // uint32_t segment; ///< memory segment ID within the pool; unused for now
uint32_t number; ///< page number within the segment
};
*/
#include "config.h"
+#include "base/TextException.h"
+#include "ipc/mem/Page.h"
#include "ipc/mem/PagePool.h"
-// TODO: implement
+
+static String
+PageIndexId(String id)
+{
+ id.append("-index");
+ return id;
+}
+
+
+// Ipc::Mem::PagePool
+
+Ipc::Mem::PagePool::PagePool(const String &id, const unsigned int capacity, const unsigned int pageSize):
+ pageIndex(PageIndexId(id), capacity),
+ shm(id.termedBuf())
+{
+ shm.create(pageSize * capacity + sizeof(Shared));
+ assert(shm.mem());
+ shared = new (shm.mem()) Shared(capacity, pageSize);
+}
+
+Ipc::Mem::PagePool::PagePool(const String &id):
+ pageIndex(PageIndexId(id)), shm(id.termedBuf())
+{
+ shm.open();
+ shared = reinterpret_cast<Shared *>(shm.mem());
+ assert(shared);
+}
+
+bool
+Ipc::Mem::PagePool::get(PageId &page)
+{
+ if (pageIndex.pop(page.number)) {
+ page.pool = shared->theId;
+ return true;
+ }
+ return false;
+}
+
+void
+Ipc::Mem::PagePool::put(PageId &page)
+{
+ Must(pageIdIsValid(page));
+ pageIndex.push(page.number);
+ page = PageId();
+}
+
+void *
+Ipc::Mem::PagePool::pagePointer(const PageId &page)
+{
+ Must(pageIdIsValid(page));
+ return shared->theBuf + shared->thePageSize * (page.number - 1);
+}
+
+bool
+Ipc::Mem::PagePool::pageIdIsValid(const PageId &page) const
+{
+ return page.pool == shared->theId &&
+ 0 < page.number && page.number <= shared->theCapacity;
+}
+
+
+// Ipc::Mem::PagePool::Shared
+
+static unsigned int LastPagePoolId = 0;
+
+Ipc::Mem::PagePool::Shared::Shared(const unsigned int aCapacity, const unsigned int aPageSize):
+ theId(++LastPagePoolId), theCapacity(aCapacity), thePageSize(aPageSize)
+{
+ if (LastPagePoolId + 1 == 0)
+ ++LastPagePoolId; // skip zero pool id
+}
#ifndef SQUID_IPC_MEM_PAGE_POOL_H
#define SQUID_IPC_MEM_PAGE_POOL_H
-#include "ipc/mem/Page.h"
+#include "ipc/mem/PageStack.h"
#include "ipc/mem/Segment.h"
namespace Ipc {
namespace Mem {
+class PageId;
+
/// Atomic container of shared memory pages. Implemented using a collection of
-/// Segments, each with a PageStack index of free pages.
+/// Segments, each with a PageStack index of free pages. All pools must be
+/// created by a single process.
class PagePool {
public:
- /// creates a new shared page pool that can hold up to capacity pages
- PagePool(const String &id, const unsigned int capacity);
+ /// creates a new shared page pool that can hold up to capacity pages of pageSize size
+ PagePool(const String &id, const unsigned int capacity, const unsigned int pageSize);
/// attaches to the identified shared page pool
PagePool(const String &id);
+ unsigned int capacity() const { return shared->theCapacity; }
+ unsigned int pageSize() const { return shared->thePageSize; }
+
/// sets page ID and returns true unless no free pages are found
bool get(PageId &page);
/// makes identified page available as a free page to future get() callers
- void put(const PageId &page);
+ void put(PageId &page);
+ /// converts page handler into a temporary writeable shared memory pointer
+ void *pagePointer(const PageId &page);
private:
- Segment meta; ///< shared memory segment to store our metadata
- /// TODO: Shared *shared; ///< our metadata, shared among all pool users
+ inline bool pageIdIsValid(const PageId &page) const;
+
+ struct Shared {
+ Shared(const unsigned int aCapacity, const unsigned int aPageSize);
+
+ const unsigned int theId; ///< pool id
+ const unsigned int theCapacity; ///< number of pages in the pool
+ const unsigned int thePageSize; ///< page size
+
+ char *theBuf[]; ///< pages storage
+ };
- /// TODO: typedef collection<Segment*> Store; ///< storage for pages
- /// TODO: Store store; ///< pages (with free page indexes)
+ PageStack pageIndex; ///< free pages index
+ Segment shm; ///< shared memory segment to store metadata (and pages)
+ Shared *shared; ///< our metadata and page storage, shared among all stack users
};
} // namespace Mem
Ipc::Mem::PageStack::push(const Value value)
{
Must(value != Writable);
+ Must(value <= shared->theCapacity);
// find a Writable slot, starting with theFirstWritable and going right
while (shared->theSize < shared->theCapacity) {
const Offset idx = shared->theFirstWritable;
typedef unsigned int Offset; ///< stack index type
struct Shared {
- Shared(const unsigned int theCapacity);
+ Shared(const unsigned int aCapacity);
// these help iterate the stack in search of a free spot or a page
Offset next(const Offset idx) const { return (idx + 1) % theCapacity; }
*/
#include "config.h"
+#include "base/TextException.h"
+#include "ipc/mem/PagePool.h"
#include "ipc/mem/Pages.h"
+#include "structs.h"
+#include "SwapDir.h"
-// TODO: Implement using a single PagePool instance, for now.
+// Uses a single PagePool instance, for now.
// Eventually, we may have pools dedicated to memory caching, disk I/O, etc.
+
+// TODO: make pool id more unique so it does not conflict with other Squids?
+static const String PagePoolId = "squid-page-pool";
+static Ipc::Mem::PagePool *ThePagePool = 0;
+
+// XXX: temporary function until we have a better page size handling
+static unsigned int
+calculatePageSize()
+{
+ unsigned int max_objsize = 0;
+ for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
+ const SwapDir *const sd = dynamic_cast<SwapDir *>(INDEXSD(i));
+ if (sd->max_objsize > max_objsize)
+ max_objsize = sd->max_objsize;
+ }
+ return max_objsize;
+}
+
+void
+Ipc::Mem::Init()
+{
+ Must(!ThePagePool);
+ // XXX: pool capacity and page size should be configurable/meaningful
+ ThePagePool = new PagePool(PagePoolId, 1024, calculatePageSize());
+}
+
+void
+Ipc::Mem::Attach()
+{
+ Must(!ThePagePool);
+ // TODO: make pool id more unique so it does not conflict with other Squid instances?
+ ThePagePool = new PagePool(PagePoolId);
+}
+
+bool
+Ipc::Mem::GetPage(PageId &page)
+{
+ Must(ThePagePool);
+ return ThePagePool->get(page);
+}
+
+void
+Ipc::Mem::PutPage(PageId &page)
+{
+ Must(ThePagePool);
+ ThePagePool->put(page);
+}
+
+void *
+Ipc::Mem::PagePointer(const PageId &page)
+{
+ Must(ThePagePool);
+ return ThePagePool->pagePointer(page);
+}
bool GetPage(PageId &page);
/// makes identified page available as a free page to future GetPage() callers
-void PutPage(const PageId &page);
+void PutPage(PageId &page);
/// converts page handler into a temporary writeable shared memory pointer
void *PagePointer(const PageId &page);