comparison src/os/unix/ngx_atomic.h @ 42:41ccba1aba45 NGINX_0_1_21

nginx 0.1.21 *) 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 <http://sysoev.ru>
date Tue, 22 Feb 2005 00:00:00 +0300
parents f0b350454894
children 4989c3d25945
comparison
equal deleted inserted replaced
41:4d8e7a81b3a0 42:41ccba1aba45
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