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__) 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 44 static inline AtomicType loadAcquire(AtomicType volatile* ptr) { 45 AtomicType ret = *ptr; 46 acquireBarrier(); 47 return ret; 48 } 49 50 static inline void storeRelease(AtomicType volatile* ptr, AtomicType value) { 51 releaseBarrier(); 52 *ptr = value; 53 } 54 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 67 static void yieldThread() { 68 #ifdef _WIN32 69 ::Sleep(0); 70 #else 71 sched_yield(); 72 #endif 73 } 74 75 bool LazyInstanceState::inInitState() { 76 return loadAcquire(&mState) == STATE_INIT; 77 } 78 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 96 void LazyInstanceState::doneConstructing() { 97 storeRelease(&mState, STATE_DONE); 98 } 99 100 } // namespace internal 101 } // namespace emugl 102