1 // Copyright (C) 2014 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "emugl/common/lazy_instance.h"
16
17 #ifdef _WIN32
18 # define WIN32_LEAN_AND_MEAN 1
19 # include <windows.h>
20 #else
21 # include <sched.h>
22 #endif
23
24 namespace emugl {
25 namespace internal {
26
27 typedef LazyInstanceState::AtomicType AtomicType;
28
29 #if defined(__GNUC__)
compilerBarrier()30 static inline void compilerBarrier() {
31 __asm__ __volatile__ ("" : : : "memory");
32 }
33 #else
34 #error "Your compiler is not supported"
35 #endif
36
37 #if defined(__i386__) || defined(__x86_64__)
38 # define acquireBarrier() compilerBarrier()
39 # define releaseBarrier() compilerBarrier()
40 #else
41 # error "Your CPU is not supported"
42 #endif
43
loadAcquire(AtomicType volatile * ptr)44 static inline AtomicType loadAcquire(AtomicType volatile* ptr) {
45 AtomicType ret = *ptr;
46 acquireBarrier();
47 return ret;
48 }
49
storeRelease(AtomicType volatile * ptr,AtomicType value)50 static inline void storeRelease(AtomicType volatile* ptr, AtomicType value) {
51 releaseBarrier();
52 *ptr = value;
53 }
54
atomicCompareAndSwap(AtomicType volatile * ptr,int expected,int value)55 static int atomicCompareAndSwap(AtomicType volatile* ptr,
56 int expected,
57 int value) {
58 #ifdef _WIN32
59 return InterlockedCompareExchange(ptr, value, expected);
60 #elif defined(__GNUC__)
61 return __sync_val_compare_and_swap(ptr, expected, value);
62 #else
63 #error "Your compiler is not supported"
64 #endif
65 }
66
yieldThread()67 static void yieldThread() {
68 #ifdef _WIN32
69 ::Sleep(0);
70 #else
71 sched_yield();
72 #endif
73 }
74
inInitState()75 bool LazyInstanceState::inInitState() {
76 return loadAcquire(&mState) == STATE_INIT;
77 }
78
needConstruction()79 bool LazyInstanceState::needConstruction() {
80 AtomicType state = loadAcquire(&mState);
81 if (mState == STATE_DONE)
82 return false;
83
84 state = atomicCompareAndSwap(&mState, STATE_INIT, STATE_CONSTRUCTING);
85 if (state == STATE_INIT)
86 return true;
87
88 do {
89 yieldThread();
90 state = loadAcquire(&mState);
91 } while (state != STATE_DONE);
92
93 return false;
94 }
95
doneConstructing()96 void LazyInstanceState::doneConstructing() {
97 storeRelease(&mState, STATE_DONE);
98 }
99
100 } // namespace internal
101 } // namespace emugl
102