| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2013 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #ifndef SkMutex_pthread_DEFINED | |
| 9 #define SkMutex_pthread_DEFINED | |
| 10 | |
| 11 /** Posix pthread_mutex based mutex. */ | |
| 12 | |
| 13 #include <errno.h> | |
| 14 #include <pthread.h> | |
| 15 | |
| 16 // We use error-checking mutexes in Debug builds or normal fast mutexes in Relea
se builds. | |
| 17 // Debug builds get these checks for free: | |
| 18 // - a double acquire() from the same thread fails immediately instead of dead
locking; | |
| 19 // - release() checks that the mutex is being unlocked by its owner thread. | |
| 20 // I don't see a built-in way to implement assertHeld(), so we track that with a
n fOwner field. | |
| 21 | |
| 22 // This isn't technically portable, but on Linux and Android pthread_t is some s
ort of int, and | |
| 23 // on Darwin it's a pointer. So assuming pthread_self() never returns 0, it wor
ks as a sentinel. | |
| 24 SkDEBUGCODE(static const pthread_t kNoOwner = 0;) | |
| 25 | |
| 26 // An SkBaseMutex is a POD structure that can be directly initialized at declara
tion time with | |
| 27 // SK_DECLARE_STATIC_MUTEX. This avoids the generation of a static initializer i
n the final | |
| 28 // machine code (and a corresponding static finalizer). | |
| 29 struct SkBaseMutex { | |
| 30 void acquire() { | |
| 31 SkDEBUGCODE(int rc = ) pthread_mutex_lock(&fMutex); | |
| 32 SkASSERT(0 == rc); | |
| 33 SkDEBUGCODE(fOwner = pthread_self();) | |
| 34 } | |
| 35 void release() { | |
| 36 this->assertHeld(); // Usually redundant, but not for static mutexes on
Macs (see below). | |
| 37 SkDEBUGCODE(fOwner = kNoOwner;) | |
| 38 SkDEBUGCODE(int rc = ) pthread_mutex_unlock(&fMutex); | |
| 39 SkASSERT(0 == rc); | |
| 40 } | |
| 41 void assertHeld() { | |
| 42 SkASSERT(0 != pthread_equal(fOwner, pthread_self())); | |
| 43 } | |
| 44 | |
| 45 pthread_mutex_t fMutex; | |
| 46 SkDEBUGCODE(pthread_t fOwner;) // Read and write only when holding fMutex. | |
| 47 }; | |
| 48 | |
| 49 // A normal mutex that's required to be initialized through normal C++ construct
ion, | |
| 50 // i.e. when it's a member of another class, or allocated on the heap. | |
| 51 class SkMutex : public SkBaseMutex { | |
| 52 public: | |
| 53 SkMutex() { | |
| 54 #ifdef SK_DEBUG | |
| 55 pthread_mutexattr_t attr; | |
| 56 SkASSERT(0 == pthread_mutexattr_init(&attr)); | |
| 57 SkASSERT(0 == pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)
); | |
| 58 SkASSERT(0 == pthread_mutex_init(&fMutex, &attr)); | |
| 59 SkASSERT(0 == pthread_mutexattr_destroy(&attr)); | |
| 60 fOwner = kNoOwner; | |
| 61 #else | |
| 62 (void)pthread_mutex_init(&fMutex, NULL); | |
| 63 #endif | |
| 64 } | |
| 65 | |
| 66 ~SkMutex() { | |
| 67 SkDEBUGCODE(int rc = )pthread_mutex_destroy(&fMutex); | |
| 68 SkASSERT(0 == rc); | |
| 69 } | |
| 70 | |
| 71 private: | |
| 72 SkMutex(const SkMutex&); | |
| 73 SkMutex& operator=(const SkMutex&); | |
| 74 }; | |
| 75 | |
| 76 #if defined(SK_DEBUG) && defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) | |
| 77 // When possible we want to use error-check mutexes in Debug builds. See th
e note at the top. | |
| 78 #define SK_BASE_MUTEX_INIT { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER, kNoOwner
} | |
| 79 #elif defined(SK_DEBUG) | |
| 80 // Macs don't support PTHREAD_ERRORCHECK_MUTEX_INITIALIZER when targeting <1
0.7. We target 10.6. | |
| 81 #define SK_BASE_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, kNoOwner } | |
| 82 #else | |
| 83 #define SK_BASE_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER } | |
| 84 #endif | |
| 85 | |
| 86 // Using POD-style initialization prevents the generation of a static initialize
r. | |
| 87 // | |
| 88 // Without magic statics there are no thread safety guarantees on initialization | |
| 89 // of local statics (even POD). As a result, it is illegal to use | |
| 90 // SK_DECLARE_STATIC_MUTEX in a function. | |
| 91 // | |
| 92 // Because SkBaseMutex is not a primitive, a static SkBaseMutex cannot be | |
| 93 // initialized in a class with this macro. | |
| 94 #define SK_DECLARE_STATIC_MUTEX(name) namespace {} static SkBaseMutex name = SK_
BASE_MUTEX_INIT | |
| 95 | |
| 96 #endif | |
| OLD | NEW |