Sirikata
|
Liveness makes it simple to track whether an object is still alive when using asynchronous callbacks. More...
#include <Liveness.hpp>
Classes | |
struct | Lock |
struct | Token |
Public Member Functions | |
Liveness () | |
~Liveness () | |
Token | livenessToken () const |
Get a token which can be used to determine whether the object is still alive or obtain a liveness lock on it. | |
void | letDie () |
Allow this object to "die", blocking until no other threads have access anymore to return. | |
Protected Member Functions | |
bool | livenessAlive () const |
Helper method to determine whether this object is still alive. | |
Private Types | |
typedef std::tr1::shared_ptr< int > | StrongInternalToken |
typedef std::tr1::weak_ptr< int > | InternalToken |
Private Attributes | |
StrongInternalToken | mLivenessStrongToken |
Liveness makes it simple to track whether an object is still alive when using asynchronous callbacks.
A common problem we encounter is that callbacks to member functions need to be handled carefully: we need to be sure a callback is not invoked after an object is deleted. One way to do this is to force the class to be used through a shared_ptr and use the shared_ptr in the callback. A better approach is to use a weak_ptr in the callback so the object can be cleaned up -- SelfWeakPtr helps you do just that.
But these approaches are bad for two reasons. First, they force you to change how you manage your class, which can be a burden if the class is already in use. Second, with weak_ptrs you need to wrap the callback with a stub that locks the weak_ptrs, checks validity, and then invokes the real callback.
Liveness avoids these problems by providing a token inside the object which is checked for validity. You pass the token through to your callback and check if it is valid at the top of the callback. The token is just a shared_ptr maintained internally and passed through the callback as a weak_ptr, the same strategy as the SelfWeakPtr approach. Essentially, you pay for one additional heap allocation.
To use, inherit from Liveness, pass livenessToken() as an extra parameter to your callbacks, and check the token's validity as the first operation in the callback, e.g.
void MyClass::my_callback(Liveness::Token alive) { if (!alive) return; }
Since you haven't accessed any data in the object, this is safe even if the this pointer to the MyClass instance has been deleted.
This basic approach doesn't protect you against multithreading: if the object is valid at the beginning of the callback but deleted by another thread during its execution, you'll end up accessing unallocated memory. In those cases, you can use a stronger primitive, a Liveness::Lock, which keeps the Liveness object from dying while you are using it: as long as there are Liveness::Lock objects which point to the Liveness object, it will block the thread trying to invalidate it. To support this, objects that inherit from Liveness call Liveness::letDie() when they want to disallow future access to themselves, e.g. because they are becoming invalid or being deleted. Then, the user of the object tries to allocate a lock, much like using weak_ptr::lock():
void MyClass::my_callback(Liveness::Token alive) { Liveness::Lock locked(alive); if (!locked) return; }
This is similar but not exactly the same as using SelfWeakPtr, and is especially useful as it doesn't force you to use shared_ptrs for all your classes.
Classes that inherit from Liveness *must* call letDie() and should be careful about when they call it. It *must* be called before any method calls could be invalid. Because virtual methods could become invalid during destruction, the absolute latest you can call it is in the destructor of the deepest subclass of Liveness. This means that you should be very careful about inheriting from other classes that themselves inherit from Liveness.
typedef std::tr1::weak_ptr<int> Sirikata::Liveness::InternalToken [private] |
typedef std::tr1::shared_ptr<int> Sirikata::Liveness::StrongInternalToken [private] |
Sirikata::Liveness::Liveness | ( | ) |
Sirikata::Liveness::~Liveness | ( | ) |
References mLivenessStrongToken.
void Sirikata::Liveness::letDie | ( | ) |
Allow this object to "die", blocking until no other threads have access anymore to return.
You should call this before your object will become invalid for further calls -- definitely by the destructor of the inheriting class (when data and virtual methods will become invalid), but possibly earlier (e.g. when Service::stop() is called for the object).
References mLivenessStrongToken.
Referenced by Sirikata::RecordSSTStream< ODPSST::Stream::Ptr >::destroy(), Sirikata::JS::JSObjectScript::iStop(), Sirikata::JS::EmersonScript::iStop(), Sirikata::Graphics::PriorityDownloadPlanner::Asset::~Asset(), Sirikata::SDL::AudioSimulation::~AudioSimulation(), Sirikata::JS::EmersonScript::~EmersonScript(), Sirikata::JS::JSContextStruct::~JSContextStruct(), Sirikata::JS::JSObjectScript::~JSObjectScript(), Sirikata::JS::JSPresenceStruct::~JSPresenceStruct(), Sirikata::JS::JSTimerStruct::~JSTimerStruct(), Sirikata::JS::JSVisibleStruct::~JSVisibleStruct(), Sirikata::OH::Manual::ObjectQueryHandler::~ObjectQueryHandler(), Sirikata::Graphics::OgreRenderer::~OgreRenderer(), Sirikata::Graphics::OgreSystem::~OgreSystem(), Sirikata::Graphics::PriorityDownloadPlanner::~PriorityDownloadPlanner(), Sirikata::Graphics::ProxyEntity::~ProxyEntity(), Sirikata::Graphics::Skybox::~Skybox(), Sirikata::SpaceNodeConnection::~SpaceNodeConnection(), and Sirikata::Graphics::WebView::~WebView().
bool Sirikata::Liveness::livenessAlive | ( | ) | const [inline, protected] |
Helper method to determine whether this object is still alive.
Useful for classes that inherit from Liveness and also have subclasses, but can be valid on their own. For example if we have Liveness <- A <- B, then A might use this method to determine whether it is a B which has already called letDie() or if it's just a regular A and needs to call letDie() itself.
Referenced by Sirikata::JS::JSObjectScript::iStop(), Sirikata::JS::EmersonScript::~EmersonScript(), Sirikata::JS::JSObjectScript::~JSObjectScript(), Sirikata::Graphics::OgreRenderer::~OgreRenderer(), and Sirikata::Graphics::PriorityDownloadPlanner::~PriorityDownloadPlanner().
Token Sirikata::Liveness::livenessToken | ( | ) | const [inline] |
Get a token which can be used to determine whether the object is still alive or obtain a liveness lock on it.
Referenced by Sirikata::Graphics::PriorityDownloadPlanner::addObject(), Sirikata::JS::JSTimerStruct::clear(), Sirikata::JS::EmersonScript::create_event(), Sirikata::OH::Manual::ObjectQueryHandler::createdReplicatedIndex(), Sirikata::Graphics::ProxyEntity::destroyed(), Sirikata::JS::JSPositionListener::eLoadMesh(), Sirikata::JS::EmersonScript::EmersonScript(), Sirikata::JS::JSObjectScript::eSetRestoreScript(), Sirikata::JS::JSObjectScript::eStorageCommit(), Sirikata::JS::JSObjectScript::eStorageCount(), Sirikata::JS::JSObjectScript::eStorageErase(), Sirikata::JS::JSObjectScript::eStorageRangeErase(), Sirikata::JS::JSObjectScript::eStorageRangeRead(), Sirikata::JS::JSObjectScript::eStorageRead(), Sirikata::JS::JSObjectScript::eStorageWrite(), Sirikata::Graphics::PriorityDownloadPlanner::finishLoadAsset(), Sirikata::JS::JSTimerStruct::fixSuspendableToContext(), Sirikata::OH::Manual::ObjectQueryHandler::generateObjectQueryEvents(), Sirikata::Graphics::ProxyEntity::handleDestroyTimeout(), Sirikata::SDL::AudioSimulation::handleFinishedDownload(), Sirikata::JS::EmersonMessagingManager::handleIncomingSubstream(), Sirikata::Graphics::WebView::handleListenToBrowser(), Sirikata::OH::Manual::ObjectQueryHandler::handleRemoveObjectQuery(), Sirikata::JS::EmersonScript::handleScriptCommUnreliable(), Sirikata::Graphics::OgreSystem::handleUIReady(), Sirikata::JS::JSTimerStruct::iEvaluateCallback(), Sirikata::Graphics::Skybox::imageDownloadFinished(), Sirikata::Graphics::OgreSystem::instantiateAllObjects(), Sirikata::Graphics::ProxyEntity::invalidated(), Sirikata::JS::EmersonScript::invokeInvokable(), Sirikata::JS::JSObjectScript::iStop(), Sirikata::JS::JSTimerStruct::JSTimerStruct(), Sirikata::JS::EmersonScript::killScript(), Sirikata::Graphics::Skybox::load(), Sirikata::Graphics::PriorityDownloadPlanner::loadBillboard(), Sirikata::Graphics::PriorityDownloadPlanner::loadDependentTextures(), Sirikata::Graphics::PriorityDownloadPlanner::loadMeshdata(), Sirikata::JS::EmersonScript::notifyProximate(), Sirikata::JS::EmersonScript::notifyProximateGone(), Sirikata::OH::Manual::ObjectQueryHandler::onBoundsUpdated(), Sirikata::JS::EmersonScript::onConnected(), Sirikata::Graphics::OgreSystem::onCreateProxy(), Sirikata::Graphics::OgreSystem::onDestroyProxy(), Sirikata::Graphics::OgreSystem::onDisconnected(), Sirikata::JS::EmersonScript::onDisconnected(), Sirikata::OH::Manual::ObjectQueryHandler::onEpochUpdated(), Sirikata::OH::Manual::ObjectQueryHandler::onLocationUpdated(), Sirikata::OH::Manual::ObjectQueryHandler::onMeshUpdated(), Sirikata::OH::Manual::ObjectQueryHandler::onOrientationUpdated(), Sirikata::OH::Manual::ObjectQueryHandler::onPhysicsUpdated(), Sirikata::Graphics::ProxyEntity::onSetIsAggregate(), Sirikata::Graphics::ProxyEntity::onSetMesh(), Sirikata::Graphics::ProxyEntity::onSetScale(), Sirikata::Graphics::OgreRenderer::parseMesh(), Sirikata::Graphics::PriorityDownloadPlanner::poll(), Sirikata::JS::EmersonMessagingManager::presenceConnected(), Sirikata::OH::Manual::ObjectQueryHandler::presenceDisconnected(), Sirikata::OH::Manual::ObjectQueryHandler::removedReplicatedIndex(), Sirikata::Graphics::PriorityDownloadPlanner::removeObject(), Sirikata::OH::Manual::ObjectQueryHandler::removeQuery(), Sirikata::JS::EmersonScript::restorePresence(), Sirikata::JS::JSTimerStruct::resume(), Sirikata::SessionManager::scheduleHandleServerMessages(), Sirikata::JS::EmersonMessagingManager::scriptCommWriteStreamConnectedCB(), Sirikata::JS::EmersonScript::sendSandbox(), Sirikata::JS::EmersonMessagingManager::sendScriptCommMessageReliable(), Sirikata::JS::JSObjectScript::setRestoreScript(), Sirikata::JS::EmersonMessagingManager::setupNewStream(), Sirikata::SDL::AudioSimulation::start(), Sirikata::SDL::AudioSimulation::stop(), Sirikata::JS::JSObjectScript::stop(), Sirikata::JS::EmersonScript::stop(), Sirikata::Graphics::PriorityDownloadPlanner::stop(), Sirikata::Graphics::OgreRenderer::stop(), Sirikata::JS::JSObjectScript::storageBeginTransaction(), Sirikata::JS::JSObjectScript::storageCommit(), Sirikata::JS::JSObjectScript::storageCommitCallback(), Sirikata::JS::JSObjectScript::storageCount(), Sirikata::JS::JSObjectScript::storageCountCallback(), Sirikata::JS::JSObjectScript::storageErase(), Sirikata::JS::JSObjectScript::storageRangeErase(), Sirikata::JS::JSObjectScript::storageRangeRead(), Sirikata::JS::JSObjectScript::storageRead(), Sirikata::JS::JSObjectScript::storageWrite(), Sirikata::JS::JSTimerStruct::struct_resetTimer(), Sirikata::JS::JSTimerStruct::timerWeakReferenceCleanup(), Sirikata::Graphics::ProxyEntity::updateLocation(), Sirikata::Graphics::PriorityDownloadPlanner::updateObject(), Sirikata::OH::Manual::ObjectQueryHandler::updateQuery(), Sirikata::Graphics::ProxyEntity::validated(), Sirikata::RecordSSTStream< ODPSST::Stream::Ptr >::write(), Sirikata::JS::EmersonMessagingManager::writeData(), Sirikata::JS::EmersonMessagingManager::writeMessageSubstream(), and Sirikata::JS::EmersonScript::~EmersonScript().
Referenced by letDie(), and ~Liveness().