blob: ad243b9e3ad7130dec873b46ca217861d4e607dc [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"
reed@google.come22a4212012-05-07 20:28:00 +00009#include "SkTLS.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010
11#include <pthread.h>
12#include <errno.h>
13
digit@google.comf66436c2012-01-11 17:44:41 +000014#ifndef SK_BUILD_FOR_ANDROID
15
bsalomon@google.com09866002011-08-18 20:31:35 +000016/**
17 We prefer the GCC intrinsic implementation of the atomic operations over the
18 SkMutex-based implementation. The SkMutex version suffers from static
19 destructor ordering problems.
20 Note clang also defines the GCC version macros and implements the intrinsics.
21 TODO: Verify that gcc-style __sync_* intrinsics work on ARM
22 According to this the intrinsics are supported on ARM in LLVM 2.7+
23 http://llvm.org/releases/2.7/docs/ReleaseNotes.html
24*/
25#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4
26 #if (defined(__x86_64) || defined(__i386__))
27 #define GCC_INTRINSIC
28 #endif
29#endif
30
31#if defined(GCC_INTRINSIC)
32
33int32_t sk_atomic_inc(int32_t* addr)
34{
35 return __sync_fetch_and_add(addr, 1);
36}
37
scroggo@google.com50ccb0a2012-07-16 16:51:28 +000038int32_t sk_atomic_add(int32_t* addr, int32_t inc)
39{
40 return __sync_fetch_and_add(addr, inc);
41}
42
bsalomon@google.com09866002011-08-18 20:31:35 +000043int32_t sk_atomic_dec(int32_t* addr)
44{
45 return __sync_fetch_and_add(addr, -1);
46}
bungeman@google.coma02bc152012-05-16 18:21:56 +000047void sk_membar_aquire__after_atomic_dec() { }
48
49int32_t sk_atomic_conditional_inc(int32_t* addr)
50{
51 int32_t value = *addr;
52
53 while (true) {
54 if (value == 0) {
55 return 0;
56 }
57
58 int32_t before = __sync_val_compare_and_swap(addr, value, value + 1);
59
60 if (before == value) {
61 return value;
62 } else {
63 value = before;
64 }
65 }
66}
67void sk_membar_aquire__after_atomic_conditional_inc() { }
bsalomon@google.com09866002011-08-18 20:31:35 +000068
69#else
70
reed@android.com8a1c16f2008-12-17 15:59:43 +000071SkMutex gAtomicMutex;
72
73int32_t sk_atomic_inc(int32_t* addr)
74{
75 SkAutoMutexAcquire ac(gAtomicMutex);
76
77 int32_t value = *addr;
78 *addr = value + 1;
79 return value;
80}
81
scroggo@google.com50ccb0a2012-07-16 16:51:28 +000082int32_t sk_atomic_add(int32_t* addr, int32_t inc)
83{
84 SkAutoMutexAcquire ac(gAtomicMutex);
85
86 int32_t value = *addr;
87 *addr = value + inc;
88 return value;
89}
90
reed@android.com8a1c16f2008-12-17 15:59:43 +000091int32_t sk_atomic_dec(int32_t* addr)
92{
93 SkAutoMutexAcquire ac(gAtomicMutex);
digit@google.com1771cbf2012-01-26 21:26:40 +000094
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 int32_t value = *addr;
96 *addr = value - 1;
97 return value;
98}
bungeman@google.coma02bc152012-05-16 18:21:56 +000099void sk_membar_aquire__after_atomic_dec() { }
100
101int32_t sk_atomic_conditional_inc(int32_t* addr)
102{
103 SkAutoMutexAcquire ac(gAtomicMutex);
104
105 int32_t value = *addr;
106 if (value != 0) ++*addr;
107 return value;
108}
109void sk_membar_aquire__after_atomic_conditional_inc() { }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110
bsalomon@google.com09866002011-08-18 20:31:35 +0000111#endif
112
digit@google.comf66436c2012-01-11 17:44:41 +0000113#endif // SK_BUILD_FOR_ANDROID
114
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115//////////////////////////////////////////////////////////////////////////////
116
reed@google.comdcbd6e32012-01-12 15:21:16 +0000117static void print_pthread_error(int status) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 switch (status) {
119 case 0: // success
120 break;
121 case EINVAL:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000122 SkDebugf("pthread error [%d] EINVAL\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 break;
124 case EBUSY:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000125 SkDebugf("pthread error [%d] EBUSY\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 break;
127 default:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000128 SkDebugf("pthread error [%d] unknown\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 break;
130 }
131}
132
digit@google.com1771cbf2012-01-26 21:26:40 +0000133#ifdef SK_USE_POSIX_THREADS
134
135SkMutex::SkMutex() {
136 int status;
137
138 status = pthread_mutex_init(&fMutex, NULL);
139 if (status != 0) {
140 print_pthread_error(status);
141 SkASSERT(0 == status);
142 }
143}
144
145SkMutex::~SkMutex() {
146 int status = pthread_mutex_destroy(&fMutex);
147
148 // only report errors on non-global mutexes
149 if (status != 0) {
150 print_pthread_error(status);
151 SkASSERT(0 == status);
152 }
153}
154
155#else // !SK_USE_POSIX_THREADS
156
reed@google.comdcbd6e32012-01-12 15:21:16 +0000157SkMutex::SkMutex() {
158 if (sizeof(pthread_mutex_t) > sizeof(fStorage)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000160 SkDEBUGFAIL("mutex storage is too small");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 }
162
163 int status;
164 pthread_mutexattr_t attr;
165
166 status = pthread_mutexattr_init(&attr);
167 print_pthread_error(status);
168 SkASSERT(0 == status);
169
170 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
171 print_pthread_error(status);
172 SkASSERT(0 == status);
173}
174
reed@google.comdcbd6e32012-01-12 15:21:16 +0000175SkMutex::~SkMutex() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
reed@google.comdcbd6e32012-01-12 15:21:16 +0000177#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 // only report errors on non-global mutexes
reed@google.comdcbd6e32012-01-12 15:21:16 +0000179 if (!fIsGlobal) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 print_pthread_error(status);
181 SkASSERT(0 == status);
182 }
reed@google.comdcbd6e32012-01-12 15:21:16 +0000183#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184}
185
reed@google.comdcbd6e32012-01-12 15:21:16 +0000186void SkMutex::acquire() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
188 print_pthread_error(status);
189 SkASSERT(0 == status);
190}
191
reed@google.comdcbd6e32012-01-12 15:21:16 +0000192void SkMutex::release() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
194 print_pthread_error(status);
195 SkASSERT(0 == status);
196}
197
digit@google.com1771cbf2012-01-26 21:26:40 +0000198#endif // !SK_USE_POSIX_THREADS
reed@google.come6f7d682012-04-23 12:51:32 +0000199
200///////////////////////////////////////////////////////////////////////////////
201
reed@google.come6f7d682012-04-23 12:51:32 +0000202static pthread_key_t gSkTLSKey;
203static pthread_once_t gSkTLSKey_Once = PTHREAD_ONCE_INIT;
204
205static void sk_tls_make_key() {
reed@google.com48ca7e32012-05-07 20:23:27 +0000206 (void)pthread_key_create(&gSkTLSKey, SkTLS::Destructor);
reed@google.come6f7d682012-04-23 12:51:32 +0000207}
208
reed@google.com331e2dc2012-05-08 21:45:03 +0000209void* SkTLS::PlatformGetSpecific(bool forceCreateTheSlot) {
210 // should we use forceCreateTheSlot to potentially skip calling pthread_once
211 // and just return NULL if we've never been called with
212 // forceCreateTheSlot==true ?
213
reed@google.come6f7d682012-04-23 12:51:32 +0000214 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
reed@google.com48ca7e32012-05-07 20:23:27 +0000215 return pthread_getspecific(gSkTLSKey);
reed@google.come6f7d682012-04-23 12:51:32 +0000216}
217
reed@google.com48ca7e32012-05-07 20:23:27 +0000218void SkTLS::PlatformSetSpecific(void* ptr) {
219 (void)pthread_setspecific(gSkTLSKey, ptr);
reed@google.comae1b6b62012-04-23 15:49:45 +0000220}
221