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 // This isn't technically portable, but on Linux and Android pthread_t is some sort of int, and 17 // on Darwin it's a pointer. So assuming pthread_self() never returns 0, it works as a sentinel. 18 SkDEBUGCODE(static const pthread_t kNoOwner = 0;) 19 20 // A SkBaseMutex is a POD structure that can be directly initialized 21 // at declaration time with SK_DECLARE_STATIC/GLOBAL_MUTEX. This avoids the 22 // generation of a static initializer in the final machine code (and 23 // a corresponding static finalizer). 24 struct SkBaseMutex { 25 void acquire() { 26 SkASSERT(0 == pthread_equal(fOwner, pthread_self())); // SkMutex is not re-entrant 27 pthread_mutex_lock(&fMutex); 28 SkDEBUGCODE(fOwner = pthread_self();) 29 } 30 void release() { 31 this->assertHeld(); 32 SkDEBUGCODE(fOwner = kNoOwner;) 33 pthread_mutex_unlock(&fMutex); 34 } 35 void assertHeld() { 36 SkASSERT(0 != pthread_equal(fOwner, pthread_self())); 37 } 38 39 pthread_mutex_t fMutex; 40 SkDEBUGCODE(pthread_t fOwner;) 41 }; 42 43 // A normal mutex that requires to be initialized through normal C++ construction, 44 // i.e. when it's a member of another class, or allocated on the heap. 45 class SkMutex : public SkBaseMutex { 46 public: 47 SkMutex() { 48 SkDEBUGCODE(int status = )pthread_mutex_init(&fMutex, NULL); 49 SkDEBUGCODE( 50 if (status != 0) { 51 print_pthread_error(status); 52 SkASSERT(0 == status); 53 } 54 fOwner = kNoOwner; 55 ) 56 } 57 58 ~SkMutex() { 59 SkDEBUGCODE(int status = )pthread_mutex_destroy(&fMutex); 60 SkDEBUGCODE( 61 if (status != 0) { 62 print_pthread_error(status); 63 SkASSERT(0 == status); 64 } 65 ) 66 } 67 68 private: 69 SkMutex(const SkMutex&); 70 SkMutex& operator=(const SkMutex&); 71 72 static void print_pthread_error(int status) { 73 switch (status) { 74 case 0: // success 75 break; 76 case EINVAL: 77 SkDebugf("pthread error [%d] EINVAL\n", status); 78 break; 79 case EBUSY: 80 SkDebugf("pthread error [%d] EBUSY\n", status); 81 break; 82 default: 83 SkDebugf("pthread error [%d] unknown\n", status); 84 break; 85 } 86 } 87 }; 88 89 #define SK_BASE_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, SkDEBUGCODE(0) } 90 91 // Using POD-style initialization prevents the generation of a static initializer. 92 // 93 // Without magic statics there are no thread safety guarantees on initialization 94 // of local statics (even POD). As a result, it is illegal to use 95 // SK_DECLARE_STATIC_MUTEX in a function. 96 // 97 // Because SkBaseMutex is not a primitive, a static SkBaseMutex cannot be 98 // initialized in a class with this macro. 99 #define SK_DECLARE_STATIC_MUTEX(name) namespace {} static SkBaseMutex name = SK_BASE_MUTEX_INIT 100 101 #endif 102