1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkThread.h" 9 10 #include <pthread.h> 11 #include <errno.h> 12 13 #ifndef SK_BUILD_FOR_ANDROID 14 15 /** 16 We prefer the GCC intrinsic implementation of the atomic operations over the 17 SkMutex-based implementation. The SkMutex version suffers from static 18 destructor ordering problems. 19 Note clang also defines the GCC version macros and implements the intrinsics. 20 TODO: Verify that gcc-style __sync_* intrinsics work on ARM 21 According to this the intrinsics are supported on ARM in LLVM 2.7+ 22 http://llvm.org/releases/2.7/docs/ReleaseNotes.html 23 */ 24 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4 25 #if (defined(__x86_64) || defined(__i386__)) 26 #define GCC_INTRINSIC 27 #endif 28 #endif 29 30 #if defined(GCC_INTRINSIC) 31 32 int32_t sk_atomic_inc(int32_t* addr) 33 { 34 return __sync_fetch_and_add(addr, 1); 35 } 36 37 int32_t sk_atomic_add(int32_t* addr, int32_t inc) 38 { 39 return __sync_fetch_and_add(addr, inc); 40 } 41 42 int32_t sk_atomic_dec(int32_t* addr) 43 { 44 return __sync_fetch_and_add(addr, -1); 45 } 46 void sk_membar_aquire__after_atomic_dec() { } 47 48 int32_t sk_atomic_conditional_inc(int32_t* addr) 49 { 50 int32_t value = *addr; 51 52 while (true) { 53 if (value == 0) { 54 return 0; 55 } 56 57 int32_t before = __sync_val_compare_and_swap(addr, value, value + 1); 58 59 if (before == value) { 60 return value; 61 } else { 62 value = before; 63 } 64 } 65 } 66 void sk_membar_aquire__after_atomic_conditional_inc() { } 67 68 #else 69 70 SkMutex gAtomicMutex; 71 72 int32_t sk_atomic_inc(int32_t* addr) 73 { 74 SkAutoMutexAcquire ac(gAtomicMutex); 75 76 int32_t value = *addr; 77 *addr = value + 1; 78 return value; 79 } 80 81 int32_t sk_atomic_add(int32_t* addr, int32_t inc) 82 { 83 SkAutoMutexAcquire ac(gAtomicMutex); 84 85 int32_t value = *addr; 86 *addr = value + inc; 87 return value; 88 } 89 90 int32_t sk_atomic_dec(int32_t* addr) 91 { 92 SkAutoMutexAcquire ac(gAtomicMutex); 93 94 int32_t value = *addr; 95 *addr = value - 1; 96 return value; 97 } 98 void sk_membar_aquire__after_atomic_dec() { } 99 100 int32_t sk_atomic_conditional_inc(int32_t* addr) 101 { 102 SkAutoMutexAcquire ac(gAtomicMutex); 103 104 int32_t value = *addr; 105 if (value != 0) ++*addr; 106 return value; 107 } 108 void sk_membar_aquire__after_atomic_conditional_inc() { } 109 110 #endif 111 112 #endif // SK_BUILD_FOR_ANDROID 113 114 ////////////////////////////////////////////////////////////////////////////// 115 116 static void print_pthread_error(int status) { 117 switch (status) { 118 case 0: // success 119 break; 120 case EINVAL: 121 SkDebugf("pthread error [%d] EINVAL\n", status); 122 break; 123 case EBUSY: 124 SkDebugf("pthread error [%d] EBUSY\n", status); 125 break; 126 default: 127 SkDebugf("pthread error [%d] unknown\n", status); 128 break; 129 } 130 } 131 132 #ifdef SK_USE_POSIX_THREADS 133 134 SkMutex::SkMutex() { 135 int status; 136 137 status = pthread_mutex_init(&fMutex, NULL); 138 if (status != 0) { 139 print_pthread_error(status); 140 SkASSERT(0 == status); 141 } 142 } 143 144 SkMutex::~SkMutex() { 145 int status = pthread_mutex_destroy(&fMutex); 146 147 // only report errors on non-global mutexes 148 if (status != 0) { 149 print_pthread_error(status); 150 SkASSERT(0 == status); 151 } 152 } 153 154 #else // !SK_USE_POSIX_THREADS 155 156 SkMutex::SkMutex() { 157 if (sizeof(pthread_mutex_t) > sizeof(fStorage)) { 158 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t))); 159 SkDEBUGFAIL("mutex storage is too small"); 160 } 161 162 int status; 163 pthread_mutexattr_t attr; 164 165 status = pthread_mutexattr_init(&attr); 166 print_pthread_error(status); 167 SkASSERT(0 == status); 168 169 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr); 170 print_pthread_error(status); 171 SkASSERT(0 == status); 172 } 173 174 SkMutex::~SkMutex() { 175 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage); 176 #if 0 177 // only report errors on non-global mutexes 178 if (!fIsGlobal) { 179 print_pthread_error(status); 180 SkASSERT(0 == status); 181 } 182 #endif 183 } 184 185 void SkMutex::acquire() { 186 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage); 187 print_pthread_error(status); 188 SkASSERT(0 == status); 189 } 190 191 void SkMutex::release() { 192 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage); 193 print_pthread_error(status); 194 SkASSERT(0 == status); 195 } 196 197 #endif // !SK_USE_POSIX_THREADS 198