blob: 2936eb0cfc508e500ca8b0f11ac057a95b89edc0 [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;
reed@google.comae1b6b62012-04-23 15:49:45 +0000162
163 ~SkTLSRec() {
164 if (fDeleteProc) {
165 fDeleteProc(fData);
166 }
167 // else we leak fData, or it will be managed by the caller
168 }
reed@google.come6f7d682012-04-23 12:51:32 +0000169};
170
171static void sk_tls_destructor(void* ptr) {
172 SkTLSRec* rec = (SkTLSRec*)ptr;
173 do {
174 SkTLSRec* next = rec->fNext;
reed@google.comae1b6b62012-04-23 15:49:45 +0000175 SkDELETE(rec);
reed@google.come6f7d682012-04-23 12:51:32 +0000176 rec = next;
177 } while (NULL != rec);
178}
179
180static pthread_key_t gSkTLSKey;
181static pthread_once_t gSkTLSKey_Once = PTHREAD_ONCE_INIT;
182
183static void sk_tls_make_key() {
184 (void)pthread_key_create(&gSkTLSKey, sk_tls_destructor);
185}
186
187void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) {
188 if (NULL == createProc) {
189 return NULL;
190 }
191
192 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
193 void* ptr = pthread_getspecific(gSkTLSKey);
194
195 if (ptr) {
196 const SkTLSRec* rec = (const SkTLSRec*)ptr;
197 do {
198 if (rec->fCreateProc == createProc) {
199 SkASSERT(rec->fDeleteProc == deleteProc);
200 return rec->fData;
201 }
202 } while ((rec = rec->fNext) != NULL);
203 // not found, so create a new one
204 }
205
206 // add a new head of our change
207 SkTLSRec* rec = new SkTLSRec;
208 rec->fNext = (SkTLSRec*)ptr;
209 (void)pthread_setspecific(gSkTLSKey, rec);
210
211 rec->fData = createProc();
212 rec->fCreateProc = createProc;
213 rec->fDeleteProc = deleteProc;
214 return rec->fData;
215}
216
217void* SkTLS::Find(CreateProc createProc) {
218 if (NULL == createProc) {
219 return NULL;
220 }
221
222 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
223 void* ptr = pthread_getspecific(gSkTLSKey);
224
225 if (ptr) {
226 const SkTLSRec* rec = (const SkTLSRec*)ptr;
227 do {
228 if (rec->fCreateProc == createProc) {
229 return rec->fData;
230 }
231 } while ((rec = rec->fNext) != NULL);
232 }
233 return NULL;
234}
235
reed@google.comae1b6b62012-04-23 15:49:45 +0000236void SkTLS::Delete(CreateProc createProc) {
237 if (NULL == createProc) {
238 return;
239 }
240
241 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
242 void* ptr = pthread_getspecific(gSkTLSKey);
243
244 SkTLSRec* curr = (const SkTLSRec*)ptr;
245 SkTLSRec* prev = NULL;
246 while (curr) {
247 SkTLSRec* next = curr->fNext;
248 if (rec->fCreateProc == createProc) {
249 if (prev) {
250 prev->fNext = next;
251 } else {
252 // we have a new head of our chain
253 (void)pthread_setspecific(gSkTLSKey, next);
254 }
255 SkDELETE(curr);
256 break;
257 }
258 prev = curr;
259 curr = next;
260 }
261}
262