-
Notifications
You must be signed in to change notification settings - Fork 211
/
Copy pathngx_rwlock.c
182 lines (139 loc) · 4.18 KB
/
ngx_rwlock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// annotated by chrono since 2016
/*
* Copyright (C) Ruslan Ermilov
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
// 必须支持原子操作,否则无法编译
#if (NGX_HAVE_ATOMIC_OPS)
// 读写锁也使用自旋,默认是2^11
#define NGX_RWLOCK_SPIN 2048
// 写锁的写入值
#define NGX_RWLOCK_WLOCK ((ngx_atomic_uint_t) -1)
// 写锁,相当于自旋
void
ngx_rwlock_wlock(ngx_atomic_t *lock)
{
ngx_uint_t i, n;
for ( ;; ) {
// 检查lock值,为0表示没有被锁
// 使用cas操作赋值-1,成功则获得锁
// 不会阻塞,失败则继续后续代码
// 相当于try_lock
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) {
return;
}
// 多核cpu,不必让出cpu,等待一下
if (ngx_ncpu > 1) {
for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
// cpu等待的时间逐步加长
for (i = 0; i < n; i++) {
// #define ngx_cpu_pause() __asm__ ("pause")
// 自旋等待,降低功耗,不会引起性能下降
ngx_cpu_pause();
}
// 再次try_lock
if (*lock == 0
&& ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK))
{
return;
}
}
}
// 占用cpu过久,让出cpu
// 单cpu必须让出cpu让其他进程运行
// 之后继续try_lock,直至lock成功
// yield不会进入睡眠
ngx_sched_yield();
}
}
// 读锁,相当于自旋
void
ngx_rwlock_rlock(ngx_atomic_t *lock)
{
ngx_uint_t i, n;
ngx_atomic_uint_t readers;
for ( ;; ) {
// 现有的读者数量
readers = *lock;
// 使用cas操作读者加1,成功则获得锁
// 不会阻塞,失败则继续后续代码
// 相当于try_lock
// 已经加写锁则直接失败
if (readers != NGX_RWLOCK_WLOCK
&& ngx_atomic_cmp_set(lock, readers, readers + 1))
{
return;
}
// 多核cpu,不必让出cpu,等待一下
if (ngx_ncpu > 1) {
for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
// cpu等待的时间逐步加长
for (i = 0; i < n; i++) {
// #define ngx_cpu_pause() __asm__ ("pause")
// 自旋等待,降低功耗,不会引起性能下降
ngx_cpu_pause();
}
// 必须重新取读者数量
readers = *lock;
// 再次try_lock
if (readers != NGX_RWLOCK_WLOCK
&& ngx_atomic_cmp_set(lock, readers, readers + 1))
{
return;
}
}
}
// 占用cpu过久,让出cpu
// 单cpu必须让出cpu让其他进程运行
// 之后继续try_lock,直至lock成功
// yield不会进入睡眠
ngx_sched_yield();
}
}
// 解锁
void
ngx_rwlock_unlock(ngx_atomic_t *lock)
{
// before 1.21.6
#if 0
ngx_atomic_uint_t readers;
// 现有的读者数量
readers = *lock;
// -1表示写锁
// 直接解锁,置0
if (readers == NGX_RWLOCK_WLOCK) {
(void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0);
return;
}
// 读锁则减少读者数量
// 循环保证减少成功
for ( ;; ) {
// 尝试减少值
if (ngx_atomic_cmp_set(lock, readers, readers - 1)) {
return;
}
// 不成功重新取读者数
readers = *lock;
#endif
// 1.21.6简化了代码
if (*lock == NGX_RWLOCK_WLOCK) {
(void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0);
} else {
(void) ngx_atomic_fetch_add(lock, -1);
}
}
// 锁降级,由写锁变成读锁
void
ngx_rwlock_downgrade(ngx_atomic_t *lock)
{
if (*lock == NGX_RWLOCK_WLOCK) {
*lock = 1;
}
}
#else
#if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE)
#error ngx_atomic_cmp_set() is not defined!
#endif
#endif