Home | History | Annotate | Download | only in common
      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