diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/core/SkDynamicAnnotations.h | 59 | ||||
-rw-r--r-- | include/core/SkLazyPtr.h | 2 | ||||
-rw-r--r-- | include/core/SkOnce.h | 38 | ||||
-rw-r--r-- | include/core/SkThreadPriv.h | 14 |
4 files changed, 23 insertions, 90 deletions
diff --git a/include/core/SkDynamicAnnotations.h b/include/core/SkDynamicAnnotations.h deleted file mode 100644 index 86b01814a8..0000000000 --- a/include/core/SkDynamicAnnotations.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkDynamicAnnotations_DEFINED -#define SkDynamicAnnotations_DEFINED - -// Make sure we see anything set via SkUserConfig.h (e.g. DYNAMIC_ANNOTATIONS_ENABLED). -#include "SkTypes.h" - -// This file contains macros used to send out-of-band signals to dynamic instrumentation systems, -// namely thread sanitizer. This is a cut-down version of the full dynamic_annotations library with -// only the features used by Skia. - -#if DYNAMIC_ANNOTATIONS_ENABLED - -extern "C" { -// TSAN provides these hooks. -void AnnotateIgnoreReadsBegin(const char* file, int line); -void AnnotateIgnoreReadsEnd(const char* file, int line); -void AnnotateIgnoreWritesBegin(const char* file, int line); -void AnnotateIgnoreWritesEnd(const char* file, int line); -} // extern "C" - -// SK_ANNOTATE_UNPROTECTED_READ can wrap any variable read to tell TSAN to ignore that it appears to -// be a racy read. This should be used only when we can make an external guarantee that though this -// particular read is racy, it is being used as part of a mechanism which is thread safe. Examples: -// - the first check in double-checked locking; -// - checking if a ref count is equal to 1. -// Note that in both these cases, we must still add terrifyingly subtle memory barriers to provide -// that overall thread safety guarantee. Using this macro to shut TSAN up without providing such an -// external guarantee is pretty much never correct. -template <typename T> -inline T SK_ANNOTATE_UNPROTECTED_READ(const volatile T& x) { - AnnotateIgnoreReadsBegin(__FILE__, __LINE__); - T read = x; - AnnotateIgnoreReadsEnd(__FILE__, __LINE__); - return read; -} - -// Like SK_ANNOTATE_UNPROTECTED_READ, but for writes. -template <typename T> -inline void SK_ANNOTATE_UNPROTECTED_WRITE(T* ptr, const T& val) { - AnnotateIgnoreWritesBegin(__FILE__, __LINE__); - *ptr = val; - AnnotateIgnoreWritesEnd(__FILE__, __LINE__); -} - -#else // !DYNAMIC_ANNOTATIONS_ENABLED - -#define SK_ANNOTATE_UNPROTECTED_READ(x) (x) -#define SK_ANNOTATE_UNPROTECTED_WRITE(ptr, val) *(ptr) = (val) - -#endif - -#endif//SkDynamicAnnotations_DEFINED diff --git a/include/core/SkLazyPtr.h b/include/core/SkLazyPtr.h index fb2e43e874..035a269add 100644 --- a/include/core/SkLazyPtr.h +++ b/include/core/SkLazyPtr.h @@ -103,7 +103,7 @@ template <typename T> void sk_delete(T* ptr) { SkDELETE(ptr); } template <typename T> T consume_load(T* ptr) { -#if DYNAMIC_ANNOTATIONS_ENABLED +#if defined(THREAD_SANITIZER) // TSAN gets anxious if we don't tell it what we're actually doing, a consume load. return sk_atomic_load(ptr, sk_memory_order_consume); #else diff --git a/include/core/SkOnce.h b/include/core/SkOnce.h index f025cc2abf..c26c49fca5 100644 --- a/include/core/SkOnce.h +++ b/include/core/SkOnce.h @@ -27,9 +27,7 @@ // No matter how many times you call EnsureRegistered(), register_my_stuff will be called just once. // OnceTest.cpp also should serve as a few other simple examples. -#include "SkDynamicAnnotations.h" -#include "SkThread.h" -#include "SkTypes.h" +#include "SkAtomics.h" // This must be used in a global scope, not in fuction scope or as a class member. #define SK_DECLARE_STATIC_ONCE(name) namespace {} static SkOnceFlag name @@ -85,7 +83,7 @@ private: template <typename Lock, typename Arg> static void sk_once_slow(bool* done, Lock* lock, void (*f)(Arg), Arg arg) { lock->acquire(); - if (!*done) { + if (!sk_atomic_load(done, sk_memory_order_relaxed)) { f(arg); // Also known as a store-store/load-store barrier, this makes sure that the writes // done before here---in particular, those done by calling f(arg)---are observable @@ -104,20 +102,28 @@ static void sk_once_slow(bool* done, Lock* lock, void (*f)(Arg), Arg arg) { // This is our fast path, called all the time. We do really want it to be inlined. template <typename Lock, typename Arg> inline void SkOnce(bool* done, Lock* lock, void (*f)(Arg), Arg arg) { - if (!SK_ANNOTATE_UNPROTECTED_READ(*done)) { - sk_once_slow(done, lock, f, arg); - } - // Also known as a load-load/load-store barrier, this acquire barrier makes - // sure that anything we read from memory---in particular, memory written by - // calling f(arg)---is at least as current as the value we read from done. + // When *done == true: + // Also known as a load-load/load-store barrier, this acquire barrier makes + // sure that anything we read from memory---in particular, memory written by + // calling f(arg)---is at least as current as the value we read from done. + // + // In version control terms, this is a lot like saying "sync up to the + // commit where we wrote done = true". // - // In version control terms, this is a lot like saying "sync up to the - // commit where we wrote done = true". + // The release barrier in sk_once_slow guaranteed that done = true + // happens after f(arg), so by syncing to done = true here we're + // forcing ourselves to also wait until the effects of f(arg) are readble. // - // The release barrier in sk_once_slow guaranteed that done = true - // happens after f(arg), so by syncing to done = true here we're - // forcing ourselves to also wait until the effects of f(arg) are readble. - SkAssertResult(sk_acquire_load(done)); + // When *done == false: + // We'll try to call f(arg) in sk_once_slow. + // If we get the lock, great, we call f(arg), release true into done, and drop the lock. + // If we race and don't get the lock first, we'll wait for the first guy to finish. + // Then lock acquire() will give us at least an acquire memory barrier to get the same + // effect as the acquire load in the *done == true fast case. We'll see *done is true, + // then just drop the lock and return. + if (!sk_atomic_load(done, sk_memory_order_acquire)) { + sk_once_slow(done, lock, f, arg); + } } template <typename Arg> diff --git a/include/core/SkThreadPriv.h b/include/core/SkThreadPriv.h deleted file mode 100644 index aca71a6709..0000000000 --- a/include/core/SkThreadPriv.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkThreadPriv_DEFINED -#define SkThreadPriv_DEFINED - -// TODO: delete this file -#include "SkAtomics.h" - -#endif//SkThreadPriv_DEFINED |