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 |