blob: 51c0859031d65487c9e6e7cb566cb5d4bad82563 [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);
58
59 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
70static void print_pthread_error(int status)
71{
72 switch (status) {
73 case 0: // success
74 break;
75 case EINVAL:
76 printf("pthread error [%d] EINVAL\n", status);
77 break;
78 case EBUSY:
79 printf("pthread error [%d] EBUSY\n", status);
80 break;
81 default:
82 printf("pthread error [%d] unknown\n", status);
83 break;
84 }
85}
86
87SkMutex::SkMutex(bool isGlobal) : fIsGlobal(isGlobal)
88{
89 if (sizeof(pthread_mutex_t) > sizeof(fStorage))
90 {
91 SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
tomhudson@google.com0c00f212011-12-28 14:59:50 +000092 SkDEBUGFAIL("mutex storage is too small");
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 }
94
95 int status;
96 pthread_mutexattr_t attr;
97
98 status = pthread_mutexattr_init(&attr);
99 print_pthread_error(status);
100 SkASSERT(0 == status);
101
102 status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
103 print_pthread_error(status);
104 SkASSERT(0 == status);
105}
106
107SkMutex::~SkMutex()
108{
109 int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
110
111 // only report errors on non-global mutexes
112 if (!fIsGlobal)
113 {
114 print_pthread_error(status);
115 SkASSERT(0 == status);
116 }
117}
118
119void SkMutex::acquire()
120{
121 int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
122 print_pthread_error(status);
123 SkASSERT(0 == status);
124}
125
126void SkMutex::release()
127{
128 int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
129 print_pthread_error(status);
130 SkASSERT(0 == status);
131}
132