#include <support/Atom.h>
Inheritance diagram for SAtom:
SAtom is used with most objects that are reference counted. In particular, IBinder and all Binder interfaces include SAtom, meaning all Binder objects are intrinsically reference counted using the SAtom facilities.
The reference counting semantics are designed so that you will very rarely, if ever, have to directly deal with reference count management. Instead, you use the smart pointer classes sptr<T> and wptr<T> (for "strong pointer" and "weak pointer", respectively) to create pointers to SAtom objects, which will automatically manage the reference count for you. For example, the following function creates, assigns, and returns objects, in all cases maintaining proper reference counts:
sptr< MyClass > RefFunction(sptr< MyClass >* inOutClass) { sptr< MyClass > old = *inOutClass; *inOutClass = new MyClass; return old; }
When deriving directly from SAtom to make your own reference counted object, you should usually use virtual inhertance so that your class can be properly mixed in with other SAtom-derived classes (ensuring there is only one SAtom object, with its single set of reference counts, for the entire final class):
class MyClass : public virtual SAtom { };
Weak pointers allow you to hold a reference on an SAtom object that does not prevent it from being destroyed. The only thing you can do with a weak pointer is compare its address against other weak or strong pointers (to check if they are the same object), and use the wptr::promote() operation to attempt to obtain a strong pointer. The promotion will fail (by returning a sptr<T> containing NULL) if the object has already been destroyed (because all of its strong references have gone away). This mechanism is very useful to maintain parent/child relationships, where the child holds a weak pointer up to its parent:
class MyClass : public virtual SAtom { private: // NOTE: Not thread safe! wptr<MyClass> m_parent; sptr<MyClass> m_child; public: void SetChild(const sptr<MyClass>& child) { m_child = child; child->SetParent(this); } void SetParent(const sptr<MyClass>& parent) { m_parent = parent; } sptr<MyClass> Parent() const { return m_parent.promote(); } };
The SAtom class includes a rich debugging facility for tracking down reference counting bugs, and especially leaks. See SAtom Debugging for more information on it.
Reference Counting | |
Basic APIs for managing the reference count of an SAtom object. | |
int32_t | Acquire (const void *id) const |
status_t | AttachAtom (SAtom *target) |
Tie the reference counts of two atoms together. | |
bool | AttemptAcquire (const void *id) const |
bool | AttemptDecStrong (const void *id) const |
Perform a DecStrong() if there any strong pointers remaining. | |
bool | AttemptIncStrong (const void *id) const |
Try to acquire a strong pointer on this atom. | |
bool | AttemptIncStrongFast () const |
Optimized version of AttemptIncStrong() for release builds. | |
bool | AttemptIncWeak (const void *id) const |
Try to acquire a weak pointer on this atom. | |
bool | AttemptIncWeakFast () const |
Optimized version of AttemptIncWeak() for release builds. | |
bool | AttemptRelease (const void *id) const |
weak_atom_ptr * | CreateWeak (const void *cookie) const |
Create a weak reference to the atom. | |
int32_t | DecRefs (const void *id) const |
int32_t | DecStrong (const void *id) const |
Decrement the atom's strong pointer count. | |
void | DecStrongFast () const |
Optimized version of DecStrong() for release builds. | |
int32_t | DecWeak (const void *id) const |
Decrement the atom's weak pointer count. | |
void | DecWeakFast () const |
Optimized version of DecWeak() for release builds. | |
int32_t | ForceAcquire (const void *id) const |
int32_t | ForceIncStrong (const void *id) const |
Acquire a strong pointer on the atom, even if it doesn't have one. | |
void | ForceIncStrongFast () const |
Optimized version of ForceIncStrong() for release builds. | |
int32_t | IncRefs (const void *id) const |
int32_t | IncStrong (const void *id) const |
Increment the atom's strong pointer count. | |
void | IncStrongFast () const |
Optimized version of IncStrong() for release builds. | |
int32_t | IncWeak (const void *id) const |
Increment the atom's weak pointer count. | |
void | IncWeakFast () const |
Optimized version of IncWeak() for release builds. | |
int32_t | Release (const void *id) const |
Debugging | |
These methods allow you to work with the SAtom reference count debugging and leak tracking mechanism as described in SAtom Debugging. They are only implemented on debug builds when the atom debugging facility is enabled. In other cases, they are a no-op. | |
size_t | AtomObjectSize () const |
Prints the size of the object. Sometimes useful to know. | |
void | Report (const sptr< ITextOutput > &io, uint32_t flags=0) const |
Print information state and references on this atom to io. | |
int32_t | StrongCount () const |
Return the number of strong pointers currently on the atom. | |
int32_t | WeakCount () const |
Return the number of weak pointers currently on the atom. | |
static bool | ExistsAndIncStrong (SAtom *atom) |
Check for atom existance and acquire string reference. | |
static bool | ExistsAndIncWeak (SAtom *atom) |
Check for atom existance and acquire weak reference. | |
static void | GetActiveTypeNames (SSortedVector< SString > *outNames) |
Return a set of the type names for all SAtom/SLightAtoms that currently exist. | |
static void | GetAllWithTypeName (const char *typeName, SVector< wptr< SAtom > > *outAtoms=NULL, SVector< sptr< SLightAtom > > *outLightAtoms=NULL) |
Return all existing atoms that are the given type name. | |
static void | LeakReport (int32_t mark=0, int32_t last=-1, uint32_t flags=0) |
Print information about SAtom/SLightAtoms in a leak context to standard output. | |
static void | LeakReport (const sptr< ITextOutput > &io, int32_t mark=0, int32_t last=-1, uint32_t flags=0) |
Print information about SAtom/SLightAtoms in a leak context to an output stream. | |
static int32_t | MarkLeakReport () |
Start a new SAtom/SLightAtom leak context and returns its identifier. | |
static void | StartWatching (const B_SNS(std::) type_info *type) |
Register a particular class type for watching SAtom/SLightAtom operations. | |
static void | StopWatching (const B_SNS(std::) type_info *type) |
Remove a watching of a class type originally supplied to StartWatching(). | |
Reference Count Access | |
Retrieve the current reference count on the object. Generally only used for debugging. | |
bool | HasManyStrongPointers () const |
Return true if this atom has more than one strong acquire on it. | |
bool | HasManyWeakPointers () const |
Return true if this atom has more than one weak acquire on it. | |
bool | HasStrongPointers () const |
Return true if this atom has any strong acquires on it. | |
bool | HasWeakPointers () const |
Return true if this atom has any weak acquires on it. | |
Custom New and Delete Operators | |
SAtom must use its own new and delete operators to perform the bookkeeping necessary to support weak pointers. | |
void | operator delete (void *ptr, size_t size) |
void * | operator new (size_t size, const B_SNS(std::) nothrow_t &) throw () |
void * | operator new (size_t size) |
Reference Count Owner | |
SAtom provides a rich reference count debugging facility described in SAtom Debugging. For it to work, each reference on an SAtom must have a unique object ID (usually a memory address) of the entity that "owns" that reference. You should use these APIs in situations where that object ID changes, so that when atom debugging is enabled others will be able to properly track their references. | |
void | RenameOwnerID (const void *newID, const void *oldID) const |
Change an owner ID associated with this atom. | |
static void | MovePointersAfter (SAtom **newPtr, SAtom **oldPtr, size_t num=1) |
Perform a memmove() of an array of SAtom*, updating owner IDs as needed. | |
static void | MovePointersBefore (SAtom **newPtr, SAtom **oldPtr, size_t num=1) |
Perform a memcpy() of an array of SAtom*, updating owner IDs as needed. | |
Bookkeeping | |
Object initialization, destruction, and lifetime management. | |
enum | { FINISH_ATOM_ASYNC = 0x0001 } |
virtual status_t | DeleteAtom (const void *id) |
Called after last DecRefs() when the life of an atom is extended. | |
virtual status_t | FinishAtom (const void *id) |
Objects can optionally override this function to extend the lifetime of an atom (past the last strong reference). | |
virtual status_t | IncStrongAttempted (uint32_t flags, const void *id) |
Called during IncStrong() after an atom has been released. | |
virtual void | InitAtom () |
Called the first time a strong reference is acquired. All significant object initialization should go here. | |
SAtom () | |
Construct a new SAtom. | |
virtual | ~SAtom () |
Destructor called when it is time to destroy the object. Never call yourself! | |
Friends | |
class | AsyncDestructor |
class | SAtomTracker |
class | SLightAtom |
Classes | |
struct | weak_atom_ptr |
Represents a safe weak reference on an SAtom object. More... |
|
|
|
Construct a new SAtom. The reference counts start out at zero. You must call IncStrong() (or create a sptr<T> to the SAtom) to acquire the first reference, at which point InitAtom() will be called. |
|
Destructor called when it is time to destroy the object. Never call yourself! Normally called inside of DecStrong() when the reference count goes to zero, but you can change that behavior with FinishAtom(). |
|
|
|
Prints the size of the object. Sometimes useful to know.
|
|
Tie the reference counts of two atoms together. After calling this function, both objects share the same reference counts and they will both be destroyed once that count goes to zero. The 'target' object must have only one strong reference on it -- the attach operation is not thread safe for that object (its current references will be transfered to the other atom).
|
|
|
|
Perform a DecStrong() if there any strong pointers remaining. If this atom has any outstanding strong references, this function will remove one of them and return true. Otherwise it leaves the atom as-is and returns false. Note that successful removal of the strong reference may result in the object being destroyed. Trust me, it is useful... though for very few things.
|
|
Try to acquire a strong pointer on this atom. You must already have a weak reference on the atom. This function will attempt to add a new strong reference to the atom. It returns true on success, in which case a new strong reference has been acquired which you must later remove with DecStrong(). Otherwise, the atom is left as-is. Failure only occurs after the atom has already had IncStrong() called and then completely released. That is, AttemptIncStrong() will succeeded on a newly created SAtom that has never had IncStrong() called on it.
|
|
Optimized version of AttemptIncStrong() for release builds.
|
|
Try to acquire a weak pointer on this atom. Attempt to acquire a weak reference on the atom. Unlike AttemptIncStrong(), you can not call this for the first weak reference -- it will fail in that case. Like ForceIncStrong(), if you think you need to use this you should think again.
|
|
Optimized version of AttemptIncWeak() for release builds.
|
|
|
|
Create a weak reference to the atom. Upon creation it does NOT hold a reference to the atom -- you must call SAtom::weak_atom_ptr::Increment() on it first. |
|
|
|
Decrement the atom's strong pointer count. If this is the last strong pointer on it, FinishAtom() will be called. |
|
Optimized version of DecStrong() for release builds.
|
|
Decrement the atom's weak pointer count. If this is the last weak pointer on it, the object will be completely deallocated. Usually this means simply freeing the remaining memory for the SAtom object instance, since the destructor was previously called when the last strong reference went away. Some SAtom objects may extend their lifetime with FinishAtom(), in which case the object's destructor may be called at this point.
|
|
Optimized version of DecWeak() for release builds.
|
|
Called after last DecRefs() when the life of an atom is extended. If you override FinishAtom() to not call into SAtom (and thus extend the life of your object), then this method will be called when its last reference goes away. The default implementation returns B_OK to have the object deleted. You can override this to return an error code so that the object is not destroyed. This is a very, very unusual feature and requires a lot of careful and specific management of objects and reference counts to make work. You probably want to leave it as-is.
Reimplemented in BpAtom, BpInterface, BpInterface< IStorage >, BpInterface< IMemoryDealer >, BpInterface< IXMLOStr >, BpInterface< IMemory >, BpInterface< IByteOutput >, BpInterface< IByteInput >, BpInterface< IMemoryHeap >, and BpInterface< IByteSeekable >. |
|
Check for atom existance and acquire string reference. Check whether the given atom currently exists, and acquire a strong pointer if so. These only work when the leak checker is turned on; otherwise, false is always returned.
|
|
Check for atom existance and acquire weak reference. Check whether the given atom currently exists, and acquire a weak pointer if so. These only work when the leak checker is turned on; otherwise, false is always returned.
|
|
Objects can optionally override this function to extend the lifetime of an atom (past the last strong reference). If you return FINISH_ATOM_ASYNC here, your object's destructor will be called asynchronously from the current thread. This is highly recommend if you must acquire a lock in the destructor, to avoid unexpected deadlocks due to things like sptr<> going out of scope while a lock is held. If you return an error code here, the object's destructor will not be called at this point. The default implementation will return B_OK, allowing the SAtom destruction to proceed as normal. Don't override this method unless you want some other behavior. Like InitAtom(), you do not need to call the SAtom implementation.
Reimplemented in BSchemaRowIDJoin::RowNode, BSchemaRowIDJoin::JoinIterator, BSchemaTableNode::RowNode, BSchemaTableNode::QueryIterator, BInformant, SDatumGeneratorInt::IndexedDatum, BGenericIterable::GenericIterator, BIndexedTableNode::RowNode, BStreamDatum::Stream, BpAtom, BpInterface, BProcess::ComponentImage, BpBinder, BpInterface< IStorage >, BpInterface< IMemoryDealer >, BpInterface< IXMLOStr >, BpInterface< IMemory >, BpInterface< IByteOutput >, BpInterface< IByteInput >, BpInterface< IMemoryHeap >, and BpInterface< IByteSeekable >. |
|
|
|
Acquire a strong pointer on the atom, even if it doesn't have one. This is just like IncStrong(), except that it is not an error to call on a SAtom that currently does not have a strong reference. If you think you need to use this, think again.
|
|
Optimized version of ForceIncStrong() for release builds.
|
|
Return a set of the type names for all SAtom/SLightAtoms that currently exist. Return the type names for all atom objects that current exist. |
|
Return all existing atoms that are the given type name. Retrieve all currently existing atoms that are the given type name. These are returned as an array of weak references to them, so as a side effect you will be acquiring weak references on these atoms as they are found. |
|
Return true if this atom has more than one strong acquire on it.
|
|
Return true if this atom has more than one weak acquire on it.
|
|
Return true if this atom has any strong acquires on it.
|
|
Return true if this atom has any weak acquires on it.
|
|
|
|
Increment the atom's strong pointer count. This is the standard reference count -- once it transitions to zero, the atom will become invalid. An atom starts with a reference count of zero, and gets invalidated the first time it transitions from one to zero. The optional id parameter is the memory address of the object holding this reference. It is only used for debugging. The first time you call IncStrong() will result in InitAtom() being called.
|
|
Called during IncStrong() after an atom has been released. The flags will be B_ATOM_FIRST_STRONG if this is the first strong reference ever acquired on the atom. The default implementation returns B_OK if B_ATOM_FIRST_STRONG is set, otherwise it returns B_NOT_ALLOWED to make the attempted IncStrong() fail. You can override this to return B_OK when you would like an atom to continue allowing primary references. Note that this also requires overriding FinishAtom() to return an error code, extending the lifetime of the object. Like FinishAtom(), you do not need to call the SAtom implementation.
Reimplemented in BpAtom, BpInterface, BProcess::ComponentImage, BpBinder, BpInterface< IStorage >, BpInterface< IMemoryDealer >, BpInterface< IXMLOStr >, BpInterface< IMemory >, BpInterface< IByteOutput >, BpInterface< IByteInput >, BpInterface< IMemoryHeap >, and BpInterface< IByteSeekable >. |
|
Optimized version of IncStrong() for release builds.
|
|
Increment the atom's weak pointer count. This keeps an atom from actually being freed after its last primary reference is removed. If you are only holding a weak reference on the object, you know that the memory it points to still exists, but don't know what state the object is in. The optional id parameter is the memory address of the object holding this reference. It is only used for debugging.
|
|
Optimized version of IncWeak() for release builds.
|
|
Called the first time a strong reference is acquired. All significant object initialization should go here. You can override it and do any setup you need. Note that you do not need to call the SAtom implementation. (So you can derive from two different SAtom implementations and safely call down to both of their IncStrong() methods.)
Reimplemented in BSchemaDatabaseNode, BSchemaTableNode, BSchemaTableNode::DataAccessor, BSchemaTableNode::RowNode, BSchemaTableNode::QueryIterator, BPackageManager, BInformant, BGenericIterable::GenericIterator, BStreamDatum::Stream, BpAtom, BpInterface, BCatalog, SDatumLord, SDatumLord::Datum, BRandomIterator, BSerialObserver, BSharedObject, BProcess::ComponentImage, BProcess, BTokenSource, BpBinder, BpInterface< IStorage >, BpInterface< IMemoryDealer >, BpInterface< IXMLOStr >, BpInterface< IMemory >, BpInterface< IByteOutput >, BpInterface< IByteInput >, BpInterface< IMemoryHeap >, and BpInterface< IByteSeekable >. |
|
Print information about SAtom/SLightAtoms in a leak context to standard output.
|
|
Print information about SAtom/SLightAtoms in a leak context to an output stream. This function prints information about all of the currently active atoms created during the leak context mark up to and including the context last. A mark context of 0 is the first context; a last context of -1 means the current context. This is the API called by the "atom leaks" command described in SAtom Debugging.
|
|
Start a new SAtom/SLightAtom leak context and returns its identifier. This is the API called by the "atom mark" command described in SAtom Debugging.
|
|
Perform a memmove() of an array of SAtom*, updating owner IDs as needed.
|
|
Perform a memcpy() of an array of SAtom*, updating owner IDs as needed.
|
|
|
|
|
|
SAtom overrides its new and delete operators for its implementation. You must use these operators and instantiating classes derived from SAtom. Thus a subclass can not implement its own new or delete operators, nor can you use inplace-new on a SAtom class. |
|
|
|
Change an owner ID associated with this atom. This is useful, for example, if you have a piece of memory with a pointer to an atom, whose memory address you have used for the reference ID. If you are moving your memory to a new location with memcpy(), you can use this function to change the ID stored in the atom for your reference. This function does nothing if atom debugging is not currently enabled.
|
|
Print information state and references on this atom to io. The flags may be one of B_ATOM_REPORT_FORCE_LONG, B_ATOM_REPORT_FORCE_SHORT, or B_ATOM_REPORT_FORCE_SUMMARY, as well as B_ATOM_REPORT_REMOVE_HEADER. This is the API called by the "atom report" command described in SAtom Debugging.
In addition, you can modify the default Report() format with the ATOM_REPORT environment variable:
|
|
Register a particular class type for watching SAtom/SLightAtom operations. When a watch is in effect, SAtom will print to standard out whenever significant operations happen on an object of the watched type. Note that they must be exactly this type -- subclasses are not included. Use StopWatching() to remove a watched type.
|
|
Remove a watching of a class type originally supplied to StartWatching().
|
|
Return the number of strong pointers currently on the atom.
|
|
Return the number of weak pointers currently on the atom.
|
|
|
|
|
|
|