Home | History | Annotate | Download | only in ports
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkThread.h"
      9 
     10 #include <pthread.h>
     11 #include <errno.h>
     12 
     13 #ifndef SK_BUILD_FOR_ANDROID
     14 
     15 /**
     16  We prefer the GCC intrinsic implementation of the atomic operations over the
     17  SkMutex-based implementation. The SkMutex version suffers from static
     18  destructor ordering problems.
     19  Note clang also defines the GCC version macros and implements the intrinsics.
     20  TODO: Verify that gcc-style __sync_* intrinsics work on ARM
     21  According to this the intrinsics are supported on ARM in LLVM 2.7+
     22  http://llvm.org/releases/2.7/docs/ReleaseNotes.html
     23 */
     24 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4
     25     #if (defined(__x86_64) || defined(__i386__))
     26         #define GCC_INTRINSIC
     27     #endif
     28 #endif
     29 
     30 #if defined(GCC_INTRINSIC)
     31 
     32 int32_t sk_atomic_inc(int32_t* addr)
     33 {
     34     return __sync_fetch_and_add(addr, 1);
     35 }
     36 
     37 int32_t sk_atomic_dec(int32_t* addr)
     38 {
     39     return __sync_fetch_and_add(addr, -1);
     40 }
     41 
     42 #else
     43 
     44 SkMutex gAtomicMutex;
     45 
     46 int32_t sk_atomic_inc(int32_t* addr)
     47 {
     48     SkAutoMutexAcquire ac(gAtomicMutex);
     49 
     50     int32_t value = *addr;
     51     *addr = value + 1;
     52     return value;
     53 }
     54 
     55 int32_t sk_atomic_dec(int32_t* addr)
     56 {
     57     SkAutoMutexAcquire ac(gAtomicMutex);
     58 
     59     int32_t value = *addr;
     60     *addr = value - 1;
     61     return value;
     62 }
     63 
     64 #endif
     65 
     66 #endif // SK_BUILD_FOR_ANDROID
     67 
     68 //////////////////////////////////////////////////////////////////////////////
     69 
     70 static void print_pthread_error(int status) {
     71     switch (status) {
     72     case 0: // success
     73         break;
     74     case EINVAL:
     75         SkDebugf("pthread error [%d] EINVAL\n", status);
     76         break;
     77     case EBUSY:
     78         SkDebugf("pthread error [%d] EBUSY\n", status);
     79         break;
     80     default:
     81         SkDebugf("pthread error [%d] unknown\n", status);
     82         break;
     83     }
     84 }
     85 
     86 #ifdef SK_USE_POSIX_THREADS
     87 
     88 SkMutex::SkMutex() {
     89     int status;
     90 
     91     status = pthread_mutex_init(&fMutex, NULL);
     92     if (status != 0) {
     93         print_pthread_error(status);
     94         SkASSERT(0 == status);
     95     }
     96 }
     97 
     98 SkMutex::~SkMutex() {
     99     int status = pthread_mutex_destroy(&fMutex);
    100 
    101     // only report errors on non-global mutexes
    102     if (status != 0) {
    103         print_pthread_error(status);
    104         SkASSERT(0 == status);
    105     }
    106 }
    107 
    108 #else // !SK_USE_POSIX_THREADS
    109 
    110 SkMutex::SkMutex() {
    111     if (sizeof(pthread_mutex_t) > sizeof(fStorage)) {
    112         SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
    113         SkDEBUGFAIL("mutex storage is too small");
    114     }
    115 
    116     int status;
    117     pthread_mutexattr_t attr;
    118 
    119     status = pthread_mutexattr_init(&attr);
    120     print_pthread_error(status);
    121     SkASSERT(0 == status);
    122 
    123     status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
    124     print_pthread_error(status);
    125     SkASSERT(0 == status);
    126 }
    127 
    128 SkMutex::~SkMutex() {
    129     int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
    130 #if 0
    131     // only report errors on non-global mutexes
    132     if (!fIsGlobal) {
    133         print_pthread_error(status);
    134         SkASSERT(0 == status);
    135     }
    136 #endif
    137 }
    138 
    139 void SkMutex::acquire() {
    140     int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
    141     print_pthread_error(status);
    142     SkASSERT(0 == status);
    143 }
    144 
    145 void SkMutex::release() {
    146     int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
    147     print_pthread_error(status);
    148     SkASSERT(0 == status);
    149 }
    150 
    151 #endif // !SK_USE_POSIX_THREADS
    152