blob: 87606e2ca7fd8df944f7e600517d65f149b8d439 [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
digit@google.comf66436c2012-01-11 17:44:41 +000013#ifndef SK_BUILD_FOR_ANDROID
14
bsalomon@google.com09866002011-08-18 20:31:35 +000015/**
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
32int32_t sk_atomic_inc(int32_t* addr)
33{
34 return __sync_fetch_and_add(addr, 1);
35}
36
37int32_t sk_atomic_dec(int32_t* addr)
38{
39 return __sync_fetch_and_add(addr, -1);
40}
41
42#else
43
reed@android.com8a1c16f2008-12-17 15:59:43 +000044SkMutex gAtomicMutex;
45
46int32_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
55int32_t sk_atomic_dec(int32_t* addr)
56{
57 SkAutoMutexAcquire ac(gAtomicMutex);
digit@google.com1771cbf2012-01-26 21:26:40 +000058
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 int32_t value = *addr;
60 *addr = value - 1;
61 return value;
62}
63
bsalomon@google.com09866002011-08-18 20:31:35 +000064#endif
65
digit@google.comf66436c2012-01-11 17:44:41 +000066#endif // SK_BUILD_FOR_ANDROID
67
reed@android.com8a1c16f2008-12-17 15:59:43 +000068//////////////////////////////////////////////////////////////////////////////
69
reed@google.comdcbd6e32012-01-12 15:21:16 +000070static void print_pthread_error(int status) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 switch (status) {
72 case 0: // success
73 break;
74 case EINVAL:
reed@google.comdcbd6e32012-01-12 15:21:16 +000075 SkDebugf("pthread error [%d] EINVAL\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 break;
77 case EBUSY:
reed@google.comdcbd6e32012-01-12 15:21:16 +000078 SkDebugf("pthread error [%d] EBUSY\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 break;
80 default:
reed@google.comdcbd6e32012-01-12 15:21:16 +000081 SkDebugf("pthread error [%d] unknown\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 break;
83 }
84}
85
digit@google.com1771cbf2012-01-26 21:26:40 +000086#ifdef SK_USE_POSIX_THREADS
87
88SkMutex::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
98SkMutex::~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
reed@google.comdcbd6e32012-01-12 15:21:16 +0000110SkMutex::SkMutex() {
111 if (sizeof(pthread_mutex_t) > sizeof(fStorage)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000113 SkDEBUGFAIL("mutex storage is too small");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 }
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
reed@google.comdcbd6e32012-01-12 15:21:16 +0000128SkMutex::~SkMutex() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
reed@google.comdcbd6e32012-01-12 15:21:16 +0000130#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 // only report errors on non-global mutexes
reed@google.comdcbd6e32012-01-12 15:21:16 +0000132 if (!fIsGlobal) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 print_pthread_error(status);
134 SkASSERT(0 == status);
135 }
reed@google.comdcbd6e32012-01-12 15:21:16 +0000136#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137}
138
reed@google.comdcbd6e32012-01-12 15:21:16 +0000139void SkMutex::acquire() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
141 print_pthread_error(status);
142 SkASSERT(0 == status);
143}
144
reed@google.comdcbd6e32012-01-12 15:21:16 +0000145void SkMutex::release() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
147 print_pthread_error(status);
148 SkASSERT(0 == status);
149}
150
digit@google.com1771cbf2012-01-26 21:26:40 +0000151#endif // !SK_USE_POSIX_THREADS
reed@google.come6f7d682012-04-23 12:51:32 +0000152
153///////////////////////////////////////////////////////////////////////////////
154
155#include "SkTLS.h"
156
157struct SkTLSRec {
158 SkTLSRec* fNext;
159 void* fData;
160 SkTLS::CreateProc fCreateProc;
161 SkTLS::DeleteProc fDeleteProc;
162};
163
164static void sk_tls_destructor(void* ptr) {
165 SkTLSRec* rec = (SkTLSRec*)ptr;
166 do {
167 SkTLSRec* next = rec->fNext;
168 if (rec->fDeleteProc) {
169 rec->fDeleteProc(rec->fData);
170 }
171 delete rec;
172 rec = next;
173 } while (NULL != rec);
174}
175
176static pthread_key_t gSkTLSKey;
177static pthread_once_t gSkTLSKey_Once = PTHREAD_ONCE_INIT;
178
179static void sk_tls_make_key() {
180 (void)pthread_key_create(&gSkTLSKey, sk_tls_destructor);
181}
182
183void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) {
184 if (NULL == createProc) {
185 return NULL;
186 }
187
188 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
189 void* ptr = pthread_getspecific(gSkTLSKey);
190
191 if (ptr) {
192 const SkTLSRec* rec = (const SkTLSRec*)ptr;
193 do {
194 if (rec->fCreateProc == createProc) {
195 SkASSERT(rec->fDeleteProc == deleteProc);
196 return rec->fData;
197 }
198 } while ((rec = rec->fNext) != NULL);
199 // not found, so create a new one
200 }
201
202 // add a new head of our change
203 SkTLSRec* rec = new SkTLSRec;
204 rec->fNext = (SkTLSRec*)ptr;
205 (void)pthread_setspecific(gSkTLSKey, rec);
206
207 rec->fData = createProc();
208 rec->fCreateProc = createProc;
209 rec->fDeleteProc = deleteProc;
210 return rec->fData;
211}
212
213void* SkTLS::Find(CreateProc createProc) {
214 if (NULL == createProc) {
215 return NULL;
216 }
217
218 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
219 void* ptr = pthread_getspecific(gSkTLSKey);
220
221 if (ptr) {
222 const SkTLSRec* rec = (const SkTLSRec*)ptr;
223 do {
224 if (rec->fCreateProc == createProc) {
225 return rec->fData;
226 }
227 } while ((rec = rec->fNext) != NULL);
228 }
229 return NULL;
230}
231