comparison src/atomic/SDL_atomic.c @ 5004:0c72ae7b7cb2

Added native atomic operations for Windows, Mac OS X, and gcc compiler intrinsics. Changed the CAS return value to bool, so it's efficient with OSAtomicCompareAndSwap32Barrier() Added an atomic test adapted from code by Michael Davidsaver
author Sam Lantinga <slouken@libsdl.org>
date Sun, 16 Jan 2011 15:16:39 -0800
parents 3a95a2b93eb3
children dceec93471e7
comparison
equal deleted inserted replaced
5003:3a95a2b93eb3 5004:0c72ae7b7cb2
21 */ 21 */
22 #include "SDL_stdinc.h" 22 #include "SDL_stdinc.h"
23 23
24 #include "SDL_atomic.h" 24 #include "SDL_atomic.h"
25 25
26 /* Note that we undefine the atomic operations here, in case they are
27 defined as compiler intrinsics while building SDL but the library user
28 doesn't have that compiler. That way we always have a working set of
29 atomic operations built into the library.
30 */
31
26 /* 32 /*
27 If any of the operations are not provided then we must emulate some 33 If any of the operations are not provided then we must emulate some
28 of them. That means we need a nice implementation of spin locks 34 of them. That means we need a nice implementation of spin locks
29 that avoids the "one big lock" problem. We use a vector of spin 35 that avoids the "one big lock" problem. We use a vector of spin
30 locks and pick which one to use based on the address of the operand 36 locks and pick which one to use based on the address of the operand
49 static SDL_SpinLock locks[32]; 55 static SDL_SpinLock locks[32];
50 56
51 static __inline__ void 57 static __inline__ void
52 enterLock(void *a) 58 enterLock(void *a)
53 { 59 {
54 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f); 60 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
55 61
56 SDL_AtomicLock(&locks[index]); 62 SDL_AtomicLock(&locks[index]);
57 } 63 }
58 64
59 static __inline__ void 65 static __inline__ void
60 leaveLock(void *a) 66 leaveLock(void *a)
61 { 67 {
62 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f); 68 uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
63 69
64 SDL_AtomicUnlock(&locks[index]); 70 SDL_AtomicUnlock(&locks[index]);
65 } 71 }
66 72
67 #ifndef SDL_AtomicSet 73 #undef SDL_AtomicSet
68 int 74 int
69 SDL_AtomicSet(SDL_atomic_t *a, int value) 75 SDL_AtomicSet(SDL_atomic_t *a, int value)
70 { 76 {
71 int oldvalue; 77 int oldvalue;
72 78
75 a->value = value; 81 a->value = value;
76 leaveLock(a); 82 leaveLock(a);
77 83
78 return oldvalue; 84 return oldvalue;
79 } 85 }
80 #endif
81 86
82 #ifndef SDL_AtomicGet 87 #undef SDL_AtomicGet
83 int 88 int
84 SDL_AtomicGet(SDL_atomic_t *a) 89 SDL_AtomicGet(SDL_atomic_t *a)
85 { 90 {
86 /* Assuming integral reads on this platform, we're safe here since the 91 /* Assuming integral reads on this platform, we're safe here since the
87 functions that set the variable have the necessary memory barriers. 92 functions that set the variable have the necessary memory barriers.
88 */ 93 */
89 return a->value; 94 return a->value;
90 } 95 }
91 #endif
92 96
93 #ifndef SDL_AtomicAdd 97 #undef SDL_AtomicAdd
94 int 98 int
95 SDL_AtomicAdd(SDL_atomic_t *a, int value) 99 SDL_AtomicAdd(SDL_atomic_t *a, int value)
96 { 100 {
97 int oldvalue; 101 int oldvalue;
98 102
101 a->value += value; 105 a->value += value;
102 leaveLock(a); 106 leaveLock(a);
103 107
104 return oldvalue; 108 return oldvalue;
105 } 109 }
106 #endif
107 110
108 #ifndef SDL_AtomicIncRef 111 #undef SDL_AtomicIncRef
109 void 112 void
110 SDL_AtomicIncRef(SDL_atomic_t *a) 113 SDL_AtomicIncRef(SDL_atomic_t *a)
111 { 114 {
112 SDL_AtomicAdd(a, 1); 115 SDL_AtomicAdd(a, 1);
113 } 116 }
114 #endif
115 117
116 #ifndef SDL_AtomicDecRef 118 #undef SDL_AtomicDecRef
117 SDL_bool 119 SDL_bool
118 SDL_AtomicDecRef(SDL_atomic_t *a) 120 SDL_AtomicDecRef(SDL_atomic_t *a)
119 { 121 {
120 return SDL_AtomicAdd(a, -1) == 1; 122 return SDL_AtomicAdd(a, -1) == 1;
121 } 123 }
122 #endif
123 124
124 #ifndef SDL_AtomicCAS 125 #undef SDL_AtomicCAS
125 int 126 SDL_bool
126 SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval) 127 SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval)
127 { 128 {
128 int prevval; 129 SDL_bool retval = SDL_FALSE;
129 130
130 enterLock(a); 131 enterLock(a);
131 prevval = a->value; 132 if (a->value == oldval) {
132 if (prevval == oldval) {
133 a->value = newval; 133 a->value = newval;
134 retval = SDL_TRUE;
134 } 135 }
135 leaveLock(a); 136 leaveLock(a);
136 137
137 return prevval; 138 return retval;
138 } 139 }
139 #endif
140 140
141 #ifndef SDL_AtomicSetPtr 141 #undef SDL_AtomicSetPtr
142 void 142 void
143 SDL_AtomicSetPtr(void** a, void* value) 143 SDL_AtomicSetPtr(void** a, void* value)
144 { 144 {
145 void *prevval; 145 void *prevval;
146 do { 146 do {
147 prevval = *a; 147 prevval = *a;
148 } while (SDL_AtomicCASPtr(a, prevval, value) != prevval); 148 } while (!SDL_AtomicCASPtr(a, prevval, value));
149 } 149 }
150 #endif
151 150
152 #ifndef SDL_AtomicGetPtr 151 #undef SDL_AtomicGetPtr
153 void* 152 void*
154 SDL_AtomicGetPtr(void** a) 153 SDL_AtomicGetPtr(void** a)
155 { 154 {
156 /* Assuming integral reads on this platform, we're safe here since the 155 /* Assuming integral reads on this platform, we're safe here since the
157 functions that set the pointer have the necessary memory barriers. 156 functions that set the pointer have the necessary memory barriers.
158 */ 157 */
159 return *a; 158 return *a;
160 } 159 }
161 #endif
162 160
163 #ifndef SDL_AtomicCASPtr 161 #undef SDL_AtomicCASPtr
164 void* SDL_AtomicCASPtr(void **a, void *oldval, void *newval) 162 SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
165 { 163 {
166 void *prevval; 164 SDL_bool retval = SDL_FALSE;
167 165
168 enterLock(a); 166 enterLock(a);
169 prevval = *a;
170 if (*a == oldval) { 167 if (*a == oldval) {
171 *a = newval; 168 *a = newval;
169 retval = SDL_TRUE;
172 } 170 }
173 leaveLock(a); 171 leaveLock(a);
174 172
175 return prevval; 173 return retval;
176 } 174 }
177 #endif
178 175
179 /* vi: set ts=4 sw=4 expandtab: */ 176 /* vi: set ts=4 sw=4 expandtab: */