blob: 6a4fade1aaa57f080f5f7bdca8830fb914c20923 [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}
42
43#else
44
reed@android.com8a1c16f2008-12-17 15:59:43 +000045SkMutex gAtomicMutex;
46
47int32_t sk_atomic_inc(int32_t* addr)
48{
49 SkAutoMutexAcquire ac(gAtomicMutex);
50
51 int32_t value = *addr;
52 *addr = value + 1;
53 return value;
54}
55
56int32_t sk_atomic_dec(int32_t* addr)
57{
58 SkAutoMutexAcquire ac(gAtomicMutex);
digit@google.com1771cbf2012-01-26 21:26:40 +000059
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 int32_t value = *addr;
61 *addr = value - 1;
62 return value;
63}
64
bsalomon@google.com09866002011-08-18 20:31:35 +000065#endif
66
digit@google.comf66436c2012-01-11 17:44:41 +000067#endif // SK_BUILD_FOR_ANDROID
68
reed@android.com8a1c16f2008-12-17 15:59:43 +000069//////////////////////////////////////////////////////////////////////////////
70
reed@google.comdcbd6e32012-01-12 15:21:16 +000071static void print_pthread_error(int status) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 switch (status) {
73 case 0: // success
74 break;
75 case EINVAL:
reed@google.comdcbd6e32012-01-12 15:21:16 +000076 SkDebugf("pthread error [%d] EINVAL\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 break;
78 case EBUSY:
reed@google.comdcbd6e32012-01-12 15:21:16 +000079 SkDebugf("pthread error [%d] EBUSY\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 break;
81 default:
reed@google.comdcbd6e32012-01-12 15:21:16 +000082 SkDebugf("pthread error [%d] unknown\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 break;
84 }
85}
86
digit@google.com1771cbf2012-01-26 21:26:40 +000087#ifdef SK_USE_POSIX_THREADS
88
89SkMutex::SkMutex() {
90 int status;
91
92 status = pthread_mutex_init(&fMutex, NULL);
93 if (status != 0) {
94 print_pthread_error(status);
95 SkASSERT(0 == status);
96 }
97}
98
99SkMutex::~SkMutex() {
100 int status = pthread_mutex_destroy(&fMutex);
101
102 // only report errors on non-global mutexes
103 if (status != 0) {
104 print_pthread_error(status);
105 SkASSERT(0 == status);
106 }
107}
108
109#else // !SK_USE_POSIX_THREADS
110
reed@google.comdcbd6e32012-01-12 15:21:16 +0000111SkMutex::SkMutex() {
112 if (sizeof(pthread_mutex_t) > sizeof(fStorage)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000114 SkDEBUGFAIL("mutex storage is too small");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 }
116
117 int status;
118 pthread_mutexattr_t attr;
119
120 status = pthread_mutexattr_init(&attr);
121 print_pthread_error(status);
122 SkASSERT(0 == status);
123
124 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
125 print_pthread_error(status);
126 SkASSERT(0 == status);
127}
128
reed@google.comdcbd6e32012-01-12 15:21:16 +0000129SkMutex::~SkMutex() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
reed@google.comdcbd6e32012-01-12 15:21:16 +0000131#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 // only report errors on non-global mutexes
reed@google.comdcbd6e32012-01-12 15:21:16 +0000133 if (!fIsGlobal) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134 print_pthread_error(status);
135 SkASSERT(0 == status);
136 }
reed@google.comdcbd6e32012-01-12 15:21:16 +0000137#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138}
139
reed@google.comdcbd6e32012-01-12 15:21:16 +0000140void SkMutex::acquire() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
142 print_pthread_error(status);
143 SkASSERT(0 == status);
144}
145
reed@google.comdcbd6e32012-01-12 15:21:16 +0000146void SkMutex::release() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
148 print_pthread_error(status);
149 SkASSERT(0 == status);
150}
151
digit@google.com1771cbf2012-01-26 21:26:40 +0000152#endif // !SK_USE_POSIX_THREADS
reed@google.come6f7d682012-04-23 12:51:32 +0000153
154///////////////////////////////////////////////////////////////////////////////
155
reed@google.come6f7d682012-04-23 12:51:32 +0000156static pthread_key_t gSkTLSKey;
157static pthread_once_t gSkTLSKey_Once = PTHREAD_ONCE_INIT;
158
159static void sk_tls_make_key() {
reed@google.com48ca7e32012-05-07 20:23:27 +0000160 (void)pthread_key_create(&gSkTLSKey, SkTLS::Destructor);
reed@google.come6f7d682012-04-23 12:51:32 +0000161}
162
reed@google.com331e2dc2012-05-08 21:45:03 +0000163void* SkTLS::PlatformGetSpecific(bool forceCreateTheSlot) {
164 // should we use forceCreateTheSlot to potentially skip calling pthread_once
165 // and just return NULL if we've never been called with
166 // forceCreateTheSlot==true ?
167
reed@google.come6f7d682012-04-23 12:51:32 +0000168 (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key);
reed@google.com48ca7e32012-05-07 20:23:27 +0000169 return pthread_getspecific(gSkTLSKey);
reed@google.come6f7d682012-04-23 12:51:32 +0000170}
171
reed@google.com48ca7e32012-05-07 20:23:27 +0000172void SkTLS::PlatformSetSpecific(void* ptr) {
173 (void)pthread_setspecific(gSkTLSKey, ptr);
reed@google.comae1b6b62012-04-23 15:49:45 +0000174}
175