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