Improve RefBase documentation, especially for clients.

Add basic interface documentation to RefBase.h.

Much, but not all, of this is cut-and-pasted from an email message
from Mathias Agopian. The rest is reconstructed from the code.

Delete some, now redundant, text from Refbase.cpp, and add a bit
more about the implementation strategy.

Some minor fixes to internal comments.

Bug: 30292291
Change-Id: I56518ae5553bc6de0cc2331778e7fcf2e6c4fd87
This commit is contained in:
Hans Boehm 2016-07-21 18:56:55 -07:00
parent 077135b18c
commit 9ba7192c1f
2 changed files with 168 additions and 11 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2005 The Android Open Source Project
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,6 +14,146 @@
* limitations under the License.
*/
// SOME COMMENTS ABOUT USAGE:
// This provides primarily wp<> weak pointer types and RefBase, which work
// together with sp<> from <StrongPointer.h>.
// sp<> (and wp<>) are a type of smart pointer that use a well defined protocol
// to operate. As long as the object they are templated with implements that
// protocol, these smart pointers work. In several places the platform
// instantiates sp<> with non-RefBase objects; the two are not tied to each
// other.
// RefBase is such an implementation and it supports strong pointers, weak
// pointers and some magic features for the binder.
// So, when using RefBase objects, you have the ability to use strong and weak
// pointers through sp<> and wp<>.
// Normally, when the last strong pointer goes away, the object is destroyed,
// i.e. it's destructor is called. HOWEVER, parts of its associated memory is not
// freed until the last weak pointer is released.
// Weak pointers are essentially "safe" pointers. They are always safe to
// access through promote(). They may return nullptr if the object was
// destroyed because it ran out of strong pointers. This makes them good candidates
// for keys in a cache for instance.
// Weak pointers remain valid for comparison purposes even after the underlying
// object has been destroyed. Even if object A is destroyed and its memory reused
// for B, A remaining weak pointer to A will not compare equal to one to B.
// This again makes them attractive for use as keys.
// How is this supposed / intended to be used?
// Our recommendation is to use strong references (sp<>) when there is an
// ownership relation. e.g. when an object "owns" another one, use a strong
// ref. And of course use strong refs as arguments of functions (it's extremely
// rare that a function will take a wp<>).
// Typically a newly allocated object will immediately be used to initialize
// a strong pointer, which may then be used to construct or assign to other
// strong and weak pointers.
// Use weak references when there are no ownership relation. e.g. the keys in a
// cache (you cannot use plain pointers because there is no safe way to acquire
// a strong reference from a vanilla pointer).
// This implies that two objects should never (or very rarely) have sp<> on
// each other, because they can't both own each other.
// Caveats with reference counting
// Obviously, circular strong references are a big problem; this creates leaks
// and it's hard to debug -- except it's in fact really easy because RefBase has
// tons of debugging code for that. It can basically tell you exactly where the
// leak is.
// Another problem has to do with destructors with side effects. You must
// assume that the destructor of reference counted objects can be called AT ANY
// TIME. For instance code as simple as this:
// void setStuff(const sp<Stuff>& stuff) {
// std::lock_guard<std::mutex> lock(mMutex);
// mStuff = stuff;
// }
// is very dangerous. This code WILL deadlock one day or another.
// What isn't obvious is that ~Stuff() can be called as a result of the
// assignment. And it gets called with the lock held. First of all, the lock is
// protecting mStuff, not ~Stuff(). Secondly, if ~Stuff() uses its own internal
// mutex, now you have mutex ordering issues. Even worse, if ~Stuff() is
// virtual, now you're calling into "user" code (potentially), by that, I mean,
// code you didn't even write.
// A correct way to write this code is something like:
// void setStuff(const sp<Stuff>& stuff) {
// std::unique_lock<std::mutex> lock(mMutex);
// sp<Stuff> hold = mStuff;
// mStuff = stuff;
// lock.unlock();
// }
// More importantly, reference counted objects should do as little work as
// possible in their destructor, or at least be mindful that their destructor
// could be called from very weird and unintended places.
// Other more specific restrictions for wp<> and sp<>:
// Constructing a strong or weak pointer to "this" in its constructors is almost
// always wrong. In the case of strong pointers. it is always wrong with RefBase
// because the onFirstRef() callback will be mode on an incompletely constructed
// object. In either case, it is wrong if such a pointer does not outlive the
// constructor, since destruction of the smart pointer will attempt to destroy the
// object before construction is finished, normally resulting in a pointer to a
// destroyed object being returned from a new expression.
// In the case of weak pointers, this occurs because an object that has never been
// referenced by a strong pointer is destroyed when the last weak pointer disappears.
// Such strong or weak pointers can be safely created in the RefBase onFirstRef()
// callback.
// Use of wp::unsafe_get() for any purpose other than debugging is almost
// always wrong. Unless you somehow know that there is a longer-lived sp<> to
// the same object, it may well return a pointer to a deallocated object that
// has since been reallocated for a different purpose. (And if you know there
// is a longer-lived sp<>, why not use an sp<> directly?) A wp<> should only be
// dereferenced by using promote().
// Explicitly deleting or otherwise destroying a RefBase object with outstanding
// wp<> or sp<> pointers to it will result in heap corruption.
// Extra Features:
// RefBase::extendObjectLifetime() can be used to prevent destruction of the
// object while there are still weak references. This is really special purpose
// functionality to support Binder.
// Wp::promote(), implemented via the attemptIncStrong() member function, is
// used to try to convert a weak pointer back to a strong pointer. It's the
// normal way to try to access the fields of an object referenced only through
// a wp<>. Binder code also sometimes uses attemptIncStrong() directly.
// RefBase provides a number of additional callbacks for certain reference count
// events, as well as some debugging facilities.
// Debugging support can be enabled by turning on DEBUG_REFS in RefBase.cpp.
// Otherwise essentially no checking is provided.
// Thread safety:
// Like std::shared_ptr, sp<> and wp<> allow concurrent accesses to DIFFERENT
// sp<> and wp<> instances that happen to refer to the same underlying object.
// They do NOT support concurrent access (where at least one access is a write)
// to THE SAME sp<> or wp<>. In effect, their thread-safety properties are
// exactly like those of T*, NOT atomic<T*>.
#ifndef ANDROID_REF_BASE_H
#define ANDROID_REF_BASE_H
@ -142,9 +282,19 @@ protected:
FIRST_INC_STRONG = 0x0001
};
// Invoked after creation of initial strong pointer/reference.
virtual void onFirstRef();
// Invoked when either the last strong reference goes away, or we need to undo
// the effect of an unnecessary onIncStrongAttempted.
virtual void onLastStrongRef(const void* id);
// Only called in OBJECT_LIFETIME_WEAK case. Returns true if OK to promote to
// strong reference. May have side effects if it returns true.
// The first flags argument is always FIRST_INC_STRONG.
// TODO: Remove initial flag argument.
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
// Invoked in the OBJECT_LIFETIME_WEAK case when the last reference of either
// kind goes away. Unused.
// TODO: Remove.
virtual void onLastWeakRef(const void* id);
private:

View File

@ -56,26 +56,32 @@
namespace android {
// Usage, invariants, etc:
// Observations, invariants, etc:
// It is normally OK just to keep weak pointers to an object. The object will
// be deallocated by decWeak when the last weak reference disappears.
// Once a a strong reference has been created, the object will disappear once
// the last strong reference does (decStrong).
// AttemptIncStrong will succeed if the object has a strong reference, or if it
// has a weak reference and has never had a strong reference.
// AttemptIncWeak really does succeed only if there is already a WEAK
// reference, and thus may fail when attemptIncStrong would succeed.
// By default, obects are destroyed when the last strong reference disappears
// or, if the object never had a strong reference, when the last weak reference
// disappears.
//
// OBJECT_LIFETIME_WEAK changes this behavior to retain the object
// unconditionally until the last reference of either kind disappears. The
// client ensures that the extendObjectLifetime call happens before the dec
// call that would otherwise have deallocated the object, or before an
// attemptIncStrong call that might rely on it. We do not worry about
// concurrent changes to the object lifetime.
//
// AttemptIncStrong will succeed if the object has a strong reference, or if it
// has a weak reference and has never had a strong reference.
// AttemptIncWeak really does succeed only if there is already a WEAK
// reference, and thus may fail when attemptIncStrong would succeed.
//
// mStrong is the strong reference count. mWeak is the weak reference count.
// Between calls, and ignoring memory ordering effects, mWeak includes strong
// references, and is thus >= mStrong.
//
// A weakref_impl holds all the information, including both reference counts,
// required to perform wp<> operations. Thus these can continue to be performed
// after the RefBase object has been destroyed.
//
// A weakref_impl is allocated as the value of mRefs in a RefBase object on
// construction.
// In the OBJECT_LIFETIME_STRONG case, it is deallocated in the RefBase
@ -671,7 +677,8 @@ RefBase::~RefBase()
{
if (mRefs->mStrong.load(std::memory_order_relaxed)
== INITIAL_STRONG_VALUE) {
// we never acquired a strong (and/or weak) reference on this object.
// We never acquired a strong reference on this object.
// We assume there are no outstanding weak references.
delete mRefs;
} else {
// life-time of this object is extended to WEAK, in