blob: bab26e992803b06b73b75c69ba1c5c794e47452c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkThread.h"
9
10#include <pthread.h>
11#include <errno.h>
12
bsalomon@google.com09866002011-08-18 20:31:35 +000013/**
14 We prefer the GCC intrinsic implementation of the atomic operations over the
15 SkMutex-based implementation. The SkMutex version suffers from static
16 destructor ordering problems.
17 Note clang also defines the GCC version macros and implements the intrinsics.
18 TODO: Verify that gcc-style __sync_* intrinsics work on ARM
19 According to this the intrinsics are supported on ARM in LLVM 2.7+
20 http://llvm.org/releases/2.7/docs/ReleaseNotes.html
21*/
22#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4
23 #if (defined(__x86_64) || defined(__i386__))
24 #define GCC_INTRINSIC
25 #endif
26#endif
27
28#if defined(GCC_INTRINSIC)
29
30int32_t sk_atomic_inc(int32_t* addr)
31{
32 return __sync_fetch_and_add(addr, 1);
33}
34
35int32_t sk_atomic_dec(int32_t* addr)
36{
37 return __sync_fetch_and_add(addr, -1);
38}
39
40#else
41
reed@android.com8a1c16f2008-12-17 15:59:43 +000042SkMutex gAtomicMutex;
43
44int32_t sk_atomic_inc(int32_t* addr)
45{
46 SkAutoMutexAcquire ac(gAtomicMutex);
47
48 int32_t value = *addr;
49 *addr = value + 1;
50 return value;
51}
52
53int32_t sk_atomic_dec(int32_t* addr)
54{
55 SkAutoMutexAcquire ac(gAtomicMutex);
56
57 int32_t value = *addr;
58 *addr = value - 1;
59 return value;
60}
61
bsalomon@google.com09866002011-08-18 20:31:35 +000062#endif
63
reed@android.com8a1c16f2008-12-17 15:59:43 +000064//////////////////////////////////////////////////////////////////////////////
65
66static void print_pthread_error(int status)
67{
68 switch (status) {
69 case 0: // success
70 break;
71 case EINVAL:
72 printf("pthread error [%d] EINVAL\n", status);
73 break;
74 case EBUSY:
75 printf("pthread error [%d] EBUSY\n", status);
76 break;
77 default:
78 printf("pthread error [%d] unknown\n", status);
79 break;
80 }
81}
82
83SkMutex::SkMutex(bool isGlobal) : fIsGlobal(isGlobal)
84{
85 if (sizeof(pthread_mutex_t) > sizeof(fStorage))
86 {
87 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
tomhudson@google.com0c00f212011-12-28 14:59:50 +000088 SkDEBUGFAIL("mutex storage is too small");
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 }
90
91 int status;
92 pthread_mutexattr_t attr;
93
94 status = pthread_mutexattr_init(&attr);
95 print_pthread_error(status);
96 SkASSERT(0 == status);
97
98 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
99 print_pthread_error(status);
100 SkASSERT(0 == status);
101}
102
103SkMutex::~SkMutex()
104{
105 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
106
107 // only report errors on non-global mutexes
108 if (!fIsGlobal)
109 {
110 print_pthread_error(status);
111 SkASSERT(0 == status);
112 }
113}
114
115void SkMutex::acquire()
116{
117 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
118 print_pthread_error(status);
119 SkASSERT(0 == status);
120}
121
122void SkMutex::release()
123{
124 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
125 print_pthread_error(status);
126 SkASSERT(0 == status);
127}
128