1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 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 #ifndef sw_MutexLock_hpp 16 #define sw_MutexLock_hpp 17 18 #include "Thread.hpp" 19 20 #ifdef __ANDROID__ 21 /* Use an actual mutex on android. Since many processes may use switchshader 22 at the same time it's best to just have the scheduler overhead. */ 23 #include <pthread.h> 24 25 namespace sw 26 { 27 class BackoffLock 28 { 29 public: BackoffLock()30 BackoffLock() 31 { 32 pthread_mutex_init(&mutex, NULL); 33 } ~BackoffLock()34 ~BackoffLock() 35 { 36 pthread_mutex_destroy(&mutex); 37 } 38 attemptLock()39 bool attemptLock() 40 { 41 if (pthread_mutex_trylock(&mutex) == 0) 42 { 43 return true; 44 } 45 return false; 46 } 47 lock()48 void lock() 49 { 50 pthread_mutex_lock(&mutex); 51 } 52 unlock()53 void unlock() 54 { 55 pthread_mutex_unlock(&mutex); 56 } 57 58 private: 59 struct 60 { 61 // Ensure that the mutex variable is on its own 64-byte cache line to avoid false sharing 62 // Padding must be public to avoid compiler warnings 63 volatile int padding1[16]; 64 pthread_mutex_t mutex; 65 volatile int padding2[15]; 66 }; 67 }; 68 } 69 70 #else 71 72 namespace sw 73 { 74 class BackoffLock 75 { 76 public: BackoffLock()77 BackoffLock() 78 { 79 mutex = 0; 80 } 81 attemptLock()82 bool attemptLock() 83 { 84 if(!isLocked()) 85 { 86 if(atomicExchange(&mutex, 1) == 0) 87 { 88 return true; 89 } 90 } 91 92 return false; 93 } 94 lock()95 void lock() 96 { 97 int backoff = 1; 98 99 while(!attemptLock()) 100 { 101 if(backoff <= 64) 102 { 103 for(int i = 0; i < backoff; i++) 104 { 105 nop(); 106 nop(); 107 nop(); 108 nop(); 109 nop(); 110 111 nop(); 112 nop(); 113 nop(); 114 nop(); 115 nop(); 116 117 nop(); 118 nop(); 119 nop(); 120 nop(); 121 nop(); 122 123 nop(); 124 nop(); 125 nop(); 126 nop(); 127 nop(); 128 129 nop(); 130 nop(); 131 nop(); 132 nop(); 133 nop(); 134 135 nop(); 136 nop(); 137 nop(); 138 nop(); 139 nop(); 140 141 nop(); 142 nop(); 143 nop(); 144 nop(); 145 nop(); 146 } 147 148 backoff *= 2; 149 } 150 else 151 { 152 Thread::yield(); 153 154 backoff = 1; 155 } 156 }; 157 } 158 unlock()159 void unlock() 160 { 161 mutex = 0; 162 } 163 isLocked()164 bool isLocked() 165 { 166 return mutex != 0; 167 } 168 169 private: 170 struct 171 { 172 // Ensure that the mutex variable is on its own 64-byte cache line to avoid false sharing 173 // Padding must be public to avoid compiler warnings 174 volatile int padding1[16]; 175 volatile int mutex; 176 volatile int padding2[15]; 177 }; 178 }; 179 } 180 #endif // __android 181 182 #endif // sw_MutexLock_hpp 183