Sirikata
Classes | Public Member Functions | Protected Member Functions | Private Types | Private Attributes
Sirikata::Liveness Class Reference

Liveness makes it simple to track whether an object is still alive when using asynchronous callbacks. More...

#include <Liveness.hpp>

Inheritance diagram for Sirikata::Liveness:
Collaboration diagram for Sirikata::Liveness:

List of all members.

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

Detailed Description

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.


Member Typedef Documentation

typedef std::tr1::weak_ptr<int> Sirikata::Liveness::InternalToken [private]
typedef std::tr1::shared_ptr<int> Sirikata::Liveness::StrongInternalToken [private]

Constructor & Destructor Documentation

Sirikata::Liveness::Liveness ( )
Sirikata::Liveness::~Liveness ( )

References mLivenessStrongToken.


Member Function Documentation

void Sirikata::Liveness::letDie ( )
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().


Member Data Documentation

Referenced by letDie(), and ~Liveness().


The documentation for this class was generated from the following files: