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 // A SkBaseMutex is a POD structure that can be directly initialized
     17 // at declaration time with SK_DECLARE_STATIC/GLOBAL_MUTEX. This avoids the
     18 // generation of a static initializer in the final machine code (and
     19 // a corresponding static finalizer).
     20 struct SkBaseMutex {
     21     void acquire() {
     22         SkASSERT(fOwner != pthread_self());  // SkMutex is not re-entrant
     23         pthread_mutex_lock(&fMutex);
     24         SkDEBUGCODE(fOwner = pthread_self();)
     25     }
     26     void release() {
     27         this->assertHeld();
     28         SkDEBUGCODE(fOwner = 0;)
     29         pthread_mutex_unlock(&fMutex);
     30     }
     31     void assertHeld() {
     32         SkASSERT(pthread_self() == fOwner);
     33     }
     34 
     35     pthread_mutex_t fMutex;
     36     SkDEBUGCODE(pthread_t fOwner;)
     37 };
     38 
     39 // A normal mutex that requires to be initialized through normal C++ construction,
     40 // i.e. when it's a member of another class, or allocated on the heap.
     41 class SkMutex : public SkBaseMutex {
     42 public:
     43     SkMutex() {
     44         SkDEBUGCODE(int status = )pthread_mutex_init(&fMutex, NULL);
     45         SkDEBUGCODE(
     46             if (status != 0) {
     47                 print_pthread_error(status);
     48                 SkASSERT(0 == status);
     49             }
     50         )
     51     }
     52 
     53     ~SkMutex() {
     54         SkDEBUGCODE(int status = )pthread_mutex_destroy(&fMutex);
     55         SkDEBUGCODE(
     56             if (status != 0) {
     57                 print_pthread_error(status);
     58                 SkASSERT(0 == status);
     59             }
     60         )
     61     }
     62 
     63 private:
     64     SkMutex(const SkMutex&);
     65     SkMutex& operator=(const SkMutex&);
     66 
     67     static void print_pthread_error(int status) {
     68         switch (status) {
     69         case 0: // success
     70             break;
     71         case EINVAL:
     72             SkDebugf("pthread error [%d] EINVAL\n", status);
     73             break;
     74         case EBUSY:
     75             SkDebugf("pthread error [%d] EBUSY\n", status);
     76             break;
     77         default:
     78             SkDebugf("pthread error [%d] unknown\n", status);
     79             break;
     80         }
     81     }
     82 };
     83 
     84 #define SK_BASE_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, SkDEBUGCODE(0) }
     85 
     86 // Using POD-style initialization prevents the generation of a static initializer.
     87 #define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name = SK_BASE_MUTEX_INIT
     88 
     89 // Special case used when the static mutex must be available globally.
     90 #define SK_DECLARE_GLOBAL_MUTEX(name) SkBaseMutex name = SK_BASE_MUTEX_INIT
     91 
     92 #endif
     93