diff --git a/src/lib/allocationcluster.cpp b/src/lib/allocationcluster.cpp index 1f76fed72..306e4a659 100644 --- a/src/lib/allocationcluster.cpp +++ b/src/lib/allocationcluster.cpp @@ -1,5 +1,5 @@ /* - AllocationCluster - allocating and owning a pile of objects + AllocationCluster - allocating and owning a pile of objects Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -25,9 +25,8 @@ #include "common/error.hpp" #include "common/util.hpp" - using util::isnil; -//using util::cStr; + namespace lib { @@ -47,7 +46,7 @@ namespace lib { * the dtor without actually knowing the object's type. * * @todo this is a preliminary or pseudo-implementation based on - * a vector of smart pointers, i.e. actually the objects are heap + * a vector of raw pointers, i.e. actually the objects are heap * allocated. What actually should happen is for the MemoryManager to * allocate raw memory chunk wise, sub partition it and place the objects * into this private memory buffer. Further, possibly we could maintain @@ -76,7 +75,7 @@ namespace lib { private: void clearStorage(); }; - + void @@ -98,7 +97,7 @@ namespace lib { AllocationCluster::MemoryManager::purge() { Thread::Lock guard SIDEEFFECT; - + REQUIRE (type_.killIt, "we need a deleter function"); REQUIRE (0 < type_.allocSize, "allocation size unknown"); REQUIRE (top_ == mem_.size() || (top_+1) == mem_.size()); @@ -116,7 +115,7 @@ namespace lib { delete[] mem_[--i]; mem_.clear(); } - + inline void* AllocationCluster::MemoryManager::allocate() @@ -125,10 +124,11 @@ namespace lib { REQUIRE (0 < type_.allocSize); REQUIRE (top_ <= mem_.size()); - + if (top_==mem_.size()) mem_.resize(top_+1); - if (!mem_[top_]) + + if (!mem_[top_]) // re-use existing allocation, if any mem_[top_] = new char[type_.allocSize]; ENSURE (top_ < mem_.size()); @@ -141,7 +141,7 @@ namespace lib { AllocationCluster::MemoryManager::commit (void* pendingAlloc) { Thread::Lock guard SIDEEFFECT; - + REQUIRE (pendingAlloc); ASSERT (top_ < mem_.size()); ASSERT (pendingAlloc == mem_[top_], "allocation protocol violated"); @@ -155,8 +155,8 @@ namespace lib { /** storage for static bookkeeping of type allocation slots */ size_t AllocationCluster::maxTypeIDs; - - + + /** creating a new AllocationCluster prepares a table capable * of holding the individual object families to come. Each of those * is managed by a separate instance of the low-level memory manager. @@ -224,7 +224,7 @@ namespace lib { } ASSERT (handler(slot)); - return initiateAlloc(slot); + return initiateAlloc(slot); } diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 05226ef0a..a44151957 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -1,5 +1,5 @@ /* - ALLOCATIONCLUSTER.hpp - allocating and owning a pile of objects + ALLOCATIONCLUSTER.hpp - allocating and owning a pile of objects Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -53,7 +53,6 @@ #include "common/multithread.hpp" #include "common/error.hpp" -//#include "common/util.hpp" #include "lib/scopedholder.hpp" #include "lib/scopedholdertransfer.hpp" @@ -69,11 +68,14 @@ namespace lib { * Each of those contains a initially undetermined (but rather large) * number of individual objects, which can be expected to be allocated * within a short timespan and which are to be released cleanly on - * destruction of the AllocationCluster. There is a service creating - * individual objects with arbitrary ctor parameters and it is possible - * to control the oder in which the object families are to be discarded. + * destruction of the AllocationCluster. We provide a service creating + * individual objects with arbitrary ctor parameters. * @warning make sure the objects dtors aren't called and object references * aren't used after shutting down a given AllocationCluster. + * @todo implement a facility to control the oder in which + * the object families are to be discarded. Currently + * they are just purged in reverse order defined by + * the first request for allocating a certain type. */ class AllocationCluster : boost::noncopyable @@ -83,6 +85,7 @@ namespace lib { AllocationCluster (); ~AllocationCluster () throw(); + template TY& create () @@ -122,7 +125,7 @@ namespace lib { TY* obj = new(allocation()) TY (p0,p1,p2,p3); return commit(obj); } - + private: /** initiate an allocation for the given type */ @@ -160,7 +163,9 @@ namespace lib { typedef ScopedPtrHolder HMemManager; typedef Allocator_TransferNoncopyable Allo; typedef std::vector ManagerTable; - ManagerTable typeHandlers_; + + ManagerTable typeHandlers_; ///< table of active MemoryManager instances + HMemManager& handler (size_t slot) @@ -174,7 +179,7 @@ namespace lib { void* initiateAlloc (size_t& slot); void* initiateAlloc (TypeInfo type, size_t& slot); - /** enrol the allocation after successful ctor call */ + /** enrol the allocation after successful ctor call */ void finishAlloc (size_t& slot, void*); }; @@ -188,7 +193,7 @@ namespace lib { struct AllocationCluster::TypeInfo { size_t allocSize; - void (*killIt)(void*); + void (*killIt)(void*); ///< deleter function template TypeInfo(TY*) @@ -203,11 +208,11 @@ namespace lib { }; - + template struct AllocationCluster::TypeSlot { - static size_t id_; ///< table pos of the memory manager in charge for type TY + static size_t id_; ///< table pos+1 of the memory manager in charge for type TY static size_t & get() @@ -241,7 +246,7 @@ namespace lib { template size_t AllocationCluster::TypeSlot::id_; - + template inline void* @@ -253,7 +258,7 @@ namespace lib { ENSURE (mem); return mem; } - + template inline TY& AllocationCluster::commit (TY* obj) diff --git a/tests/50components.tests b/tests/50components.tests index 71f4a5d51..4f505c5f6 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -10,6 +10,11 @@ return: 0 END +TEST "AllocationCluster_test" AllocationCluster_test <... +out: . +out: ..install one element at index[0] +out: . +out: ..*** resize table to 16 elements +out: . +out: .throw some exceptions... out: checking ScopedPtrHolder... +out: . +out: ..install one element at index[0] +out: . +out: ..*** resize table to 16 elements +out: . +out: .throw some exceptions... END diff --git a/tests/common/allocationclustertest.cpp b/tests/common/allocationclustertest.cpp index 4b5d1f458..2d634ac37 100644 --- a/tests/common/allocationclustertest.cpp +++ b/tests/common/allocationclustertest.cpp @@ -40,6 +40,8 @@ using ::Test; using std::numeric_limits; using std::vector; + + namespace lib { namespace test { @@ -49,7 +51,8 @@ namespace lib { uint NUM_OBJECTS = 500; uint NUM_FAMILIES = 5; - long checksum = 0; + long checksum = 0; // validate proper pairing of ctor/dtor calls + bool randomFailures = false; template class Dummy @@ -67,7 +70,7 @@ namespace lib { char id = i1 + i2 + i3; content[0] = id; checksum += id; - if (0 == (rand() % 20)) + if (randomFailures && 0 == (rand() % 20)) throw id; } @@ -137,6 +140,7 @@ namespace lib { } + /************************************************************************* * @test verify the proper workings of our custom allocation scheme * managing families of interconnected objects for the segments @@ -182,6 +186,7 @@ namespace lib { // all created objects dtors will be invoked. } + void checkAllocation() { @@ -194,11 +199,14 @@ namespace lib { ASSERT (0==checksum); } + void checkErrorHandling() { ASSERT (0==checksum); { + randomFailures = true; + AllocationCluster clu; for (uint i=0; i