1
2 /*
3 * Copyright (C) Ruslan Ermilov
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10
11
12 #if (NGX_HAVE_ATOMIC_OPS)
13
14
15 #define NGX_RWLOCK_SPIN 2048
16 #define NGX_RWLOCK_WLOCK ((ngx_atomic_uint_t) -1)
17
18
19 void
ngx_rwlock_wlock(ngx_atomic_t * lock)20 ngx_rwlock_wlock(ngx_atomic_t *lock)
21 {
22 ngx_uint_t i, n;
23
24 for ( ;; ) {
25
26 if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) {
27 return;
28 }
29
30 if (ngx_ncpu > 1) {
31
32 for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
33
34 for (i = 0; i < n; i++) {
35 ngx_cpu_pause();
36 }
37
38 if (*lock == 0
39 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK))
40 {
41 return;
42 }
43 }
44 }
45
46 ngx_sched_yield();
47 }
48 }
49
50
51 void
ngx_rwlock_rlock(ngx_atomic_t * lock)52 ngx_rwlock_rlock(ngx_atomic_t *lock)
53 {
54 ngx_uint_t i, n;
55 ngx_atomic_uint_t readers;
56
57 for ( ;; ) {
58 readers = *lock;
59
60 if (readers != NGX_RWLOCK_WLOCK
61 && ngx_atomic_cmp_set(lock, readers, readers + 1))
62 {
63 return;
64 }
65
66 if (ngx_ncpu > 1) {
67
68 for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
69
70 for (i = 0; i < n; i++) {
71 ngx_cpu_pause();
72 }
73
74 readers = *lock;
75
76 if (readers != NGX_RWLOCK_WLOCK
77 && ngx_atomic_cmp_set(lock, readers, readers + 1))
78 {
79 return;
80 }
81 }
82 }
83
84 ngx_sched_yield();
85 }
86 }
87
88
89 void
ngx_rwlock_unlock(ngx_atomic_t * lock)90 ngx_rwlock_unlock(ngx_atomic_t *lock)
91 {
92 ngx_atomic_uint_t readers;
93
94 readers = *lock;
95
96 if (readers == NGX_RWLOCK_WLOCK) {
97 (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0);
98 return;
99 }
100
101 for ( ;; ) {
102
103 if (ngx_atomic_cmp_set(lock, readers, readers - 1)) {
104 return;
105 }
106
107 readers = *lock;
108 }
109 }
110
111
112 void
ngx_rwlock_downgrade(ngx_atomic_t * lock)113 ngx_rwlock_downgrade(ngx_atomic_t *lock)
114 {
115 if (*lock == NGX_RWLOCK_WLOCK) {
116 *lock = 1;
117 }
118 }
119
120
121 #else
122
123 #if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE)
124
125 #error ngx_atomic_cmp_set() is not defined!
126
127 #endif
128
129 #endif
130