teach TSAN about SkSpinlock, SkRefCnt, and SkOnce
BUG=skia: R=bsalomon@google.com, bungeman@google.com, mtklein@google.com Author: mtklein@chromium.org Review URL: https://codereview.chromium.org/247813005 git-svn-id: http://skia.googlecode.com/svn/trunk@14353 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
f0ae5e471b
commit
1d24eb20e7
@ -19,6 +19,10 @@ extern "C" {
|
|||||||
// TSAN provides these hooks.
|
// TSAN provides these hooks.
|
||||||
void AnnotateIgnoreReadsBegin(const char* file, int line);
|
void AnnotateIgnoreReadsBegin(const char* file, int line);
|
||||||
void AnnotateIgnoreReadsEnd(const char* file, int line);
|
void AnnotateIgnoreReadsEnd(const char* file, int line);
|
||||||
|
void AnnotateHappensBefore(const char* file, int line, const volatile void* ptr);
|
||||||
|
void AnnotateHappensAfter(const char* file, int line, const volatile void* ptr);
|
||||||
|
void AnnotateRWLockAcquired(const char* file, int line, const volatile void* lock, long is_w);
|
||||||
|
void AnnotateRWLockReleased(const char* file, int line, const volatile void* lock, long is_w);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
// SK_ANNOTATE_UNPROTECTED_READ can wrap any variable read to tell TSAN to ignore that it appears to
|
// SK_ANNOTATE_UNPROTECTED_READ can wrap any variable read to tell TSAN to ignore that it appears to
|
||||||
@ -37,9 +41,19 @@ inline T SK_ANNOTATE_UNPROTECTED_READ(const volatile T& x) {
|
|||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SK_ANNOTATE_HAPPENS_BEFORE(obj) AnnotateHappensBefore(__FILE__, __LINE__, obj)
|
||||||
|
#define SK_ANNOTATE_HAPPENS_AFTER(obj) AnnotateHappensAfter(__FILE__, __LINE__, obj)
|
||||||
|
|
||||||
|
#define SK_ANNOTATE_RWLOCK_ACQUIRED(lock, w) AnnotateRWLockAcquired(__FILE__, __LINE__, lock, w)
|
||||||
|
#define SK_ANNOTATE_RWLOCK_RELEASED(lock, w) AnnotateRWLockReleased(__FILE__, __LINE__, lock, w)
|
||||||
|
|
||||||
#else // !DYNAMIC_ANNOTATIONS_ENABLED
|
#else // !DYNAMIC_ANNOTATIONS_ENABLED
|
||||||
|
|
||||||
#define SK_ANNOTATE_UNPROTECTED_READ(x) (x)
|
#define SK_ANNOTATE_UNPROTECTED_READ(x) (x)
|
||||||
|
#define SK_ANNOTATE_HAPPENS_BEFORE(obj)
|
||||||
|
#define SK_ANNOTATE_HAPPENS_AFTER(obj)
|
||||||
|
#define SK_ANNOTATE_RWLOCK_ACQUIRED(lock, w)
|
||||||
|
#define SK_ANNOTATE_RWLOCK_RELEASED(lock, w)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -54,10 +54,12 @@ struct SkSpinlock {
|
|||||||
while (!sk_atomic_cas(&thisIsPrivate, 0, 1)) {
|
while (!sk_atomic_cas(&thisIsPrivate, 0, 1)) {
|
||||||
// spin
|
// spin
|
||||||
}
|
}
|
||||||
|
SK_ANNOTATE_RWLOCK_ACQUIRED(this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void release() {
|
void release() {
|
||||||
SkASSERT(shouldBeZero == 0);
|
SkASSERT(shouldBeZero == 0);
|
||||||
|
SK_ANNOTATE_RWLOCK_RELEASED(this, true);
|
||||||
// This requires a release memory barrier before storing, which sk_atomic_cas guarantees.
|
// This requires a release memory barrier before storing, which sk_atomic_cas guarantees.
|
||||||
SkAssertResult(sk_atomic_cas(&thisIsPrivate, 1, 0));
|
SkAssertResult(sk_atomic_cas(&thisIsPrivate, 1, 0));
|
||||||
}
|
}
|
||||||
@ -145,6 +147,7 @@ static void sk_once_slow(bool* done, Lock* lock, Func f, Arg arg, void (*atExit)
|
|||||||
// observable whenever we observe *done == true.
|
// observable whenever we observe *done == true.
|
||||||
release_barrier();
|
release_barrier();
|
||||||
*done = true;
|
*done = true;
|
||||||
|
SK_ANNOTATE_HAPPENS_BEFORE(done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,6 +168,7 @@ inline void SkOnce(bool* done, Lock* lock, Func f, Arg arg, void(*atExit)()) {
|
|||||||
// happens after f(arg), so by syncing to once->done = true here we're
|
// happens after f(arg), so by syncing to once->done = true here we're
|
||||||
// forcing ourselves to also wait until the effects of f(arg) are readble.
|
// forcing ourselves to also wait until the effects of f(arg) are readble.
|
||||||
acquire_barrier();
|
acquire_barrier();
|
||||||
|
SK_ANNOTATE_HAPPENS_AFTER(done);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func, typename Arg>
|
template <typename Func, typename Arg>
|
||||||
|
@ -37,7 +37,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual ~SkRefCntBase() {
|
virtual ~SkRefCntBase() {
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
SkASSERT(fRefCnt == 1);
|
SkASSERT(this->unique());
|
||||||
fRefCnt = 0; // illegal value, to catch us if we reuse after delete
|
fRefCnt = 0; // illegal value, to catch us if we reuse after delete
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -53,6 +53,7 @@ public:
|
|||||||
// an unproctected read. Generally, don't read fRefCnt, and don't stifle this warning.
|
// an unproctected read. Generally, don't read fRefCnt, and don't stifle this warning.
|
||||||
bool const unique = (1 == SK_ANNOTATE_UNPROTECTED_READ(fRefCnt));
|
bool const unique = (1 == SK_ANNOTATE_UNPROTECTED_READ(fRefCnt));
|
||||||
if (unique) {
|
if (unique) {
|
||||||
|
SK_ANNOTATE_HAPPENS_AFTER(this);
|
||||||
// Acquire barrier (L/SL), if not provided by load of fRefCnt.
|
// Acquire barrier (L/SL), if not provided by load of fRefCnt.
|
||||||
// Prevents user's 'unique' code from happening before decrements.
|
// Prevents user's 'unique' code from happening before decrements.
|
||||||
//TODO: issue the barrier.
|
//TODO: issue the barrier.
|
||||||
@ -63,7 +64,7 @@ public:
|
|||||||
/** Increment the reference count. Must be balanced by a call to unref().
|
/** Increment the reference count. Must be balanced by a call to unref().
|
||||||
*/
|
*/
|
||||||
void ref() const {
|
void ref() const {
|
||||||
SkASSERT(fRefCnt > 0);
|
SkASSERT(this->unsafeGetRefCnt() > 0);
|
||||||
sk_atomic_inc(&fRefCnt); // No barrier required.
|
sk_atomic_inc(&fRefCnt); // No barrier required.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,9 +73,11 @@ public:
|
|||||||
the object needs to have been allocated via new, and not on the stack.
|
the object needs to have been allocated via new, and not on the stack.
|
||||||
*/
|
*/
|
||||||
void unref() const {
|
void unref() const {
|
||||||
SkASSERT(fRefCnt > 0);
|
SkASSERT(this->unsafeGetRefCnt() > 0);
|
||||||
|
SK_ANNOTATE_HAPPENS_BEFORE(this);
|
||||||
// Release barrier (SL/S), if not provided below.
|
// Release barrier (SL/S), if not provided below.
|
||||||
if (sk_atomic_dec(&fRefCnt) == 1) {
|
if (sk_atomic_dec(&fRefCnt) == 1) {
|
||||||
|
SK_ANNOTATE_HAPPENS_AFTER(this);
|
||||||
// Acquire barrier (L/SL), if not provided above.
|
// Acquire barrier (L/SL), if not provided above.
|
||||||
// Prevents code in dispose from happening before the decrement.
|
// Prevents code in dispose from happening before the decrement.
|
||||||
sk_membar_acquire__after_atomic_dec();
|
sk_membar_acquire__after_atomic_dec();
|
||||||
@ -84,7 +87,7 @@ public:
|
|||||||
|
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
void validate() const {
|
void validate() const {
|
||||||
SkASSERT(fRefCnt > 0);
|
SkASSERT(this->unsafeGetRefCnt() > 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -103,6 +106,9 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// OK for use in asserts, but not much else.
|
||||||
|
int32_t unsafeGetRefCnt() { return SK_ANNOTATE_UNPROTECTED_READ(fRefCnt); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the ref count goes to 0.
|
* Called when the ref count goes to 0.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user