Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #ifndef SkOnce_DEFINED | |
| 2 #define SkOnce_DEFINED | |
| 3 | |
| 4 // TODO: docs | |
| 5 | |
| 6 #include "SkThread.h" | |
| 7 #include "SkTypes.h" | |
| 8 | |
| 9 #define DEF_SK_ONCE(name, arg) \ | |
| 10 static bool sk_once##name##ready = false; \ | |
|
bungeman-skia
2013/10/08 22:34:59
nit: can we put some '__' before and after name? I
mtklein
2013/10/09 15:22:25
You betcha. Done. Took the opportunity to rename
| |
| 11 SK_DECLARE_STATIC_MUTEX(sk_once##name##mutex); \ | |
| 12 static void sk_once##name##function(arg) | |
| 13 | |
| 14 | |
| 15 inline static void compiler_barrier() { | |
|
bungeman-skia
2013/10/08 22:34:59
note that on Windows this is _ReadWriteBarrier, no
mtklein
2013/10/09 15:22:25
Done.
| |
| 16 asm volatile("" ::: "memory"); | |
| 17 } | |
| 18 | |
| 19 inline static void full_barrier_on_arm() { | |
| 20 #ifdef SK_CPU_ARM | |
| 21 asm volatile("dmb" ::: "memory"); | |
|
bungeman-skia
2013/10/08 22:34:59
note that android has android_memory_barrier and a
mtklein
2013/10/09 15:22:25
Yeah. Given that ARM doesn't quite imply Android,
| |
| 22 #endif | |
| 23 } | |
| 24 | |
| 25 // On every platform, we issue a compiler barrier to prevent it from reordering | |
| 26 // code. That's enough for platforms like x86 where release and acquire | |
| 27 // barriers are no-ops. On other platforms we may need to be more careful; | |
| 28 // ARM, in particular, needs real code for both acquire and release. We use a | |
| 29 // full barrier, which acts as both, because that the finest precision ARM | |
| 30 // provides. | |
| 31 | |
| 32 inline static void release_barrier() { | |
| 33 compiler_barrier(); | |
| 34 full_barrier_on_arm(); | |
| 35 } | |
| 36 | |
| 37 inline static void acquire_barrier() { | |
|
bungeman-skia
2013/10/08 22:34:59
of course, all of this goes in some future cleaned
mtklein
2013/10/09 15:22:25
Agreed. I've added a note to remind us.
| |
| 38 compiler_barrier(); | |
| 39 full_barrier_on_arm(); | |
| 40 } | |
| 41 | |
| 42 // This should be rarely called, so we separate it from sk_once_impl and don't m ark it as inline. | |
| 43 template <typename Arg> | |
| 44 static void sk_once_impl_slow(bool* ready, SkBaseMutex* mutex, void (*once)(Arg) , Arg arg) { | |
| 45 const SkAutoMutexAcquire lock(*mutex); | |
| 46 if (!*ready) { | |
| 47 once(arg); | |
| 48 release_barrier(); | |
|
bungeman-skia
2013/10/08 22:34:59
I know that we know why these barriers are where t
mtklein
2013/10/09 15:22:25
Yeah, that was the TODO. How's this read to you n
| |
| 49 *ready = true; | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 // Thread sanitizer provides a hook to stifle a known safe race. | |
| 54 extern "C" { | |
| 55 void AnnotateBenignRace(const char* file, int line, const volatile void* mem, co nst char* desc); | |
| 56 } | |
| 57 // We need to define it as a no-op if we're not using TSAN | |
| 58 #if SK_HAS_COMPILER_FEATURE(thread_sanitizer) | |
|
bungeman-skia
2013/10/08 22:34:59
SK_HAS_COMPILER_FEATURE is only available on clang
mtklein
2013/10/09 15:22:25
Done.
| |
| 59 # define ANNOTATE_BENIGN_RACE(file, line, mem, desc) AnnotateBenignRace(file, l ine, mem, desc) | |
| 60 #else | |
| 61 # define ANNOTATE_BENIGN_RACE(file, line, mem, desc) | |
| 62 #endif | |
| 63 | |
| 64 template <typename Arg> | |
| 65 inline static void sk_once_impl(bool* ready, SkBaseMutex* mutex, void (*once)(Ar g), Arg arg) { | |
| 66 ANNOTATE_BENIGN_RACE(__FILE__, __LINE__, ready, "Don't worry TSAN, we're sur e this is safe."); | |
| 67 if (!*ready) { | |
| 68 sk_once_impl_slow(ready, mutex, once, arg); | |
| 69 } | |
| 70 acquire_barrier(); | |
|
bungeman-skia
2013/10/08 22:34:59
A comment like "Ensure that we see the effects of
mtklein
2013/10/09 15:22:25
Done.
| |
| 71 } | |
| 72 | |
| 73 #undef ANNOTATE_BENIGN_RACE | |
| 74 | |
| 75 #define SK_ONCE(name, arg) \ | |
| 76 sk_once_impl(&sk_once##name##ready, &sk_once##name##mutex, sk_once##name##fu nction, arg) | |
| 77 | |
| 78 #endif // SkOnce_DEFINED | |
| OLD | NEW |