blob: d0bb3acbade06511c1829f1d5adab043239155e2 [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
38int32_t sk_atomic_dec(int32_t* addr)
39{
40 return __sync_fetch_and_add(addr, -1);
41}
bungeman@google.coma02bc152012-05-16 18:21:56 +000042void sk_membar_aquire__after_atomic_dec() { }
43
44int32_t sk_atomic_conditional_inc(int32_t* addr)
45{
46 int32_t value = *addr;
47
48 while (true) {
49 if (value == 0) {
50 return 0;
51 }
52
53 int32_t before = __sync_val_compare_and_swap(addr, value, value + 1);
54
55 if (before == value) {
56 return value;
57 } else {
58 value = before;
59 }
60 }
61}
62void sk_membar_aquire__after_atomic_conditional_inc() { }
bsalomon@google.com09866002011-08-18 20:31:35 +000063
64#else
65
reed@android.com8a1c16f2008-12-17 15:59:43 +000066SkMutex gAtomicMutex;
67
68int32_t sk_atomic_inc(int32_t* addr)
69{
70 SkAutoMutexAcquire ac(gAtomicMutex);
71
72 int32_t value = *addr;
73 *addr = value + 1;
74 return value;
75}
76
77int32_t sk_atomic_dec(int32_t* addr)
78{
79 SkAutoMutexAcquire ac(gAtomicMutex);
digit@google.com1771cbf2012-01-26 21:26:40 +000080
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 int32_t value = *addr;
82 *addr = value - 1;
83 return value;
84}
bungeman@google.coma02bc152012-05-16 18:21:56 +000085void sk_membar_aquire__after_atomic_dec() { }
86
87int32_t sk_atomic_conditional_inc(int32_t* addr)
88{
89 SkAutoMutexAcquire ac(gAtomicMutex);
90
91 int32_t value = *addr;
92 if (value != 0) ++*addr;
93 return value;
94}
95void sk_membar_aquire__after_atomic_conditional_inc() { }
reed@android.com8a1c16f2008-12-17 15:59:43 +000096
bsalomon@google.com09866002011-08-18 20:31:35 +000097#endif
98
digit@google.comf66436c2012-01-11 17:44:41 +000099#endif // SK_BUILD_FOR_ANDROID
100
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101//////////////////////////////////////////////////////////////////////////////
102
reed@google.comdcbd6e32012-01-12 15:21:16 +0000103static void print_pthread_error(int status) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 switch (status) {
105 case 0: // success
106 break;
107 case EINVAL:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000108 SkDebugf("pthread error [%d] EINVAL\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 break;
110 case EBUSY:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000111 SkDebugf("pthread error [%d] EBUSY\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 break;
113 default:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000114 SkDebugf("pthread error [%d] unknown\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 break;
116 }
117}
118
digit@google.com1771cbf2012-01-26 21:26:40 +0000119#ifdef SK_USE_POSIX_THREADS
120
121SkMutex::SkMutex() {
122 int status;
123
124 status = pthread_mutex_init(&fMutex, NULL);
125 if (status != 0) {
126 print_pthread_error(status);
127 SkASSERT(0 == status);
128 }
129}
130
131SkMutex::~SkMutex() {
132 int status = pthread_mutex_destroy(&fMutex);
133
134 // only report errors on non-global mutexes
135 if (status != 0) {
136 print_pthread_error(status);
137 SkASSERT(0 == status);
138 }
139}
140
141#else // !SK_USE_POSIX_THREADS
142
reed@google.comdcbd6e32012-01-12 15:21:16 +0000143SkMutex::SkMutex() {
144 if (sizeof(pthread_mutex_t) > sizeof(fStorage)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000146 SkDEBUGFAIL("mutex storage is too small");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 }
148
149 int status;
150 pthread_mutexattr_t attr;
151
152 status = pthread_mutexattr_init(&attr);
153 print_pthread_error(status);
154 SkASSERT(0 == status);
155
156 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
157 print_pthread_error(status);
158 SkASSERT(0 == status);
159}
160
reed@google.comdcbd6e32012-01-12 15:21:16 +0000161SkMutex::~SkMutex() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
reed@google.comdcbd6e32012-01-12 15:21:16 +0000163#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164 // only report errors on non-global mutexes
reed@google.comdcbd6e32012-01-12 15:21:16 +0000165 if (!fIsGlobal) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 print_pthread_error(status);
167 SkASSERT(0 == status);
168 }
reed@google.comdcbd6e32012-01-12 15:21:16 +0000169#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170}
171
reed@google.comdcbd6e32012-01-12 15:21:16 +0000172void SkMutex::acquire() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
174 print_pthread_error(status);
175 SkASSERT(0 == status);
176}
177
reed@google.comdcbd6e32012-01-12 15:21:16 +0000178void SkMutex::release() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
180 print_pthread_error(status);
181 SkASSERT(0 == status);
182}
183
digit@google.com1771cbf2012-01-26 21:26:40 +0000184#endif // !SK_USE_POSIX_THREADS
reed@google.come6f7d682012-04-23 12:51:32 +0000185
186///////////////////////////////////////////////////////////////////////////////
187
reed@google.come6f7d682012-04-23 12:51:32 +0000188static pthread_key_t gSkTLSKey;
189static pthread_once_t gSkTLSKey_Once = PTHREAD_ONCE_INIT;
190
191static void sk_tls_make_key() {
reed@google.com48ca7e32012-05-07 20:23:27 +0000192 (void)pthread_key_create(&gSkTLSKey, SkTLS::Destructor);
reed@google.come6f7d682012-04-23 12:51:32 +0000193}
194
reed@google.com331e2dc2012-05-08 21:45:03 +0000195void* SkTLS::PlatformGetSpecific(bool forceCreateTheSlot) {
196 // should we use forceCreateTheSlot to potentially skip calling pthread_once
197 // and just return NULL if we've never been called with
198 // forceCreateTheSlot==true ?
199
reed@google.come6f7d682012-04-23 12:51:32 +0000200 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
reed@google.com48ca7e32012-05-07 20:23:27 +0000201 return pthread_getspecific(gSkTLSKey);
reed@google.come6f7d682012-04-23 12:51:32 +0000202}
203
reed@google.com48ca7e32012-05-07 20:23:27 +0000204void SkTLS::PlatformSetSpecific(void* ptr) {
205 (void)pthread_setspecific(gSkTLSKey, ptr);
reed@google.comae1b6b62012-04-23 15:49:45 +0000206}
207