Add a 'unique' method to SkRefCnt, document the usage, and add support.
std::shared_ptr has a method called 'unique' which captures the concept that a reference count of 1 is special, and can be used to optimize copy on write. It also has some undocumented need for memory barriers in certain situations and those needs are documented here. The motivation for looking into this is crbug.com/258499 . The use of the reference count in this manner is a benign race with both ref() and unref(). By introducing sk_atomic_unprotected_read, it is possible for Chromium to annotate this read to tell ThreadSanitizer that this is known. R=bsalomon@google.com Review URL: https://codereview.chromium.org/18770007 git-svn-id: http://skia.googlecode.com/svn/trunk@10221 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
13388e7164
commit
f64c6842c1
@ -41,10 +41,22 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Return the reference count.
|
||||
*/
|
||||
/** Return the reference count. Use only for debugging. */
|
||||
int32_t getRefCnt() const { return fRefCnt; }
|
||||
|
||||
/** Returns true if the caller is the only owner.
|
||||
* Ensures that all previous owner's actions are complete.
|
||||
*/
|
||||
bool unique() const {
|
||||
bool const unique = (1 == fRefCnt);
|
||||
if (unique) {
|
||||
// Aquire barrier (L/SL), if not provided by load of fRefCnt.
|
||||
// Prevents user's 'unique' code from happening before decrements.
|
||||
//TODO: issue the barrier.
|
||||
}
|
||||
return unique;
|
||||
}
|
||||
|
||||
/** Increment the reference count. Must be balanced by a call to unref().
|
||||
*/
|
||||
void ref() const {
|
||||
@ -71,16 +83,6 @@ public:
|
||||
SkASSERT(fRefCnt > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for ref(), for compatibility with scoped_refptr.
|
||||
*/
|
||||
void AddRef() { this->ref(); }
|
||||
|
||||
/**
|
||||
* Alias for unref(), for compatibility with scoped_refptr.
|
||||
*/
|
||||
void Release() { this->unref(); }
|
||||
|
||||
/**
|
||||
* Alias for unref(), for compatibility with WTF::RefPtr.
|
||||
*/
|
||||
@ -109,9 +111,10 @@ private:
|
||||
SkDELETE(this);
|
||||
}
|
||||
|
||||
// The following friends are those which override internal_dispose()
|
||||
// and conditionally call SkRefCnt::internal_dispose().
|
||||
friend class GrTexture;
|
||||
friend class SkWeakRefCnt;
|
||||
friend class GrTexture; // to allow GrTexture's internal_dispose to
|
||||
// call SkRefCnt's & directly set fRefCnt (to 1)
|
||||
|
||||
mutable int32_t fRefCnt;
|
||||
|
||||
|
@ -37,15 +37,16 @@ public:
|
||||
public:
|
||||
Editor(SkAutoTUnref<SkPathRef>* pathRef,
|
||||
int incReserveVerbs = 0,
|
||||
int incReservePoints = 0) {
|
||||
if (pathRef->get()->getRefCnt() > 1) {
|
||||
SkPathRef* copy = SkNEW(SkPathRef);
|
||||
copy->copy(*pathRef->get(), incReserveVerbs, incReservePoints);
|
||||
pathRef->reset(copy);
|
||||
} else {
|
||||
int incReservePoints = 0)
|
||||
{
|
||||
if ((*pathRef)->unique()) {
|
||||
(*pathRef)->incReserve(incReserveVerbs, incReservePoints);
|
||||
} else {
|
||||
SkPathRef* copy = SkNEW(SkPathRef);
|
||||
copy->copy(**pathRef, incReserveVerbs, incReservePoints);
|
||||
pathRef->reset(copy);
|
||||
}
|
||||
fPathRef = pathRef->get();
|
||||
fPathRef = *pathRef;
|
||||
fPathRef->fGenerationID = 0;
|
||||
SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
|
||||
}
|
||||
@ -135,18 +136,18 @@ public:
|
||||
const SkMatrix& matrix) {
|
||||
src.validate();
|
||||
if (matrix.isIdentity()) {
|
||||
if (dst->get() != &src) {
|
||||
if (*dst != &src) {
|
||||
src.ref();
|
||||
dst->reset(const_cast<SkPathRef*>(&src));
|
||||
(*dst)->validate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
int32_t rcnt = dst->get()->getRefCnt();
|
||||
if (&src == dst->get() && 1 == rcnt) {
|
||||
bool dstUnique = (*dst)->unique();
|
||||
if (&src == *dst && dstUnique) {
|
||||
matrix.mapPoints((*dst)->fPoints, (*dst)->fPointCnt);
|
||||
return;
|
||||
} else if (rcnt > 1) {
|
||||
} else if (!dstUnique) {
|
||||
dst->reset(SkNEW(SkPathRef));
|
||||
}
|
||||
(*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
|
||||
@ -179,7 +180,7 @@ public:
|
||||
* only if necessary.
|
||||
*/
|
||||
static void Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
|
||||
if (1 == (*pathRef)->getRefCnt()) {
|
||||
if ((*pathRef)->unique()) {
|
||||
(*pathRef)->validate();
|
||||
(*pathRef)->fVerbCnt = 0;
|
||||
(*pathRef)->fPointCnt = 0;
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
// call these, since other owners are not informed if we change an element.
|
||||
|
||||
T* writableBegin() {
|
||||
SkASSERT(1 == this->getRefCnt());
|
||||
SkASSERT(this->unique());
|
||||
return (T*)(this + 1);
|
||||
}
|
||||
T* writableEnd() {
|
||||
|
@ -69,9 +69,7 @@ void SkTypefaceCache::purge(int numToPurge) {
|
||||
while (i < count) {
|
||||
SkTypeface* face = fArray[i].fFace;
|
||||
bool strong = fArray[i].fStrong;
|
||||
if ((strong && face->getRefCnt() == 1) ||
|
||||
(!strong && face->weak_expired()))
|
||||
{
|
||||
if ((strong && face->unique()) || (!strong && face->weak_expired())) {
|
||||
if (strong) {
|
||||
face->unref();
|
||||
} else {
|
||||
|
@ -488,7 +488,7 @@ void GrContext::addExistingTextureToCache(GrTexture* texture) {
|
||||
|
||||
// Conceptually, the cache entry is going to assume responsibility
|
||||
// for the creation ref.
|
||||
GrAssert(1 == texture->getRefCnt());
|
||||
GrAssert(texture->unique());
|
||||
|
||||
// Since this texture came from an AutoScratchTexture it should
|
||||
// still be in the exclusive pile
|
||||
|
@ -63,7 +63,7 @@ int32_t GrBackendEffectFactory::fCurrEffectClassID = GrBackendEffectFactory::kIl
|
||||
SK_DEFINE_INST_COUNT(GrEffectRef)
|
||||
|
||||
GrEffectRef::~GrEffectRef() {
|
||||
GrAssert(1 == this->getRefCnt());
|
||||
GrAssert(this->unique());
|
||||
fEffect->EffectRefDestroyed();
|
||||
fEffect->unref();
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ void GrResourceCache::attachToHead(GrResourceEntry* entry,
|
||||
class GrTFindUnreffedFunctor {
|
||||
public:
|
||||
bool operator()(const GrResourceEntry* entry) const {
|
||||
return 1 == entry->resource()->getRefCnt();
|
||||
return entry->resource()->unique();
|
||||
}
|
||||
};
|
||||
|
||||
@ -338,7 +338,7 @@ void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) {
|
||||
}
|
||||
|
||||
GrResourceEntry* prev = iter.prev();
|
||||
if (1 == entry->fResource->getRefCnt()) {
|
||||
if (entry->fResource->unique()) {
|
||||
changed = true;
|
||||
this->deleteResource(entry);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
|
||||
// the surface may need to fork its backend, if its sharing it with
|
||||
// the cached image. Note: we only call if there is an outstanding owner
|
||||
// on the image (besides us).
|
||||
if (fCachedImage->getRefCnt() > 1) {
|
||||
if (!fCachedImage->unique()) {
|
||||
this->onCopyOnWrite(mode);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user