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 sk_atomic_inc(int32_t * addr)32int32_t sk_atomic_inc(int32_t* addr) 33 { 34 return __sync_fetch_and_add(addr, 1); 35 } 36 sk_atomic_dec(int32_t * addr)37int32_t sk_atomic_dec(int32_t* addr) 38 { 39 return __sync_fetch_and_add(addr, -1); 40 } 41 42 #else 43 44 SkMutex gAtomicMutex; 45 sk_atomic_inc(int32_t * addr)46int32_t sk_atomic_inc(int32_t* addr) 47 { 48 SkAutoMutexAcquire ac(gAtomicMutex); 49 50 int32_t value = *addr; 51 *addr = value + 1; 52 return value; 53 } 54 sk_atomic_dec(int32_t * addr)55int32_t sk_atomic_dec(int32_t* addr) 56 { 57 SkAutoMutexAcquire ac(gAtomicMutex); 58 59 int32_t value = *addr; 60 *addr = value - 1; 61 return value; 62 } 63 64 #endif 65 66 #endif // SK_BUILD_FOR_ANDROID 67 68 ////////////////////////////////////////////////////////////////////////////// 69 print_pthread_error(int status)70static void print_pthread_error(int status) { 71 switch (status) { 72 case 0: // success 73 break; 74 case EINVAL: 75 SkDebugf("pthread error [%d] EINVAL\n", status); 76 break; 77 case EBUSY: 78 SkDebugf("pthread error [%d] EBUSY\n", status); 79 break; 80 default: 81 SkDebugf("pthread error [%d] unknown\n", status); 82 break; 83 } 84 } 85 86 #ifdef SK_USE_POSIX_THREADS 87 SkMutex()88SkMutex::SkMutex() { 89 int status; 90 91 status = pthread_mutex_init(&fMutex, NULL); 92 if (status != 0) { 93 print_pthread_error(status); 94 SkASSERT(0 == status); 95 } 96 } 97 ~SkMutex()98SkMutex::~SkMutex() { 99 int status = pthread_mutex_destroy(&fMutex); 100 101 // only report errors on non-global mutexes 102 if (status != 0) { 103 print_pthread_error(status); 104 SkASSERT(0 == status); 105 } 106 } 107 108 #else // !SK_USE_POSIX_THREADS 109 SkMutex()110SkMutex::SkMutex() { 111 if (sizeof(pthread_mutex_t) > sizeof(fStorage)) { 112 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t))); 113 SkDEBUGFAIL("mutex storage is too small"); 114 } 115 116 int status; 117 pthread_mutexattr_t attr; 118 119 status = pthread_mutexattr_init(&attr); 120 print_pthread_error(status); 121 SkASSERT(0 == status); 122 123 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr); 124 print_pthread_error(status); 125 SkASSERT(0 == status); 126 } 127 ~SkMutex()128SkMutex::~SkMutex() { 129 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage); 130 #if 0 131 // only report errors on non-global mutexes 132 if (!fIsGlobal) { 133 print_pthread_error(status); 134 SkASSERT(0 == status); 135 } 136 #endif 137 } 138 acquire()139void SkMutex::acquire() { 140 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage); 141 print_pthread_error(status); 142 SkASSERT(0 == status); 143 } 144 release()145void SkMutex::release() { 146 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage); 147 print_pthread_error(status); 148 SkASSERT(0 == status); 149 } 150 151 #endif // !SK_USE_POSIX_THREADS 152