comparison src/core/ngx_shmtx.c @ 4309:3f6040cd731e

Added shmtx interface to forcibly unlock mutexes. It is currently used from master process on abnormal worker termination to unlock accept mutex (unlocking of accept mutex was broken in 1.0.2). It is expected to be used in the future to unlock other mutexes as well. Shared mutex code was rewritten to make this possible in a safe way, i.e. with a check if lock was actually held by the exited process. We again use pid to lock mutex, and use separate atomic variable for a count of processes waiting in sem_wait().
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 23 Nov 2011 13:55:38 +0000
parents 0daede16d68b
children 13f108b9f3cf
comparison
equal deleted inserted replaced
4308:39982fa69482 4309:3f6040cd731e
9 9
10 10
11 #if (NGX_HAVE_ATOMIC_OPS) 11 #if (NGX_HAVE_ATOMIC_OPS)
12 12
13 13
14 static void ngx_shmtx_wakeup(ngx_shmtx_t *mtx);
15
16
14 ngx_int_t 17 ngx_int_t
15 ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name) 18 ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
16 { 19 {
17 mtx->lock = addr; 20 mtx->lock = &addr->lock;
18 21
19 if (mtx->spin == (ngx_uint_t) -1) { 22 if (mtx->spin == (ngx_uint_t) -1) {
20 return NGX_OK; 23 return NGX_OK;
21 } 24 }
22 25
23 mtx->spin = 2048; 26 mtx->spin = 2048;
24 27
25 #if (NGX_HAVE_POSIX_SEM) 28 #if (NGX_HAVE_POSIX_SEM)
29
30 mtx->wait = &addr->wait;
26 31
27 if (sem_init(&mtx->sem, 1, 0) == -1) { 32 if (sem_init(&mtx->sem, 1, 0) == -1) {
28 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, 33 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
29 "sem_init() failed"); 34 "sem_init() failed");
30 } else { 35 } else {
54 59
55 60
56 ngx_uint_t 61 ngx_uint_t
57 ngx_shmtx_trylock(ngx_shmtx_t *mtx) 62 ngx_shmtx_trylock(ngx_shmtx_t *mtx)
58 { 63 {
59 ngx_atomic_uint_t val; 64 return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
60
61 val = *mtx->lock;
62
63 return ((val & 0x80000000) == 0
64 && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000));
65 } 65 }
66 66
67 67
68 void 68 void
69 ngx_shmtx_lock(ngx_shmtx_t *mtx) 69 ngx_shmtx_lock(ngx_shmtx_t *mtx)
70 { 70 {
71 ngx_uint_t i, n; 71 ngx_uint_t i, n;
72 ngx_atomic_uint_t val;
73 72
74 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock"); 73 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");
75 74
76 for ( ;; ) { 75 for ( ;; ) {
77 76
78 val = *mtx->lock; 77 if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
79
80 if ((val & 0x80000000) == 0
81 && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
82 {
83 return; 78 return;
84 } 79 }
85 80
86 if (ngx_ncpu > 1) { 81 if (ngx_ncpu > 1) {
87 82
89 84
90 for (i = 0; i < n; i++) { 85 for (i = 0; i < n; i++) {
91 ngx_cpu_pause(); 86 ngx_cpu_pause();
92 } 87 }
93 88
94 val = *mtx->lock; 89 if (*mtx->lock == 0
95 90 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid))
96 if ((val & 0x80000000) == 0
97 && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
98 { 91 {
99 return; 92 return;
100 } 93 }
101 } 94 }
102 } 95 }
103 96
104 #if (NGX_HAVE_POSIX_SEM) 97 #if (NGX_HAVE_POSIX_SEM)
105 98
106 if (mtx->semaphore) { 99 if (mtx->semaphore) {
107 val = *mtx->lock; 100 ngx_atomic_fetch_add(mtx->wait, 1);
108 101
109 if ((val & 0x80000000) 102 if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
110 && ngx_atomic_cmp_set(mtx->lock, val, val + 1)) 103 return;
111 { 104 }
112 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 105
113 "shmtx wait %XA", val); 106 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
114 107 "shmtx wait %uA", *mtx->wait);
115 while (sem_wait(&mtx->sem) == -1) { 108
116 ngx_err_t err; 109 while (sem_wait(&mtx->sem) == -1) {
117 110 ngx_err_t err;
118 err = ngx_errno; 111
119 112 err = ngx_errno;
120 if (err != NGX_EINTR) { 113
121 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err, 114 if (err != NGX_EINTR) {
122 "sem_wait() failed while waiting on shmtx"); 115 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
123 break; 116 "sem_wait() failed while waiting on shmtx");
124 } 117 break;
125 } 118 }
126 119
127 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 120 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
128 "shmtx awoke"); 121 "shmtx awoke");
129 } 122 }
139 132
140 133
141 void 134 void
142 ngx_shmtx_unlock(ngx_shmtx_t *mtx) 135 ngx_shmtx_unlock(ngx_shmtx_t *mtx)
143 { 136 {
144 ngx_atomic_uint_t val, old, wait;
145
146 if (mtx->spin != (ngx_uint_t) -1) { 137 if (mtx->spin != (ngx_uint_t) -1) {
147 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock"); 138 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
148 } 139 }
149 140
141 if (ngx_atomic_cmp_set(mtx->lock, ngx_pid, 0)) {
142 ngx_shmtx_wakeup(mtx);
143 }
144 }
145
146
147 ngx_uint_t
148 ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
149 {
150 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
151 "shmtx forced unlock");
152
153 if (ngx_atomic_cmp_set(mtx->lock, pid, 0)) {
154 ngx_shmtx_wakeup(mtx);
155 return 1;
156 }
157
158 return 0;
159 }
160
161
162 static void
163 ngx_shmtx_wakeup(ngx_shmtx_t *mtx)
164 {
165 #if (NGX_HAVE_POSIX_SEM)
166 ngx_atomic_uint_t wait;
167
168 if (!mtx->semaphore) {
169 return;
170 }
171
150 for ( ;; ) { 172 for ( ;; ) {
151 173
152 old = *mtx->lock; 174 wait = *mtx->wait;
153 wait = old & 0x7fffffff; 175
154 val = wait ? wait - 1 : 0; 176 if (wait == 0) {
155 177 return;
156 if (ngx_atomic_cmp_set(mtx->lock, old, val)) { 178 }
179
180 if (ngx_atomic_cmp_set(mtx->wait, wait, wait - 1)) {
157 break; 181 break;
158 } 182 }
159 } 183 }
160 184
161 #if (NGX_HAVE_POSIX_SEM)
162
163 if (wait == 0 || !mtx->semaphore) {
164 return;
165 }
166
167 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 185 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
168 "shmtx wake %XA", old); 186 "shmtx wake %uA", wait);
169 187
170 if (sem_post(&mtx->sem) == -1) { 188 if (sem_post(&mtx->sem) == -1) {
171 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, 189 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
172 "sem_post() failed while wake shmtx"); 190 "sem_post() failed while wake shmtx");
173 } 191 }
178 196
179 #else 197 #else
180 198
181 199
182 ngx_int_t 200 ngx_int_t
183 ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name) 201 ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
184 { 202 {
185 if (mtx->name) { 203 if (mtx->name) {
186 204
187 if (ngx_strcmp(name, mtx->name) == 0) { 205 if (ngx_strcmp(name, mtx->name) == 0) {
188 mtx->name = name; 206 mtx->name = name;
278 } 296 }
279 297
280 ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name); 298 ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
281 } 299 }
282 300
283 #endif 301
302 void
303 ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
304 {
305 /* void */
306 }
307
308 #endif