blob: a78c7b2f14e3ec16702fefff705d17c4839ff85d [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
rmistry@google.comd6176b02012-08-23 18:14:13 +000017 SkMutex-based implementation. The SkMutex version suffers from static
bsalomon@google.com09866002011-08-18 20:31:35 +000018 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
scroggo@google.com50ccb0a2012-07-16 16:51:28 +000037int32_t sk_atomic_add(int32_t* addr, int32_t inc)
38{
39 return __sync_fetch_and_add(addr, inc);
40}
41
bsalomon@google.com09866002011-08-18 20:31:35 +000042int32_t sk_atomic_dec(int32_t* addr)
43{
44 return __sync_fetch_and_add(addr, -1);
45}
bungeman@google.coma02bc152012-05-16 18:21:56 +000046void sk_membar_aquire__after_atomic_dec() { }
47
48int32_t sk_atomic_conditional_inc(int32_t* addr)
49{
50 int32_t value = *addr;
51
52 while (true) {
53 if (value == 0) {
54 return 0;
55 }
56
57 int32_t before = __sync_val_compare_and_swap(addr, value, value + 1);
58
59 if (before == value) {
60 return value;
61 } else {
62 value = before;
63 }
64 }
65}
66void sk_membar_aquire__after_atomic_conditional_inc() { }
bsalomon@google.com09866002011-08-18 20:31:35 +000067
68#else
69
reed@android.com8a1c16f2008-12-17 15:59:43 +000070SkMutex gAtomicMutex;
71
72int32_t sk_atomic_inc(int32_t* addr)
73{
74 SkAutoMutexAcquire ac(gAtomicMutex);
75
76 int32_t value = *addr;
77 *addr = value + 1;
78 return value;
79}
80
scroggo@google.com50ccb0a2012-07-16 16:51:28 +000081int32_t sk_atomic_add(int32_t* addr, int32_t inc)
82{
83 SkAutoMutexAcquire ac(gAtomicMutex);
rmistry@google.comd6176b02012-08-23 18:14:13 +000084
scroggo@google.com50ccb0a2012-07-16 16:51:28 +000085 int32_t value = *addr;
86 *addr = value + inc;
87 return value;
88}
89
reed@android.com8a1c16f2008-12-17 15:59:43 +000090int32_t sk_atomic_dec(int32_t* addr)
91{
92 SkAutoMutexAcquire ac(gAtomicMutex);
digit@google.com1771cbf2012-01-26 21:26:40 +000093
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 int32_t value = *addr;
95 *addr = value - 1;
96 return value;
97}
bungeman@google.coma02bc152012-05-16 18:21:56 +000098void sk_membar_aquire__after_atomic_dec() { }
99
100int32_t sk_atomic_conditional_inc(int32_t* addr)
101{
102 SkAutoMutexAcquire ac(gAtomicMutex);
103
104 int32_t value = *addr;
105 if (value != 0) ++*addr;
106 return value;
107}
108void sk_membar_aquire__after_atomic_conditional_inc() { }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109
bsalomon@google.com09866002011-08-18 20:31:35 +0000110#endif
111
digit@google.comf66436c2012-01-11 17:44:41 +0000112#endif // SK_BUILD_FOR_ANDROID
113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114//////////////////////////////////////////////////////////////////////////////
115
reed@google.comdcbd6e32012-01-12 15:21:16 +0000116static void print_pthread_error(int status) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 switch (status) {
118 case 0: // success
119 break;
120 case EINVAL:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000121 SkDebugf("pthread error [%d] EINVAL\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 break;
123 case EBUSY:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000124 SkDebugf("pthread error [%d] EBUSY\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 break;
126 default:
reed@google.comdcbd6e32012-01-12 15:21:16 +0000127 SkDebugf("pthread error [%d] unknown\n", status);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 break;
129 }
130}
131
digit@google.com1771cbf2012-01-26 21:26:40 +0000132#ifdef SK_USE_POSIX_THREADS
133
134SkMutex::SkMutex() {
135 int status;
136
137 status = pthread_mutex_init(&fMutex, NULL);
138 if (status != 0) {
139 print_pthread_error(status);
140 SkASSERT(0 == status);
141 }
142}
143
144SkMutex::~SkMutex() {
145 int status = pthread_mutex_destroy(&fMutex);
146
147 // only report errors on non-global mutexes
148 if (status != 0) {
149 print_pthread_error(status);
150 SkASSERT(0 == status);
151 }
152}
153
154#else // !SK_USE_POSIX_THREADS
155
reed@google.comdcbd6e32012-01-12 15:21:16 +0000156SkMutex::SkMutex() {
157 if (sizeof(pthread_mutex_t) > sizeof(fStorage)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000159 SkDEBUGFAIL("mutex storage is too small");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 }
161
162 int status;
163 pthread_mutexattr_t attr;
164
165 status = pthread_mutexattr_init(&attr);
166 print_pthread_error(status);
167 SkASSERT(0 == status);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000168
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
170 print_pthread_error(status);
171 SkASSERT(0 == status);
172}
173
reed@google.comdcbd6e32012-01-12 15:21:16 +0000174SkMutex::~SkMutex() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
reed@google.comdcbd6e32012-01-12 15:21:16 +0000176#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 // only report errors on non-global mutexes
reed@google.comdcbd6e32012-01-12 15:21:16 +0000178 if (!fIsGlobal) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 print_pthread_error(status);
180 SkASSERT(0 == status);
181 }
reed@google.comdcbd6e32012-01-12 15:21:16 +0000182#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183}
184
reed@google.comdcbd6e32012-01-12 15:21:16 +0000185void SkMutex::acquire() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
187 print_pthread_error(status);
188 SkASSERT(0 == status);
189}
190
reed@google.comdcbd6e32012-01-12 15:21:16 +0000191void SkMutex::release() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
193 print_pthread_error(status);
194 SkASSERT(0 == status);
195}
196
digit@google.com1771cbf2012-01-26 21:26:40 +0000197#endif // !SK_USE_POSIX_THREADS