Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1079 lines
33 KiB

2 years ago
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkGarbageCollector.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkGarbageCollector.h"
#include "vtkMultiThreader.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointerBase.h"
#include <vtkstd/queue>
#include <vtkstd/stack>
#include <vtkstd/vector>
// Leave the hashing version off for now.
#define VTK_GARBAGE_COLLECTOR_HASH 0
#if VTK_GARBAGE_COLLECTOR_HASH
# include <vtksys/hash_set.hxx>
# include <vtksys/hash_map.hxx>
#else
# include <vtkstd/map>
# include <vtkstd/set>
#endif
#include <assert.h>
vtkCxxRevisionMacro(vtkGarbageCollector, "$Revision: 1.28.4.2 $");
vtkStandardNewMacro(vtkGarbageCollector);
#if VTK_GARBAGE_COLLECTOR_HASH
struct vtkGarbageCollectorHash
{
size_t operator()(void* p) const { return reinterpret_cast<size_t>(p); }
};
#endif
class vtkGarbageCollectorSingleton;
//----------------------------------------------------------------------------
// The garbage collector singleton. In order to support delayed
// collection vtkObjectBase::UnRegister passes references to the
// singleton instead of decrementing the reference count. At some
// point collection occurs and accounts for these references. This
// MUST be default initialized to zero by the compiler and is
// therefore not initialized here. The ClassInitialize and
// ClassFinalize methods handle this instance.
static vtkGarbageCollectorSingleton* vtkGarbageCollectorSingletonInstance;
//----------------------------------------------------------------------------
// Global debug setting. This flag specifies whether a collector
// should print debugging output. This must be default initialized to
// zero by the compiler and is therefore not initialized here. The
// ClassInitialize and ClassFinalize methods handle it.
static int vtkGarbageCollectorGlobalDebugFlag;
//----------------------------------------------------------------------------
// The thread identifier of the main thread. Delayed garbage
// collection is supported only for objects in the main thread. This
// is initialized when the program loads. All garbage collection
// calls test whether they are called from this thread. If not, no
// references are accepted by the singleton. This must be default
// initialized to zero by the compiler and is therefore not
// initialized here. The ClassInitialize and ClassFinalize methods
// handle it.
static vtkMultiThreaderIDType vtkGarbageCollectorMainThread;
//----------------------------------------------------------------------------
vtkGarbageCollector::vtkGarbageCollector()
{
}
//----------------------------------------------------------------------------
vtkGarbageCollector::~vtkGarbageCollector()
{
this->SetReferenceCount(0);
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::SetGlobalDebugFlag(int flag)
{
vtkGarbageCollectorGlobalDebugFlag = flag;
}
//----------------------------------------------------------------------------
int vtkGarbageCollector::GetGlobalDebugFlag()
{
return vtkGarbageCollectorGlobalDebugFlag;
}
//----------------------------------------------------------------------------
// Friendship interface listing non-public methods the garbage
// collector can call on vtkObjectBase.
class vtkGarbageCollectorToObjectBaseFriendship
{
public:
static void ReportReferences(vtkGarbageCollector* self, vtkObjectBase* obj)
{
obj->ReportReferences(self);
}
static void RegisterBase(vtkObjectBase* obj)
{
// Call vtkObjectBase::RegisterInternal directly to make sure the
// object does not try to report the call back to the garbage
// collector and no debugging output is shown.
obj->vtkObjectBase::RegisterInternal(0, 0);
}
static void UnRegisterBase(vtkObjectBase* obj)
{
// Call vtkObjectBase::UnRegisterInternal directly to make sure
// the object does not try to report the call back to the garbage
// collector and no debugging output is shown.
obj->vtkObjectBase::UnRegisterInternal(0, 0);
}
static void Register(vtkObjectBase* obj, vtkObjectBase* from)
{
// Call RegisterInternal directly to make sure the object does not
// try to report the call back to the garbage collector.
obj->RegisterInternal(from, 0);
}
static void UnRegister(vtkObjectBase* obj, vtkObjectBase* from)
{
// Call UnRegisterInternal directly to make sure the object does
// not try to report the call back to the garbage collector.
obj->UnRegisterInternal(from, 0);
}
};
//----------------------------------------------------------------------------
// Function to test whether caller is the main thread.
static int vtkGarbageCollectorIsMainThread()
{
return
vtkMultiThreader::ThreadsEqual(vtkGarbageCollectorMainThread,
vtkMultiThreader::GetCurrentThreadID());
}
//----------------------------------------------------------------------------
// Singleton to hold discarded references.
class vtkGarbageCollectorSingleton
{
public:
vtkGarbageCollectorSingleton();
~vtkGarbageCollectorSingleton();
// Internal implementation of vtkGarbageCollector::GiveReference.
int GiveReference(vtkObjectBase* obj);
// Internal implementation of vtkGarbageCollector::TakeReference.
int TakeReference(vtkObjectBase* obj);
// Called by GiveReference to decide whether to accept a reference.
int CheckAccept();
// Push/Pop deferred collection.
void DeferredCollectionPush();
void DeferredCollectionPop();
// Map from object to number of stored references.
#if VTK_GARBAGE_COLLECTOR_HASH
typedef vtksys::hash_map<vtkObjectBase*, int, vtkGarbageCollectorHash>
ReferencesType;
#else
typedef vtkstd::map<vtkObjectBase*, int> ReferencesType;
#endif
ReferencesType References;
// The number of references stored in the map.
int TotalNumberOfReferences;
// The number of times DeferredCollectionPush has been called not
// matched by a DeferredCollectionPop.
int DeferredCollectionCount;
};
//----------------------------------------------------------------------------
// Internal implementation subclass.
class vtkGarbageCollectorImpl: public vtkGarbageCollector
{
public:
vtkTypeMacro(vtkGarbageCollectorImpl, vtkGarbageCollector);
vtkGarbageCollectorImpl();
~vtkGarbageCollectorImpl();
// Description:
// Prevent normal vtkObject reference counting behavior.
virtual void Register(vtkObjectBase*);
// Description:
// Prevent normal vtkObject reference counting behavior.
virtual void UnRegister(vtkObjectBase*);
// Perform a collection check.
void CollectInternal(vtkObjectBase* root);
// Sun's compiler is broken and does not allow access to protected members from
// nested class
// protected:
//--------------------------------------------------------------------------
// Internal data structure types.
#if VTK_GARBAGE_COLLECTOR_HASH
typedef vtksys::hash_map<vtkObjectBase*, int, vtkGarbageCollectorHash>
ReferencesType;
#else
typedef vtkstd::map<vtkObjectBase*, int> ReferencesType;
#endif
struct ComponentType;
struct Entry;
struct EntryEdge
{
Entry* Reference;
void* Pointer;
EntryEdge(Entry* r, void* p): Reference(r), Pointer(p) {}
};
// Store garbage collection entries keyed by object.
struct Entry
{
Entry(vtkObjectBase* obj): Object(obj), Root(0), Component(0),
VisitOrder(0), Count(0), GarbageCount(0),
References() {}
~Entry() { assert(this->GarbageCount == 0); }
// The object corresponding to this entry.
vtkObjectBase* Object;
// The candidate root for the component containing this object.
Entry* Root;
// The component to which the object is assigned, if any.
ComponentType* Component;
// Mark the order in which object's are visited by Tarjan's algorithm.
int VisitOrder;
// The number of references from outside the component not
// counting the garbage collector references.
int Count;
// The number of references held by the garbage collector.
int GarbageCount;
// The list of references reported by this entry's object.
typedef vtkstd::vector<EntryEdge> ReferencesType;
ReferencesType References;
};
// Compare entries by object pointer for quick lookup.
#if VTK_GARBAGE_COLLECTOR_HASH
struct EntryCompare
{
vtkstd_bool operator()(Entry* l, Entry* r) const
{ return l->Object == r->Object; }
};
struct EntryHash
{
size_t operator()(Entry* e) const
{ return e?reinterpret_cast<size_t>(e->Object):0; }
};
#else
struct EntryCompare
{
vtkstd::less<vtkObjectBase*> Compare;
vtkstd_bool operator()(Entry* l, Entry* r) const
{ return Compare(l->Object, r->Object); }
};
#endif
// Represent a strongly connected component of the reference graph.
typedef vtkstd::vector<Entry*> ComponentBase;
struct ComponentType: public ComponentBase
{
typedef ComponentBase::iterator iterator;
ComponentType(): NetCount(0), Identifier(0) {}
~ComponentType()
{ for(iterator i = begin(); i != end(); ++i) { (*i)->Component = 0; } }
// The net reference count of the component.
int NetCount;
// The component identifier.
int Identifier;
};
//--------------------------------------------------------------------------
// Internal data objects.
// The set of objects that have been visited.
#if VTK_GARBAGE_COLLECTOR_HASH
typedef vtksys::hash_set<Entry*, EntryHash, EntryCompare> VisitedType;
#else
typedef vtkstd::set<Entry*, EntryCompare> VisitedType;
#endif
VisitedType Visited;
// Count the number of components found to give each an identifier
// for use in debugging messages.
int NumberOfComponents;
// The set of components found that have not yet leaked.
#if VTK_GARBAGE_COLLECTOR_HASH
typedef vtksys::hash_set<ComponentType*, vtkGarbageCollectorHash>
ComponentsType;
#else
typedef vtkstd::set<ComponentType*> ComponentsType;
#endif
ComponentsType ReferencedComponents;
// Queue leaked components for deletion.
vtkstd::queue<ComponentType*> LeakedComponents;
// The stack of objects forming the connected components. This is
// used in the implementation of Tarjan's algorithm.
vtkstd::stack<Entry*> Stack;
// The object whose references are currently being traced by
// Tarjan's algorithm. Used during the ReportReferences callback.
Entry* Current;
// Count for visit order of Tarjan's algorithm.
int VisitCount;
// The singleton instance from which to take references when passing
// references to the entries.
vtkGarbageCollectorSingleton* Singleton;
//--------------------------------------------------------------------------
// Internal implementation methods.
// Walk the reference graph using Tarjan's algorithm to identify
// strongly connected components.
void FindComponents(vtkObjectBase* root);
// Get the entry for the given object. This may visit the object.
Entry* MaybeVisit(vtkObjectBase*);
// Node visitor for Tarjan's algorithm.
Entry* VisitTarjan(vtkObjectBase*);
// Callback from objects to report references.
void Report(vtkObjectBase* obj, void* ptr);
virtual void Report(vtkObjectBase* obj, void* ptr, const char* desc);
// Collect the objects of the given leaked component.
void CollectComponent(ComponentType* c);
// Print the given component as a debugging message.
void PrintComponent(ComponentType* c);
// Subtract references the component holds to itself.
void SubtractInternalReferences(ComponentType* c);
// Subtract references the component holds to other components.
void SubtractExternalReferences(ComponentType* c);
// Subtract one reference from the given entry. If the entry's
// component is left with no references, it is queued as a leaked
// component.
void SubtractReference(Entry* e);
// Transfer references from the garbage collector to the entry for
// its object.
void PassReferencesToEntry(Entry* e);
// Flush all collector references to the object in an entry.
void FlushEntryReferences(Entry* e);
private:
vtkGarbageCollectorImpl(const vtkGarbageCollectorImpl&); // Not implemented.
void operator=(const vtkGarbageCollectorImpl&); // Not implemented.
};
//----------------------------------------------------------------------------
vtkGarbageCollectorImpl::vtkGarbageCollectorImpl()
{
// Set debugging state.
this->SetDebug(vtkGarbageCollectorGlobalDebugFlag);
// Take references from the singleton only in the main thread.
if(vtkGarbageCollectorIsMainThread())
{
this->Singleton = vtkGarbageCollectorSingletonInstance;
}
else
{
this->Singleton = 0;
}
// Initialize reference graph walk implementation.
this->VisitCount = 0;
this->Current = 0;
this->NumberOfComponents = 0;
}
//----------------------------------------------------------------------------
vtkGarbageCollectorImpl::~vtkGarbageCollectorImpl()
{
// The collector implementation should have left these empty.
assert(this->Current == 0);
assert(this->Stack.empty());
assert(this->LeakedComponents.empty());
// Clear component list.
for(ComponentsType::iterator c = this->ReferencedComponents.begin();
c != this->ReferencedComponents.end(); ++c)
{
delete *c;
}
this->ReferencedComponents.clear();
// Clear visited list.
for(VisitedType::iterator v = this->Visited.begin();
v != this->Visited.end();)
{
// Increment the iterator before deleting because the hash table
// compare function dereferences the pointer.
delete *v++;
}
this->Visited.clear();
// Disable debugging to avoid destruction message.
this->SetDebug(0);
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::Register(vtkObjectBase*)
{
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::UnRegister(vtkObjectBase*)
{
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::CollectInternal(vtkObjectBase* root)
{
// Identify strong components.
this->FindComponents(root);
// Delete all the leaked components.
while(!this->LeakedComponents.empty())
{
// Get the next leaked component.
ComponentType* c = this->LeakedComponents.front();
this->LeakedComponents.pop();
// Subtract this component's references to other components. This
// may cause others to be queued.
this->SubtractExternalReferences(c);
// Collect the members of this component.
this->CollectComponent(c);
// We are done with this component.
delete c;
}
// Print remaining referenced components for debugging.
for(ComponentsType::iterator i = this->ReferencedComponents.begin();
i != this->ReferencedComponents.end(); ++i)
{
this->PrintComponent(*i);
}
// Flush remaining references owned by entries in referenced
// components.
for(ComponentsType::iterator c = this->ReferencedComponents.begin();
c != this->ReferencedComponents.end(); ++c)
{
for(ComponentType::iterator j = (*c)->begin(); j != (*c)->end(); ++j)
{
this->FlushEntryReferences(*j);
}
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::FindComponents(vtkObjectBase* root)
{
// Walk the references from the given object, if any.
if(root)
{
this->MaybeVisit(root);
}
}
//----------------------------------------------------------------------------
vtkGarbageCollectorImpl::Entry*
vtkGarbageCollectorImpl::MaybeVisit(vtkObjectBase* obj)
{
// Check for an existing entry.
assert(obj != 0);
Entry e(obj);
VisitedType::iterator i = this->Visited.find(&e);
if(i == this->Visited.end())
{
// Visit the object to create the entry.
return this->VisitTarjan(obj);
}
// else Return the existing entry.
return *i;
}
//----------------------------------------------------------------------------
vtkGarbageCollectorImpl::Entry*
vtkGarbageCollectorImpl::VisitTarjan(vtkObjectBase* obj)
{
// Create an entry for the object.
Entry* v = new Entry(obj);
this->Visited.insert(v);
// Initialize the entry and push it onto the stack of graph nodes.
v->Root = v;
v->Component = 0;
v->VisitOrder = ++this->VisitCount;
this->PassReferencesToEntry(v);
this->Stack.push(v);
vtkDebugMacro("Requesting references from "
<< v->Object->GetClassName() << "("
<< v->Object << ") with reference count "
<< (v->Object->GetReferenceCount()-v->GarbageCount));
// Process the references from this node.
Entry* saveCurrent = this->Current;
this->Current = v;
vtkGarbageCollectorToObjectBaseFriendship::ReportReferences(this, v->Object);
this->Current = saveCurrent;
// Check if we have found a component.
if(v->Root == v)
{
// Found a new component.
ComponentType* c = new ComponentType;
c->Identifier = ++this->NumberOfComponents;
Entry* w;
do
{
// Get the next member of the component.
w = this->Stack.top();
this->Stack.pop();
// Assign the member to the component.
w->Component = c;
w->Root = v;
c->push_back(w);
// Include this member's reference count in the component total.
c->NetCount += w->Count;
} while(w != v);
// Save the component.
this->ReferencedComponents.insert(c);
// Print the component for debugging.
this->PrintComponent(c);
// Remove internal references from the component.
this->SubtractInternalReferences(c);
}
return v;
}
//----------------------------------------------------------------------------
#ifdef VTK_LEAN_AND_MEAN
void vtkGarbageCollectorImpl::Report(vtkObjectBase* obj, void* ptr,
const char*)
{
// All calls should be given the pointer.
assert(ptr != 0);
// Forward call to the internal implementation.
if(obj)
{
this->Report(obj, ptr);
}
}
#else
void vtkGarbageCollectorImpl::Report(vtkObjectBase* obj, void* ptr,
const char* desc)
{
// All calls should be given the pointer.
assert(ptr != 0);
if(obj)
{
// Report debugging information if requested.
if(this->Debug && vtkObject::GetGlobalWarningDisplay())
{
vtkObjectBase* current = this->Current->Object;
ostrstream msg;
msg << "Report: "
<< current->GetClassName() << "(" << current << ") "
<< (desc?desc:"")
<< " -> " << obj->GetClassName() << "(" << obj << ")";
msg << ends;
vtkDebugMacro(<< msg.str());
msg.rdbuf()->freeze(0);
}
// Forward call to the internal implementation.
this->Report(obj, ptr);
}
}
#endif
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::Report(vtkObjectBase* obj, void* ptr)
{
// Get the source and destination of this reference.
Entry* v = this->Current;
Entry* w = this->MaybeVisit(obj);
// If the destination has not yet been assigned to a component,
// check if it is a better potential root for the current object.
if(!w->Component)
{
if(w->Root->VisitOrder < v->Root->VisitOrder)
{
v->Root = w->Root;
}
}
// Save this reference.
v->References.push_back(EntryEdge(w, ptr));
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::CollectComponent(ComponentType* c)
{
ComponentType::iterator e;
// Print out the component for debugging.
this->PrintComponent(c);
// Get an extra reference to all objects in the component so that
// they are not deleted until all references are removed.
for(e = c->begin(); e != c->end(); ++e)
{
vtkGarbageCollectorToObjectBaseFriendship::Register((*e)->Object, this);
}
// Disconnect the reference graph.
for(e = c->begin(); e != c->end(); ++e)
{
// Loop over all references made by this entry's object.
Entry* entry = *e;
for(unsigned int i = 0; i < entry->References.size(); ++i)
{
// Get a pointer to the object referenced.
vtkObjectBase* obj = entry->References[i].Reference->Object;
// Get a pointer to the pointer holding the reference.
void** ptr = static_cast<void**>(entry->References[i].Pointer);
// Set the pointer holding the reference to NULL. The
// destructor of the object that reported this reference must
// deal with this.
*ptr = 0;
// Remove the reference to the object referenced without
// recursively collecting. We already know about the object.
vtkGarbageCollectorToObjectBaseFriendship::UnRegister(obj,
entry->Object);
}
}
// Remove the Entries' references to objects.
for(e = c->begin(); e != c->end(); ++e)
{
this->FlushEntryReferences(*e);
}
// Only our extra reference to each object remains. Delete the
// objects.
for(e = c->begin(); e != c->end(); ++e)
{
assert((*e)->Object->GetReferenceCount() == 1);
vtkGarbageCollectorToObjectBaseFriendship::UnRegister((*e)->Object, this);
}
}
//----------------------------------------------------------------------------
#ifndef VTK_LEAN_AND_MEAN
void vtkGarbageCollectorImpl::PrintComponent(ComponentType* c)
{
if(this->Debug && vtkObject::GetGlobalWarningDisplay())
{
ostrstream msg;
msg << "Identified strongly connected component "
<< c->Identifier << " with net reference count "
<< c->NetCount << ":";
for(ComponentType::iterator i = c->begin(); i != c->end(); ++i)
{
vtkObjectBase* obj = (*i)->Object;
int count = (*i)->Count;
msg << "\n " << obj->GetClassName() << "(" << obj << ")"
<< " with " << count << " external "
<< ((count == 1)? "reference" : "references");
}
msg << ends;
vtkDebugMacro(<< msg.str());
msg.rdbuf()->freeze(0);
}
}
#else
void vtkGarbageCollectorImpl::PrintComponent(ComponentType*)
{
}
#endif
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::SubtractInternalReferences(ComponentType* c)
{
// Loop over all members of the component.
for(ComponentType::iterator i = c->begin(); i != c->end(); ++i)
{
Entry* v = *i;
// Loop over all references from this member.
for(Entry::ReferencesType::iterator r = v->References.begin();
r != v->References.end(); ++r)
{
Entry* w = r->Reference;
// If this reference points inside the component, subtract it.
if(v->Component == w->Component)
{
this->SubtractReference(w);
}
}
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::SubtractExternalReferences(ComponentType* c)
{
// Loop over all members of the component.
for(ComponentType::iterator i = c->begin(); i != c->end(); ++i)
{
Entry* v = *i;
// Loop over all references from this member.
for(Entry::ReferencesType::iterator r = v->References.begin();
r != v->References.end(); ++r)
{
Entry* w = r->Reference;
// If this reference points outside the component, subtract it.
if(v->Component != w->Component)
{
this->SubtractReference(w);
}
}
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::SubtractReference(Entry* e)
{
// The component should not be leaked before we get here.
assert(e->Component != 0);
assert(e->Component->NetCount > 0);
vtkDebugMacro("Subtracting reference to object "
<< e->Object->GetClassName() << "(" << e->Object << ")"
<< " in component " << e->Component->Identifier << ".");
// Decrement the entry's reference count.
--e->Count;
// If the component's net count is now zero, move it to the queue of
// leaked component.
if(--e->Component->NetCount == 0)
{
this->ReferencedComponents.erase(e->Component);
this->LeakedComponents.push(e->Component);
vtkDebugMacro("Component " << e->Component->Identifier << " is leaked.");
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::PassReferencesToEntry(Entry* e)
{
// Get the number of references the collector holds.
e->GarbageCount = 0;
if(this->Singleton)
{
ReferencesType::iterator i = this->Singleton->References.find(e->Object);
if(i != this->Singleton->References.end())
{
// Pass these references from the singleton to the entry.
e->GarbageCount = i->second;
this->Singleton->References.erase(i);
this->Singleton->TotalNumberOfReferences -= e->GarbageCount;
}
}
// Make sure the entry has at least one reference to the object.
// This ensures the object in components of size 1 is not deleted
// until we delete the component.
if(e->GarbageCount == 0)
{
vtkGarbageCollectorToObjectBaseFriendship::RegisterBase(e->Object);
++e->GarbageCount;
}
// Subtract the garbage count from the object's reference count.
e->Count = e->Object->GetReferenceCount() - e->GarbageCount;
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorImpl::FlushEntryReferences(Entry* e)
{
while(e->GarbageCount > 0)
{
vtkGarbageCollectorToObjectBaseFriendship::UnRegisterBase(e->Object);
--e->GarbageCount;
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::ClassInitialize()
{
// Set default debugging state.
vtkGarbageCollectorGlobalDebugFlag = 0;
// Record the id of the main thread.
vtkGarbageCollectorMainThread = vtkMultiThreader::GetCurrentThreadID();
// Allocate the singleton used for delayed collection in the main
// thread.
vtkGarbageCollectorSingletonInstance = new vtkGarbageCollectorSingleton;
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::ClassFinalize()
{
// We are done with the singleton. Delete it and reset the pointer.
// Other singletons may still cause garbage collection of VTK
// objects, they just will not have the option of deferred
// collection. In order to get it they need only to include
// vtkGarbageCollectorManager.h so that this singleton stays around
// longer.
delete vtkGarbageCollectorSingletonInstance;
vtkGarbageCollectorSingletonInstance = 0;
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::Report(vtkObjectBase*, void*, const char*)
{
vtkErrorMacro("vtkGarbageCollector::Report should be overridden.");
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::Collect()
{
// This must be called only from the main thread.
assert(vtkGarbageCollectorIsMainThread());
// Keep collecting until no deferred checks exist.
while(vtkGarbageCollectorSingletonInstance &&
vtkGarbageCollectorSingletonInstance->TotalNumberOfReferences > 0)
{
// Collect starting from one deferred object at a time. Each
// check will remove at least the starting object and possibly
// other objects from the singleton's references.
vtkObjectBase* root =
vtkGarbageCollectorSingletonInstance->References.begin()->first;
vtkGarbageCollector::Collect(root);
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::Collect(vtkObjectBase* root)
{
// Create a collector instance.
vtkGarbageCollectorImpl collector;
vtkDebugWithObjectMacro((&collector), "Starting collection check.");
// Collect leaked objects.
collector.CollectInternal(root);
vtkDebugWithObjectMacro((&collector), "Finished collection check.");
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::DeferredCollectionPush()
{
// This must be called only from the main thread.
assert(vtkGarbageCollectorIsMainThread());
// Forward the call to the singleton.
if(vtkGarbageCollectorSingletonInstance)
{
vtkGarbageCollectorSingletonInstance->DeferredCollectionPush();
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollector::DeferredCollectionPop()
{
// This must be called only from the main thread.
assert(vtkGarbageCollectorIsMainThread());
// Forward the call to the singleton.
if(vtkGarbageCollectorSingletonInstance)
{
vtkGarbageCollectorSingletonInstance->DeferredCollectionPop();
}
}
//----------------------------------------------------------------------------
int vtkGarbageCollector::GiveReference(vtkObjectBase* obj)
{
// We must have an object.
assert(obj != 0);
// See if the singleton will accept a reference.
if(vtkGarbageCollectorIsMainThread() &&
vtkGarbageCollectorSingletonInstance)
{
return vtkGarbageCollectorSingletonInstance->GiveReference(obj);
}
// Could not accept the reference.
return 0;
}
//----------------------------------------------------------------------------
int vtkGarbageCollector::TakeReference(vtkObjectBase* obj)
{
// We must have an object.
assert(obj != 0);
// See if the singleton has a reference.
if(vtkGarbageCollectorIsMainThread() &&
vtkGarbageCollectorSingletonInstance)
{
return vtkGarbageCollectorSingletonInstance->TakeReference(obj);
}
// No reference is available.
return 0;
}
//----------------------------------------------------------------------------
vtkGarbageCollectorSingleton::vtkGarbageCollectorSingleton()
{
this->TotalNumberOfReferences = 0;
this->DeferredCollectionCount = 0;
}
//----------------------------------------------------------------------------
vtkGarbageCollectorSingleton::~vtkGarbageCollectorSingleton()
{
// There should be no deferred collections left.
assert(this->TotalNumberOfReferences == 0);
}
//----------------------------------------------------------------------------
int vtkGarbageCollectorSingleton::GiveReference(vtkObjectBase* obj)
{
// Check if we can store a reference to the object in the map.
if(this->CheckAccept())
{
// Create a reference to the object.
ReferencesType::iterator i = this->References.find(obj);
if(i == this->References.end())
{
// This is a new object. Create a map entry for it.
this->References.insert(ReferencesType::value_type(obj, 1));
}
else
{
++i->second;
}
++this->TotalNumberOfReferences;
return 1;
}
// We did not accept the reference.
return 0;
}
//----------------------------------------------------------------------------
int vtkGarbageCollectorSingleton::TakeReference(vtkObjectBase* obj)
{
// If we have a reference to the object hand it back to the caller.
ReferencesType::iterator i = this->References.find(obj);
if(i != this->References.end())
{
// Remove our reference to the object.
--this->TotalNumberOfReferences;
if(--i->second == 0)
{
// If we have no more references to the object, remove its map
// entry.
this->References.erase(i);
}
return 1;
}
// We do not have a reference to the object.
return 0;
}
//----------------------------------------------------------------------------
int vtkGarbageCollectorSingleton::CheckAccept()
{
// Accept the reference only if deferred collection is enabled. It
// is tempting to put a check against TotalNumberOfReferences here
// to collect every so many deferred calls, but this will NOT work.
// Some objects call UnRegister on other objects during
// construction. We do not want to perform deferred collection
// while an object is under construction because the reference walk
// might call ReportReferences on a partially constructed object!
return this->DeferredCollectionCount > 0;
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorSingleton::DeferredCollectionPush()
{
if(++this->DeferredCollectionCount <= 0)
{
// Deferred collection is disabled. Collect immediately.
vtkGarbageCollector::Collect();
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorSingleton::DeferredCollectionPop()
{
if(--this->DeferredCollectionCount <= 0)
{
// Deferred collection is disabled. Collect immediately.
vtkGarbageCollector::Collect();
}
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorReportInternal(vtkGarbageCollector* collector,
vtkObjectBase* obj, void* ptr,
const char* desc)
{
collector->Report(obj, ptr, desc);
}
//----------------------------------------------------------------------------
void vtkGarbageCollectorReport(vtkGarbageCollector* collector,
vtkSmartPointerBase& ptr,
const char* desc)
{
ptr.Report(collector, desc);
}