Mercurial > hg > nginx
comparison src/os/unix/ngx_atomic.h @ 561:e48ebafc6939 release-0.3.2
nginx-0.3.2-RELEASE import
*) Feature: the Sun Studio 10 C compiler support.
*) Feature: the "proxy_upstream_max_fails",
"proxy_upstream_fail_timeout", "fastcgi_upstream_max_fails", and
"fastcgi_upstream_fail_timeout" directives.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Wed, 12 Oct 2005 13:50:36 +0000 |
parents | 483cca230603 |
children | 9c2f3ed7a247 |
comparison
equal
deleted
inserted
replaced
560:8886091eddd2 | 561:e48ebafc6939 |
---|---|
12 #include <ngx_core.h> | 12 #include <ngx_core.h> |
13 | 13 |
14 | 14 |
15 #if ( __i386__ || __i386 ) | 15 #if ( __i386__ || __i386 ) |
16 | 16 |
17 typedef int32_t ngx_atomic_int_t; | |
18 typedef uint32_t ngx_atomic_uint_t; | |
19 typedef volatile ngx_atomic_uint_t ngx_atomic_t; | |
20 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 | |
21 | |
22 | |
23 #if ( __SUNPRO_C ) | |
24 | |
17 #define NGX_HAVE_ATOMIC_OPS 1 | 25 #define NGX_HAVE_ATOMIC_OPS 1 |
18 | 26 |
19 typedef int32_t ngx_atomic_int_t; | 27 ngx_atomic_uint_t |
20 typedef uint32_t ngx_atomic_uint_t; | 28 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, |
21 typedef volatile ngx_atomic_uint_t ngx_atomic_t; | 29 ngx_atomic_uint_t set); |
22 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 | 30 |
31 ngx_atomic_int_t | |
32 ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); | |
33 | |
34 /* the code in src/os/unix/ngx_sunpro_x86.il */ | |
23 | 35 |
24 | 36 |
25 #if (NGX_SMP) | 37 #else /* ( __GNUC__ || __INTEL_COMPILER ) */ |
26 #define NGX_SMP_LOCK "lock;" | 38 |
27 #else | 39 #define NGX_HAVE_ATOMIC_OPS 1 |
28 #define NGX_SMP_LOCK | 40 |
41 #include "ngx_gcc_atomic_x86.h" | |
42 | |
29 #endif | 43 #endif |
30 | |
31 /* | |
32 * the "=q" is any of the %eax, %ebx, %ecx, or %edx registers. | |
33 * the '"0" (1)' parameter preloads 1 into %0. | |
34 * the "cc" means that flags were changed. | |
35 * | |
36 * "xadd r, [m]": | |
37 * | |
38 * temp = [m]; | |
39 * [m] += r; | |
40 * r = temp; | |
41 */ | |
42 | |
43 static ngx_inline ngx_atomic_uint_t | |
44 ngx_atomic_inc(ngx_atomic_t *value) | |
45 { | |
46 ngx_atomic_uint_t old; | |
47 | |
48 __asm__ volatile ( | |
49 | |
50 NGX_SMP_LOCK | |
51 " xaddl %0, %2; " | |
52 " incl %0; " | |
53 | |
54 : "=q" (old) : "0" (1), "m" (*value) : "cc", "memory"); | |
55 | |
56 return old; | |
57 } | |
58 | |
59 | |
60 static ngx_inline ngx_atomic_uint_t | |
61 ngx_atomic_dec(ngx_atomic_t *value) | |
62 { | |
63 ngx_atomic_uint_t old; | |
64 | |
65 __asm__ volatile ( | |
66 | |
67 NGX_SMP_LOCK | |
68 " xaddl %0, %2; " | |
69 " decl %0; " | |
70 | |
71 : "=q" (old) : "0" (-1), "m" (*value) : "cc", "memory"); | |
72 | |
73 return old; | |
74 } | |
75 | |
76 | |
77 /* | |
78 * the "q" is any of the %eax, %ebx, %ecx, or %edx registers. | |
79 * the "=a" and "a" are the %eax register. Although we can return result | |
80 * in any register, we use %eax because it is used in cmpxchg anyway. | |
81 * | |
82 * "cmpxchg r, [m]": | |
83 * | |
84 * if (eax == [m]) { | |
85 * zf = 1; | |
86 * [m] = r; | |
87 * } else { | |
88 * zf = 0; | |
89 * eax = [m]; | |
90 * } | |
91 */ | |
92 | |
93 static ngx_inline ngx_atomic_uint_t | |
94 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, | |
95 ngx_atomic_uint_t set) | |
96 { | |
97 ngx_atomic_uint_t res; | |
98 | |
99 __asm__ volatile ( | |
100 | |
101 NGX_SMP_LOCK | |
102 " cmpxchgl %3, %1; " | |
103 " setz %b0; " | |
104 " movzbl %b0, %0; " | |
105 | |
106 : "=a" (res) : "m" (*lock), "a" (old), "q" (set) : "cc", "memory"); | |
107 | |
108 return res; | |
109 } | |
110 | 44 |
111 | 45 |
112 #elif ( __amd64__ || __amd64 ) | 46 #elif ( __amd64__ || __amd64 ) |
113 | 47 |
48 typedef int64_t ngx_atomic_int_t; | |
49 typedef uint64_t ngx_atomic_uint_t; | |
50 typedef volatile ngx_atomic_uint_t ngx_atomic_t; | |
51 #define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 | |
52 | |
53 | |
54 #if ( __SUNPRO_C ) | |
55 | |
114 #define NGX_HAVE_ATOMIC_OPS 1 | 56 #define NGX_HAVE_ATOMIC_OPS 1 |
115 | 57 |
116 typedef int64_t ngx_atomic_int_t; | 58 ngx_atomic_uint_t |
117 typedef uint64_t ngx_atomic_uint_t; | 59 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, |
118 typedef volatile ngx_atomic_uint_t ngx_atomic_t; | 60 ngx_atomic_uint_t set); |
119 #define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 | 61 |
62 ngx_atomic_int_t | |
63 ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); | |
64 | |
65 /* the code in src/os/unix/ngx_sunpro_amd64.il */ | |
120 | 66 |
121 | 67 |
122 #if (NGX_SMP) | 68 #else /* ( __GNUC__ || __INTEL_COMPILER ) */ |
123 #define NGX_SMP_LOCK "lock;" | 69 |
124 #else | 70 #define NGX_HAVE_ATOMIC_OPS 1 |
125 #define NGX_SMP_LOCK | 71 |
72 #include "ngx_gcc_atomic_amd64.h" | |
73 | |
126 #endif | 74 #endif |
127 | |
128 | |
129 static ngx_inline ngx_atomic_uint_t | |
130 ngx_atomic_inc(ngx_atomic_t *value) | |
131 { | |
132 ngx_atomic_uint_t old; | |
133 | |
134 __asm__ volatile ( | |
135 | |
136 NGX_SMP_LOCK | |
137 " xaddq %0, %2; " | |
138 " incq %0; " | |
139 | |
140 : "=r" (old) : "0" (1), "m" (*value) : "cc", "memory"); | |
141 | |
142 return old; | |
143 } | |
144 | |
145 | |
146 /* the '"0" (-1LL)' parameter preloads -1 into the 64-bit %0 register */ | |
147 | |
148 static ngx_inline ngx_atomic_uint_t | |
149 ngx_atomic_dec(ngx_atomic_t *value) | |
150 { | |
151 ngx_atomic_uint_t old; | |
152 | |
153 __asm__ volatile ( | |
154 | |
155 NGX_SMP_LOCK | |
156 " xaddq %0, %2; " | |
157 " decq %0; " | |
158 | |
159 : "=r" (old) : "0" (-1LL), "m" (*value) : "cc", "memory"); | |
160 | |
161 return old; | |
162 } | |
163 | |
164 | |
165 /* the "=a" and "a" are the %rax register. */ | |
166 | |
167 static ngx_inline ngx_atomic_uint_t | |
168 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, | |
169 ngx_atomic_uint_t set) | |
170 { | |
171 ngx_atomic_uint_t res; | |
172 | |
173 __asm__ volatile ( | |
174 | |
175 NGX_SMP_LOCK | |
176 " cmpxchgq %3, %1; " | |
177 " setz %b0; " | |
178 " movzbq %b0, %0; " | |
179 | |
180 : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); | |
181 | |
182 return res; | |
183 } | |
184 | 75 |
185 | 76 |
186 #elif ( __sparc__ || __sparcv9 ) | 77 #elif ( __sparc__ || __sparcv9 ) |
187 | 78 |
188 #define NGX_HAVE_ATOMIC_OPS 1 | 79 #if (NGX_PTR_SIZE == 8) |
189 | 80 |
190 #if (NGX_PTR_SIZE == 8) | 81 typedef int64_t ngx_atomic_int_t; |
191 typedef int64_t ngx_atomic_int_t; | 82 typedef uint64_t ngx_atomic_uint_t; |
192 typedef uint64_t ngx_atomic_uint_t; | 83 #define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 |
193 #define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 | 84 |
194 #define NGX_CASXA "casxa" | |
195 #else | 85 #else |
196 typedef int32_t ngx_atomic_int_t; | 86 |
197 typedef uint32_t ngx_atomic_uint_t; | 87 typedef int32_t ngx_atomic_int_t; |
198 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 | 88 typedef uint32_t ngx_atomic_uint_t; |
199 #define NGX_CASXA "casa" | 89 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 |
90 | |
200 #endif | 91 #endif |
201 | 92 |
202 typedef volatile ngx_atomic_uint_t ngx_atomic_t; | 93 typedef volatile ngx_atomic_uint_t ngx_atomic_t; |
203 | 94 |
204 | 95 |
205 /* | 96 #if ( __SUNPRO_C ) |
206 * the "+r" means the general register used for both input and output. | |
207 * | |
208 * "casa [r1] 0x80, r2, r0" and | |
209 * "casxa [r1] 0x80, r2, r0" do the following: | |
210 * | |
211 * if ([r1] == r2) { | |
212 * swap(r0, [r1]); | |
213 * } else { | |
214 * r0 = [r1]; | |
215 * } | |
216 * | |
217 * so "r0 == r2" means that the operation was successfull. | |
218 */ | |
219 | 97 |
220 static ngx_inline ngx_atomic_uint_t | 98 #define NGX_HAVE_ATOMIC_OPS 1 |
221 ngx_atomic_inc(ngx_atomic_t *value) | |
222 { | |
223 ngx_atomic_uint_t old, new, res; | |
224 | 99 |
225 old = *value; | 100 #include "ngx_sunpro_atomic_sparc64.h" |
226 | |
227 for ( ;; ) { | |
228 | |
229 new = old + 1; | |
230 res = new; | |
231 | |
232 __asm__ volatile ( | |
233 | |
234 NGX_CASXA " [%1] 0x80, %2, %0" | |
235 | |
236 : "+r" (res) : "r" (value), "r" (old) : "memory"); | |
237 | |
238 if (res == old) { | |
239 return new; | |
240 } | |
241 | |
242 old = res; | |
243 } | |
244 } | |
245 | 101 |
246 | 102 |
247 static ngx_inline ngx_atomic_uint_t | 103 #else /* ( __GNUC__ || __INTEL_COMPILER ) */ |
248 ngx_atomic_dec(ngx_atomic_t *value) | |
249 { | |
250 ngx_atomic_uint_t old, new, res; | |
251 | 104 |
252 old = *value; | 105 #define NGX_HAVE_ATOMIC_OPS 1 |
253 | 106 |
254 for ( ;; ) { | 107 #include "ngx_gcc_atomic_sparc64.h" |
255 | 108 |
256 new = old - 1; | 109 #endif |
257 res = new; | |
258 | |
259 __asm__ volatile ( | |
260 | |
261 NGX_CASXA " [%1] 0x80, %2, %0" | |
262 | |
263 : "+r" (res) : "r" (value), "r" (old) : "memory"); | |
264 | |
265 if (res == old) { | |
266 return new; | |
267 } | |
268 | |
269 old = res; | |
270 } | |
271 } | |
272 | |
273 | |
274 static ngx_inline ngx_atomic_uint_t | |
275 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, | |
276 ngx_atomic_uint_t set) | |
277 { | |
278 __asm__ volatile ( | |
279 | |
280 NGX_CASXA " [%1] 0x80, %2, %0" | |
281 | |
282 : "+r" (set) : "r" (lock), "r" (old) : "memory"); | |
283 | |
284 return (set == old); | |
285 } | |
286 | 110 |
287 | 111 |
288 #elif ( __ppc__ || __powerpc__ ) | 112 #elif ( __ppc__ || __powerpc__ ) |
289 | 113 |
290 #define NGX_HAVE_ATOMIC_OPS 1 | 114 #define NGX_HAVE_ATOMIC_OPS 1 |
291 | 115 |
292 #if (NGX_PTR_SIZE == 8) | 116 #if (NGX_PTR_SIZE == 8) |
293 typedef int64_t ngx_atomic_int_t; | 117 |
294 typedef uint64_t ngx_atomic_uint_t; | 118 typedef int64_t ngx_atomic_int_t; |
295 #define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 | 119 typedef uint64_t ngx_atomic_uint_t; |
120 #define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 | |
121 | |
296 #else | 122 #else |
297 typedef int32_t ngx_atomic_int_t; | 123 |
298 typedef uint32_t ngx_atomic_uint_t; | 124 typedef int32_t ngx_atomic_int_t; |
299 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 | 125 typedef uint32_t ngx_atomic_uint_t; |
126 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 | |
127 | |
300 #endif | 128 #endif |
301 | 129 |
302 typedef volatile ngx_atomic_uint_t ngx_atomic_t; | 130 typedef volatile ngx_atomic_uint_t ngx_atomic_t; |
303 | 131 |
304 | 132 |
305 /* | 133 #include "ngx_gcc_atomic_ppc.h" |
306 * the ppc assembler treats ";" as comment, so we have to use "\n". | |
307 * the minus in "bne-" is a hint for the branch prediction unit that | |
308 * this branch is unlikely to be taken. | |
309 * | |
310 * the "=&r" means that no input registers can be used. | |
311 * the "=&b" means that the base registers can be used only, i.e. | |
312 * any register except r0. the r0 register always has a zero value and | |
313 * could not be used in "addi r0, r0, 1". | |
314 * the "1b" means the nearest backward label "1" and the "1f" means | |
315 * the nearest forward label "1". | |
316 */ | |
317 | |
318 static ngx_inline ngx_atomic_uint_t | |
319 ngx_atomic_inc(ngx_atomic_t *value) | |
320 { | |
321 ngx_atomic_uint_t res; | |
322 | |
323 __asm__ volatile ( | |
324 | |
325 "1: lwarx %0, 0, %1 \n" /* load from [value] into "res" */ | |
326 /* and store reservation */ | |
327 " addi %0, %0, 1 \n" /* add "1" to "res" */ | |
328 " stwcx. %0, 0, %1 \n" /* store "res" into [value] if reservation */ | |
329 /* is not cleared */ | |
330 " bne- 1b \n" /* try again if reservation was cleared */ | |
331 | |
332 : "=&b" (res) : "r" (value) : "cc", "memory"); | |
333 | |
334 return res; | |
335 } | |
336 | 134 |
337 | 135 |
338 static ngx_inline ngx_atomic_uint_t | 136 #endif |
339 ngx_atomic_dec(ngx_atomic_t *value) | |
340 { | |
341 ngx_atomic_uint_t res; | |
342 | |
343 __asm__ volatile ( | |
344 | |
345 "1: lwarx %0, 0, %1 \n" /* load from [value] into "res" */ | |
346 /* and store reservation */ | |
347 " addi %0, %0, -1 \n" /* sub "1" from "res" */ | |
348 " stwcx. %0, 0, %1 \n" /* store "res" into [value] if reservation */ | |
349 /* is not cleared */ | |
350 " bne- 1b \n" /* try again if reservation was cleared */ | |
351 | |
352 : "=&b" (res) : "r" (value) : "cc", "memory"); | |
353 | |
354 return res; | |
355 } | |
356 | 137 |
357 | 138 |
358 static ngx_inline ngx_atomic_uint_t | 139 #if !(NGX_HAVE_ATOMIC_OPS) |
359 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, | |
360 ngx_atomic_uint_t set) | |
361 { | |
362 ngx_atomic_uint_t res, temp; | |
363 | |
364 __asm__ volatile ( | |
365 | |
366 " li %0, 0 \n" /* preset "0" to "res" */ | |
367 " lwarx %1, 0, %2 \n" /* load from [lock] into "temp" */ | |
368 /* and store reservation */ | |
369 " cmpw %1, %3 \n" /* compare "temp" and "old" */ | |
370 " bne- 1f \n" /* not equal */ | |
371 " stwcx. %4, 0, %2 \n" /* store "set" into [lock] if reservation */ | |
372 /* is not cleared */ | |
373 " bne- 1f \n" /* the reservation was cleared */ | |
374 " li %0, 1 \n" /* set "1" to "res" */ | |
375 "1: \n" | |
376 | |
377 : "=&r" (res), "=&r" (temp) | |
378 : "r" (lock), "r" (old), "r" (set) | |
379 : "cc", "memory"); | |
380 | |
381 return res; | |
382 } | |
383 | |
384 | |
385 #else | |
386 | 140 |
387 #define NGX_HAVE_ATOMIC_OPS 0 | 141 #define NGX_HAVE_ATOMIC_OPS 0 |
388 | 142 |
389 typedef int32_t ngx_atomic_int_t; | 143 typedef int32_t ngx_atomic_int_t; |
390 typedef uint32_t ngx_atomic_uint_t; | 144 typedef uint32_t ngx_atomic_uint_t; |
391 typedef volatile ngx_atomic_uint_t ngx_atomic_t; | 145 typedef volatile ngx_atomic_uint_t ngx_atomic_t; |
392 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 | 146 #define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 |
393 | 147 |
394 #define ngx_atomic_inc(x) ++(*(x)) | |
395 #define ngx_atomic_dec(x) --(*(x)) | |
396 | 148 |
397 static ngx_inline ngx_atomic_uint_t | 149 static ngx_inline ngx_atomic_uint_t |
398 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, | 150 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, |
399 ngx_atomic_uint_t set) | 151 ngx_atomic_uint_t set) |
400 { | 152 { |
401 *lock = set; | 153 if (*lock == old { |
402 return 1; | 154 *lock = set; |
155 return 1; | |
156 } | |
157 | |
158 return 0; | |
159 } | |
160 | |
161 | |
162 static ngx_inline ngx_atomic_int_t | |
163 ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) | |
164 { | |
165 ngx_atomic_int_t old; | |
166 | |
167 old = *value; | |
168 *value += add; | |
169 | |
170 return old; | |
403 } | 171 } |
404 | 172 |
405 #endif | 173 #endif |
406 | 174 |
407 | 175 |