Refactoring III: Recursive/Nonrecursive and Waitable as policy classes
pass test again
This commit is contained in:
parent
1ff7f0c656
commit
54e88e6914
9 changed files with 82 additions and 83 deletions
|
|
@ -81,7 +81,7 @@ namespace lib {
|
|||
void
|
||||
AllocationCluster::MemoryManager::reset (TypeInfo info)
|
||||
{
|
||||
Sync::ClassLock<MemoryManager> guard();
|
||||
Sync<>::ClassLock<MemoryManager> guard();
|
||||
|
||||
if (0 < mem_.size()) purge();
|
||||
type_ = info;
|
||||
|
|
@ -96,7 +96,7 @@ namespace lib {
|
|||
void
|
||||
AllocationCluster::MemoryManager::purge()
|
||||
{
|
||||
Sync::ClassLock<MemoryManager> guard();
|
||||
Sync<>::ClassLock<MemoryManager> guard();
|
||||
|
||||
REQUIRE (type_.killIt, "we need a deleter function");
|
||||
REQUIRE (0 < type_.allocSize, "allocation size unknown");
|
||||
|
|
@ -120,7 +120,7 @@ namespace lib {
|
|||
inline void*
|
||||
AllocationCluster::MemoryManager::allocate()
|
||||
{
|
||||
Sync::ClassLock<MemoryManager> guard();
|
||||
Sync<>::ClassLock<MemoryManager> guard();
|
||||
|
||||
REQUIRE (0 < type_.allocSize);
|
||||
REQUIRE (top_ <= mem_.size());
|
||||
|
|
@ -140,7 +140,7 @@ namespace lib {
|
|||
inline void
|
||||
AllocationCluster::MemoryManager::commit (void* pendingAlloc)
|
||||
{
|
||||
Sync::ClassLock<MemoryManager> guard();
|
||||
Sync<>::ClassLock<MemoryManager> guard();
|
||||
|
||||
REQUIRE (pendingAlloc);
|
||||
ASSERT (top_ < mem_.size());
|
||||
|
|
@ -175,7 +175,7 @@ namespace lib {
|
|||
{
|
||||
try
|
||||
{
|
||||
Sync::ClassLock<AllocationCluster> guard();
|
||||
Sync<>::ClassLock<AllocationCluster> guard();
|
||||
|
||||
TRACE (memory, "shutting down AllocationCluster");
|
||||
for (size_t i = typeHandlers_.size(); 0 < i; --i)
|
||||
|
|
@ -214,7 +214,7 @@ namespace lib {
|
|||
ASSERT (0 < slot);
|
||||
|
||||
{
|
||||
Sync::ClassLock<AllocationCluster> guard(); /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class?
|
||||
Sync<>::ClassLock<AllocationCluster> guard(); /////TODO: decide tradeoff: lock just the instance, or lock the AllocationCluster class?
|
||||
|
||||
if (slot > typeHandlers_.size())
|
||||
typeHandlers_.resize(slot);
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ namespace lib {
|
|||
static TypeInfo
|
||||
setup()
|
||||
{
|
||||
Sync::ClassLock<AllocationCluster> guard();
|
||||
Sync<>::ClassLock<AllocationCluster> guard();
|
||||
if (!id_)
|
||||
id_= ++maxTypeIDs;
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ namespace lumiera
|
|||
struct Multithreaded
|
||||
{
|
||||
typedef volatile S VolatileType;
|
||||
typedef lib::Sync::ClassLock<S> Lock;
|
||||
typedef lib::Sync<>::ClassLock<S> Lock;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
137
src/lib/sync.hpp
137
src/lib/sync.hpp
|
|
@ -121,6 +121,12 @@ namespace lib {
|
|||
class Mutex
|
||||
: protected MTX
|
||||
{
|
||||
protected:
|
||||
using MTX::mutex;
|
||||
using MTX::__may_block;
|
||||
using MTX::__enter;
|
||||
using MTX::__leave;
|
||||
|
||||
public:
|
||||
void
|
||||
acquire()
|
||||
|
|
@ -151,6 +157,10 @@ namespace lib {
|
|||
class Condition
|
||||
: public Mutex<CDX>
|
||||
{
|
||||
protected:
|
||||
using CDX::cond;
|
||||
using CDX::mutex;
|
||||
|
||||
public:
|
||||
void
|
||||
signal (bool wakeAll=false)
|
||||
|
|
@ -162,9 +172,9 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
template<class BF, class MTX>
|
||||
template<class BF>
|
||||
bool
|
||||
wait (BF& predicate, MTX& mtx, Timeout& waitEndTime)
|
||||
wait (BF& predicate, Timeout& waitEndTime)
|
||||
{
|
||||
int err=0;
|
||||
while (!predicate() && !err)
|
||||
|
|
@ -210,32 +220,8 @@ namespace lib {
|
|||
operator bool() { return 0 != tv_sec; } // allows if (timeout_)....
|
||||
};
|
||||
|
||||
|
||||
typedef volatile bool& Flag;
|
||||
|
||||
class Monitor
|
||||
: Condition<Wrapped_LumieraExcCond> /////////TODO: to be refactored. This is just one example, using the non-recursive condition
|
||||
{
|
||||
Timeout timeout_;
|
||||
|
||||
//////TODO my intention is to make two variants of the monitor, where the simple one leaves out the condition part
|
||||
|
||||
public:
|
||||
Monitor() {}
|
||||
~Monitor() {}
|
||||
|
||||
void acquireLock() { acquire(); }
|
||||
void releaseLock() { release(); }
|
||||
|
||||
void signal(bool a){ signal(a); }
|
||||
|
||||
inline bool wait (Flag, ulong);
|
||||
inline void setTimeout(ulong);
|
||||
inline bool isTimedWait();
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct BoolFlagPredicate
|
||||
{
|
||||
Flag flag_;
|
||||
|
|
@ -244,25 +230,48 @@ namespace lib {
|
|||
bool operator() () { return flag_; }
|
||||
};
|
||||
|
||||
|
||||
template<class IMPL>
|
||||
class Monitor
|
||||
: IMPL
|
||||
{
|
||||
Timeout timeout_;
|
||||
|
||||
public:
|
||||
Monitor() {}
|
||||
~Monitor() {}
|
||||
|
||||
void acquireLock() { IMPL::acquire(); }
|
||||
void releaseLock() { IMPL::release(); }
|
||||
|
||||
void signal(bool a){ IMPL::signal(a); }
|
||||
|
||||
bool wait (Flag flag, ulong timedwait=0)
|
||||
{
|
||||
BoolFlagPredicate checkFlag(flag);
|
||||
return IMPL::wait(checkFlag, timeout_.setOffset(timedwait));
|
||||
}
|
||||
|
||||
void setTimeout(ulong relative) {timeout_.setOffset(relative);}
|
||||
bool isTimedWait() {return (timeout_);}
|
||||
};
|
||||
|
||||
bool
|
||||
Monitor::wait (Flag flag, ulong timedwait)
|
||||
{
|
||||
BoolFlagPredicate checkFlag(flag);
|
||||
return cond_.wait(checkFlag, mtx_, timeout_.setOffset(timedwait));
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::setTimeout (ulong relative) {timeout_.setOffset(relative);}
|
||||
|
||||
bool
|
||||
Monitor::isTimedWait () {return (timeout_);}
|
||||
typedef Mutex<Wrapped_LumieraExcMutex> NonrecursiveLock_NoWait;
|
||||
typedef Mutex<Wrapped_LumieraRecMutex> RecursiveLock_NoWait;
|
||||
typedef Condition<Wrapped_LumieraExcCond> NonrecursiveLock_Waitable;
|
||||
typedef Condition<Wrapped_LumieraRecCond> RecursiveLock_Waitable;
|
||||
|
||||
|
||||
} // namespace sync (helpers and building blocks)
|
||||
|
||||
|
||||
|
||||
using sync::NonrecursiveLock_NoWait;
|
||||
using sync::NonrecursiveLock_Waitable;
|
||||
using sync::RecursiveLock_NoWait;
|
||||
using sync::RecursiveLock_Waitable;
|
||||
|
||||
|
||||
/**
|
||||
* Facility for monitor object based locking.
|
||||
* To be attached either on a per class base or per object base.
|
||||
|
|
@ -274,18 +283,33 @@ namespace lib {
|
|||
*
|
||||
* @todo actually implement this facility using the Lumiera backend.
|
||||
*/
|
||||
template<class CONF = NonrecursiveLock_NoWait>
|
||||
struct Sync
|
||||
{
|
||||
typedef sync::Monitor Monitor;
|
||||
|
||||
typedef sync::Monitor<CONF> Monitor;
|
||||
Monitor objectMonitor_;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////TODO: factor out the recursive/non-recursive mutex case as policy...
|
||||
static Monitor&
|
||||
getMonitor(Sync* forThis)
|
||||
{
|
||||
REQUIRE (forThis);
|
||||
return forThis->objectMonitor_;
|
||||
}
|
||||
|
||||
template<class X>
|
||||
static inline Monitor& getMonitor();
|
||||
|
||||
static inline Monitor& getMonitor(Sync* forThis);
|
||||
static Monitor&
|
||||
getMonitor()
|
||||
{
|
||||
//TODO: a rather obscure race condition is hidden here:
|
||||
//TODO: depending on the build order, the dtor of this static variable may be called, while another thread is still holding an ClassLock.
|
||||
//TODO: An possible solution would be to use an shared_ptr to the Monitor in case of a ClassLock and to protect access with another Mutex.
|
||||
//TODO. But I am really questioning if we can't ignore this case and state: "don't hold a ClassLock when your code maybe still running in shutdown phase!"
|
||||
//TODO: probably best Idea is to detect this situation in DEBUG or ALPHA mode
|
||||
|
||||
static scoped_ptr<Monitor> classMonitor_ (0);
|
||||
if (!classMonitor_) classMonitor_.reset (new Monitor ());
|
||||
return *classMonitor_;
|
||||
}
|
||||
|
||||
|
||||
class Lock
|
||||
|
|
@ -316,31 +340,6 @@ namespace lib {
|
|||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Sync::Monitor&
|
||||
Sync::getMonitor(Sync* forThis)
|
||||
{
|
||||
REQUIRE (forThis);
|
||||
return forThis->objectMonitor_;
|
||||
}
|
||||
|
||||
template<class X>
|
||||
Sync::Monitor&
|
||||
Sync::getMonitor()
|
||||
{
|
||||
//TODO: a rather obscure race condition is hidden here:
|
||||
//TODO: depending on the build order, the dtor of this static variable may be called, while another thread is still holding an ClassLock.
|
||||
//TODO: An possible solution would be to use an shared_ptr to the Monitor in case of a ClassLock and to protect access with another Mutex.
|
||||
//TODO. But I am really questioning if we can't ignore this case and state: "don't hold a ClassLock when your code maybe still running in shutdown phase!"
|
||||
//TODO: probably best Idea is to detect this situation in DEBUG or ALPHA mode
|
||||
|
||||
static scoped_ptr<Monitor> classMonitor_ (0);
|
||||
if (!classMonitor_) classMonitor_.reset (new Monitor ());
|
||||
return *classMonitor_;
|
||||
}
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace lumiera {
|
|||
static void
|
||||
generateID (size_t& id)
|
||||
{
|
||||
Sync::ClassLock<Tag> guard();
|
||||
Sync<>::ClassLock<Tag> guard();
|
||||
if (!id)
|
||||
id = ++lastRegisteredID;
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ namespace lumiera {
|
|||
void
|
||||
accomodate (size_t index)
|
||||
{
|
||||
Sync::ClassLock<Dispatcher> guard();
|
||||
Sync<>::ClassLock<Dispatcher> guard();
|
||||
if (index > table_.size())
|
||||
table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ namespace asset
|
|||
TODO ("check validity of Ident Category");
|
||||
ID<KIND> asset_id (getID (idi));
|
||||
|
||||
Sync::ClassLock<DB> guard();
|
||||
Sync<>::ClassLock<DB> guard();
|
||||
TODO ("handle duplicate Registrations");
|
||||
P<KIND> smart_ptr (obj, &destroy);
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ namespace mobject {
|
|||
static void
|
||||
createSlot (Table& table)
|
||||
{
|
||||
Sync::ClassLock<TableEntry> guard();
|
||||
Sync<>::ClassLock<TableEntry> guard();
|
||||
if (!index)
|
||||
index = ++maxSlots;
|
||||
if (index > table.size())
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace lib {
|
|||
|
||||
|
||||
class Victim
|
||||
: public Sync
|
||||
: public Sync<RecursiveLock_NoWait>
|
||||
{
|
||||
volatile long cnt_[NUM_COUNTERS];
|
||||
volatile uint step_; ///< @note stored as instance variable
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace lib {
|
|||
|
||||
class SyncOnBool
|
||||
: public Token,
|
||||
public Sync
|
||||
public Sync<NonrecursiveLock_Waitable>
|
||||
{
|
||||
bool got_new_data_;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue