/src/server/mysys/thr_rwlock.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. |
2 | | |
3 | | This program is free software; you can redistribute it and/or modify |
4 | | it under the terms of the GNU General Public License as published by |
5 | | the Free Software Foundation; version 2 of the License. |
6 | | |
7 | | This program is distributed in the hope that it will be useful, |
8 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | GNU General Public License for more details. |
11 | | |
12 | | You should have received a copy of the GNU General Public License |
13 | | along with this program; if not, write to the Free Software |
14 | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ |
15 | | |
16 | | /* Synchronization - readers / writer thread locks */ |
17 | | |
18 | | #include "mysys_priv.h" |
19 | | #if defined(NEED_MY_RW_LOCK) |
20 | | #include <errno.h> |
21 | | |
22 | | #ifdef _WIN32 |
23 | | |
24 | | int my_rw_init(my_rw_lock_t *rwp) |
25 | | { |
26 | | InitializeSRWLock(&rwp->srwlock); |
27 | | rwp->have_exclusive_srwlock = FALSE; |
28 | | return 0; |
29 | | } |
30 | | |
31 | | |
32 | | int my_rw_rdlock(my_rw_lock_t *rwp) |
33 | | { |
34 | | AcquireSRWLockShared(&rwp->srwlock); |
35 | | return 0; |
36 | | } |
37 | | |
38 | | |
39 | | int my_rw_tryrdlock(my_rw_lock_t *rwp) |
40 | | { |
41 | | if (!TryAcquireSRWLockShared(&rwp->srwlock)) |
42 | | return EBUSY; |
43 | | return 0; |
44 | | } |
45 | | |
46 | | |
47 | | int my_rw_wrlock(my_rw_lock_t *rwp) |
48 | | { |
49 | | AcquireSRWLockExclusive(&rwp->srwlock); |
50 | | rwp->have_exclusive_srwlock= TRUE; |
51 | | return 0; |
52 | | } |
53 | | |
54 | | int my_rw_trywrlock(my_rw_lock_t *rwp) |
55 | | { |
56 | | if (!TryAcquireSRWLockExclusive(&rwp->srwlock)) |
57 | | return EBUSY; |
58 | | rwp->have_exclusive_srwlock= TRUE; |
59 | | return 0; |
60 | | } |
61 | | |
62 | | |
63 | | int my_rw_unlock(my_rw_lock_t *rwp) |
64 | | { |
65 | | if (rwp->have_exclusive_srwlock) |
66 | | { |
67 | | rwp->have_exclusive_srwlock= FALSE; |
68 | | ReleaseSRWLockExclusive(&rwp->srwlock); |
69 | | } |
70 | | else |
71 | | { |
72 | | ReleaseSRWLockShared(&rwp->srwlock); |
73 | | } |
74 | | return 0; |
75 | | } |
76 | | |
77 | | int my_rw_destroy(my_rw_lock_t* rwp) |
78 | | { |
79 | | DBUG_ASSERT(!rwp->have_exclusive_srwlock); |
80 | | return 0; |
81 | | } |
82 | | |
83 | | #else |
84 | | |
85 | | /* |
86 | | Source base from Sun Microsystems SPILT, simplified for MySQL use |
87 | | -- Joshua Chamas |
88 | | Some cleanup and additional code by Monty |
89 | | */ |
90 | | |
91 | | /* |
92 | | * Multithreaded Demo Source |
93 | | * |
94 | | * Copyright (C) 1995 by Sun Microsystems, Inc. |
95 | | * |
96 | | * |
97 | | * This file is a product of SunSoft, Inc. and is provided for |
98 | | * unrestricted use provided that this legend is included on all |
99 | | * media and as a part of the software program in whole or part. |
100 | | * Users may copy, modify or distribute this file at will. |
101 | | * |
102 | | * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING |
103 | | * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR |
104 | | * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. |
105 | | * |
106 | | * This file is provided with no support and without any obligation on the |
107 | | * part of SunSoft, Inc. to assist in its use, correction, modification or |
108 | | * enhancement. |
109 | | * |
110 | | * SUNSOFT AND SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT |
111 | | * TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS |
112 | | * FILE OR ANY PART THEREOF. |
113 | | * |
114 | | * IN NO EVENT WILL SUNSOFT OR SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY |
115 | | * LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL |
116 | | * DAMAGES, EVEN IF THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH |
117 | | * DAMAGES. |
118 | | * |
119 | | * SunSoft, Inc. |
120 | | * 2550 Garcia Avenue |
121 | | * Mountain View, California 94043 |
122 | | */ |
123 | | |
124 | | int my_rw_init(my_rw_lock_t *rwp) |
125 | | { |
126 | | pthread_condattr_t cond_attr; |
127 | | |
128 | | pthread_mutex_init( &rwp->lock, MY_MUTEX_INIT_FAST); |
129 | | pthread_condattr_init( &cond_attr ); |
130 | | pthread_cond_init( &rwp->readers, &cond_attr ); |
131 | | pthread_cond_init( &rwp->writers, &cond_attr ); |
132 | | pthread_condattr_destroy(&cond_attr); |
133 | | |
134 | | rwp->state = 0; |
135 | | rwp->waiters = 0; |
136 | | #ifdef SAFE_MUTEX |
137 | | rwp->write_thread = 0; |
138 | | #endif |
139 | | |
140 | | return(0); |
141 | | } |
142 | | |
143 | | |
144 | | int my_rw_destroy(my_rw_lock_t *rwp) |
145 | | { |
146 | | DBUG_ASSERT(rwp->state == 0); |
147 | | pthread_mutex_destroy( &rwp->lock ); |
148 | | pthread_cond_destroy( &rwp->readers ); |
149 | | pthread_cond_destroy( &rwp->writers ); |
150 | | return(0); |
151 | | } |
152 | | |
153 | | |
154 | | int my_rw_rdlock(my_rw_lock_t *rwp) |
155 | | { |
156 | | pthread_mutex_lock(&rwp->lock); |
157 | | |
158 | | /* active or queued writers */ |
159 | | while (( rwp->state < 0 ) || rwp->waiters) |
160 | | pthread_cond_wait( &rwp->readers, &rwp->lock); |
161 | | |
162 | | rwp->state++; |
163 | | pthread_mutex_unlock(&rwp->lock); |
164 | | return(0); |
165 | | } |
166 | | |
167 | | int my_rw_tryrdlock(my_rw_lock_t *rwp) |
168 | | { |
169 | | int res; |
170 | | pthread_mutex_lock(&rwp->lock); |
171 | | if ((rwp->state < 0 ) || rwp->waiters) |
172 | | res= EBUSY; /* Can't get lock */ |
173 | | else |
174 | | { |
175 | | res=0; |
176 | | rwp->state++; |
177 | | } |
178 | | pthread_mutex_unlock(&rwp->lock); |
179 | | return(res); |
180 | | } |
181 | | |
182 | | |
183 | | int my_rw_wrlock(my_rw_lock_t *rwp) |
184 | | { |
185 | | pthread_mutex_lock(&rwp->lock); |
186 | | rwp->waiters++; /* another writer queued */ |
187 | | |
188 | | my_rw_lock_assert_not_write_owner(rwp); |
189 | | |
190 | | while (rwp->state) |
191 | | pthread_cond_wait(&rwp->writers, &rwp->lock); |
192 | | rwp->state = -1; |
193 | | rwp->waiters--; |
194 | | #ifdef SAFE_MUTEX |
195 | | rwp->write_thread= pthread_self(); |
196 | | #endif |
197 | | pthread_mutex_unlock(&rwp->lock); |
198 | | return(0); |
199 | | } |
200 | | |
201 | | |
202 | | int my_rw_trywrlock(my_rw_lock_t *rwp) |
203 | | { |
204 | | int res; |
205 | | |
206 | | pthread_mutex_lock(&rwp->lock); |
207 | | if (rwp->state) |
208 | | res= EBUSY; /* Can't get lock */ |
209 | | else |
210 | | { |
211 | | res=0; |
212 | | rwp->state = -1; |
213 | | #ifdef SAFE_MUTEX |
214 | | rwp->write_thread= pthread_self(); |
215 | | #endif |
216 | | } |
217 | | pthread_mutex_unlock(&rwp->lock); |
218 | | return(res); |
219 | | } |
220 | | |
221 | | |
222 | | int my_rw_unlock(my_rw_lock_t *rwp) |
223 | | { |
224 | | DBUG_PRINT("rw_unlock", |
225 | | ("state: %d waiters: %d", rwp->state, rwp->waiters)); |
226 | | pthread_mutex_lock(&rwp->lock); |
227 | | |
228 | | DBUG_ASSERT(rwp->state != 0); |
229 | | |
230 | | if (rwp->state == -1) /* writer releasing */ |
231 | | { |
232 | | my_rw_lock_assert_write_owner(rwp); |
233 | | rwp->state= 0; /* mark as available */ |
234 | | #ifdef SAFE_MUTEX |
235 | | rwp->write_thread= 0; |
236 | | #endif |
237 | | |
238 | | if ( rwp->waiters ) /* writers queued */ |
239 | | pthread_cond_signal( &rwp->writers ); |
240 | | else |
241 | | pthread_cond_broadcast( &rwp->readers ); |
242 | | } |
243 | | else |
244 | | { |
245 | | if ( --rwp->state == 0 && /* no more readers */ |
246 | | rwp->waiters) |
247 | | pthread_cond_signal( &rwp->writers ); |
248 | | } |
249 | | |
250 | | pthread_mutex_unlock( &rwp->lock ); |
251 | | return(0); |
252 | | } |
253 | | |
254 | | #endif /* !defined _WIN32 */ |
255 | | #endif /* NEED_MY_RW_LOCK*/ |
256 | | |
257 | | |
258 | | int rw_pr_init(rw_pr_lock_t *rwlock) |
259 | 0 | { |
260 | 0 | pthread_mutex_init(&rwlock->lock, NULL); |
261 | 0 | pthread_cond_init(&rwlock->no_active_readers, NULL); |
262 | 0 | rwlock->active_readers= 0; |
263 | 0 | rwlock->writers_waiting_readers= 0; |
264 | 0 | rwlock->active_writer= FALSE; |
265 | | #ifdef SAFE_MUTEX |
266 | | rwlock->writer_thread= 0; |
267 | | #endif |
268 | 0 | return 0; |
269 | 0 | } |
270 | | |
271 | | |
272 | | int rw_pr_destroy(rw_pr_lock_t *rwlock) |
273 | 0 | { |
274 | 0 | pthread_cond_destroy(&rwlock->no_active_readers); |
275 | 0 | pthread_mutex_destroy(&rwlock->lock); |
276 | 0 | return 0; |
277 | 0 | } |
278 | | |
279 | | |
280 | | int rw_pr_rdlock(rw_pr_lock_t *rwlock) |
281 | 0 | { |
282 | 0 | pthread_mutex_lock(&rwlock->lock); |
283 | | /* |
284 | | The fact that we were able to acquire 'lock' mutex means |
285 | | that there are no active writers and we can acquire rd-lock. |
286 | | Increment active readers counter to prevent requests for |
287 | | wr-lock from succeeding and unlock mutex. |
288 | | */ |
289 | 0 | rwlock->active_readers++; |
290 | 0 | pthread_mutex_unlock(&rwlock->lock); |
291 | 0 | return 0; |
292 | 0 | } |
293 | | |
294 | | |
295 | | int rw_pr_wrlock(rw_pr_lock_t *rwlock) |
296 | 0 | { |
297 | 0 | pthread_mutex_lock(&rwlock->lock); |
298 | |
|
299 | 0 | if (rwlock->active_readers != 0) |
300 | 0 | { |
301 | | /* There are active readers. We have to wait until they are gone. */ |
302 | 0 | rwlock->writers_waiting_readers++; |
303 | |
|
304 | 0 | while (rwlock->active_readers != 0) |
305 | 0 | pthread_cond_wait(&rwlock->no_active_readers, &rwlock->lock); |
306 | |
|
307 | 0 | rwlock->writers_waiting_readers--; |
308 | 0 | } |
309 | | |
310 | | /* |
311 | | We own 'lock' mutex so there is no active writers. |
312 | | Also there are no active readers. |
313 | | This means that we can grant wr-lock. |
314 | | Not releasing 'lock' mutex until unlock will block |
315 | | both requests for rd and wr-locks. |
316 | | Set 'active_writer' flag to simplify unlock. |
317 | | |
318 | | Thanks to the fact wr-lock/unlock in the absence of |
319 | | contention from readers is essentially mutex lock/unlock |
320 | | with a few simple checks make this rwlock implementation |
321 | | wr-lock optimized. |
322 | | */ |
323 | 0 | rwlock->active_writer= TRUE; |
324 | | #ifdef SAFE_MUTEX |
325 | | rwlock->writer_thread= pthread_self(); |
326 | | #endif |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |
330 | | |
331 | | int rw_pr_unlock(rw_pr_lock_t *rwlock) |
332 | 0 | { |
333 | 0 | if (rwlock->active_writer) |
334 | 0 | { |
335 | | /* We are unlocking wr-lock. */ |
336 | | #ifdef SAFE_MUTEX |
337 | | rwlock->writer_thread= 0; |
338 | | #endif |
339 | 0 | rwlock->active_writer= FALSE; |
340 | 0 | if (rwlock->writers_waiting_readers) |
341 | 0 | { |
342 | | /* |
343 | | Avoid expensive cond signal in case when there is no contention |
344 | | or it is wr-only. |
345 | | |
346 | | Note that from view point of performance it would be better to |
347 | | signal on the condition variable after unlocking mutex (as it |
348 | | reduces number of contex switches). |
349 | | |
350 | | Unfortunately this would mean that such rwlock can't be safely |
351 | | used by MDL subsystem, which relies on the fact that it is OK |
352 | | to destroy rwlock once it is in unlocked state. |
353 | | */ |
354 | 0 | pthread_cond_signal(&rwlock->no_active_readers); |
355 | 0 | } |
356 | 0 | pthread_mutex_unlock(&rwlock->lock); |
357 | 0 | } |
358 | 0 | else |
359 | 0 | { |
360 | | /* We are unlocking rd-lock. */ |
361 | 0 | pthread_mutex_lock(&rwlock->lock); |
362 | 0 | rwlock->active_readers--; |
363 | 0 | if (rwlock->active_readers == 0 && |
364 | 0 | rwlock->writers_waiting_readers) |
365 | 0 | { |
366 | | /* |
367 | | If we are last reader and there are waiting |
368 | | writers wake them up. |
369 | | */ |
370 | 0 | pthread_cond_signal(&rwlock->no_active_readers); |
371 | 0 | } |
372 | 0 | pthread_mutex_unlock(&rwlock->lock); |
373 | 0 | } |
374 | 0 | return 0; |
375 | 0 | } |
376 | | |
377 | | |