Mercurial > sdl-ios-xcode
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: */ |