Home | History | Annotate | Download | only in ports
      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