Coverage Report

Created: 2024-06-18 07:03

/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