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. 18SkDEBUGCODE(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). 24struct 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. 45class SkMutex : public SkBaseMutex { 46public: 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 68private: 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