From: Dmitry Kurochkin Date: Wed, 6 Apr 2011 13:23:03 +0000 (+0400) Subject: Initial shared memory pages implementation. X-Git-Tag: take06~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=56f8aa5058c31c5483ac494c124c2329fb8bc2a4;p=thirdparty%2Fsquid.git Initial shared memory pages implementation. --- diff --git a/src/ipc/mem/Page.cc b/src/ipc/mem/Page.cc index 377b9bd53c..e1fb96c88c 100644 --- a/src/ipc/mem/Page.cc +++ b/src/ipc/mem/Page.cc @@ -8,4 +8,12 @@ #include "config.h" #include "ipc/mem/Page.h" -// TODO: implement +#if HAVE_IOSTREAM +#include +#endif + + +std::ostream &Ipc::Mem::operator <<(std::ostream &os, const PageId &page) +{ + return os << "sh_page" << page.pool << '.' << page.number; +} diff --git a/src/ipc/mem/Page.h b/src/ipc/mem/Page.h index cebce9f3eb..fabab730a7 100644 --- a/src/ipc/mem/Page.h +++ b/src/ipc/mem/Page.h @@ -17,10 +17,10 @@ namespace Mem { /// 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 }; diff --git a/src/ipc/mem/PagePool.cc b/src/ipc/mem/PagePool.cc index 5fb2288b17..f04da8db50 100644 --- a/src/ipc/mem/PagePool.cc +++ b/src/ipc/mem/PagePool.cc @@ -6,6 +6,78 @@ */ #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(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 +} diff --git a/src/ipc/mem/PagePool.h b/src/ipc/mem/PagePool.h index 6bdf638a57..fdccf89357 100644 --- a/src/ipc/mem/PagePool.h +++ b/src/ipc/mem/PagePool.h @@ -6,33 +6,51 @@ #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 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 diff --git a/src/ipc/mem/PageStack.cc b/src/ipc/mem/PageStack.cc index bd11aa7023..a31d774f2b 100644 --- a/src/ipc/mem/PageStack.cc +++ b/src/ipc/mem/PageStack.cc @@ -71,6 +71,7 @@ void 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; diff --git a/src/ipc/mem/PageStack.h b/src/ipc/mem/PageStack.h index ae3b9b0712..d7a8bd7fe9 100644 --- a/src/ipc/mem/PageStack.h +++ b/src/ipc/mem/PageStack.h @@ -34,7 +34,7 @@ private: 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; } diff --git a/src/ipc/mem/Pages.cc b/src/ipc/mem/Pages.cc index 83d4655f32..4b95a08d21 100644 --- a/src/ipc/mem/Pages.cc +++ b/src/ipc/mem/Pages.cc @@ -6,7 +6,65 @@ */ #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(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); +} diff --git a/src/ipc/mem/Pages.h b/src/ipc/mem/Pages.h index f6c4a1e521..c18e14903c 100644 --- a/src/ipc/mem/Pages.h +++ b/src/ipc/mem/Pages.h @@ -25,7 +25,7 @@ void Attach(); 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);