1
/******************************************************
2
The read-write lock (for threads)
6
Created 9/11/1995 Heikki Tuuri
7
*******************************************************/
9
/**********************************************************************
10
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
11
locked in exclusive mode, or there is an exclusive lock request waiting,
12
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
13
waiting for the lock before suspending the thread. */
18
rw_lock_t* lock, /* in: pointer to rw-lock */
19
ulint pass, /* in: pass value; != 0, if the lock will
20
be passed to another thread to unlock */
21
const char* file_name,/* in: file name where lock requested */
22
ulint line); /* in: line where requested */
23
#ifdef UNIV_SYNC_DEBUG
24
/**********************************************************************
25
Inserts the debug information for an rw-lock. */
28
rw_lock_add_debug_info(
29
/*===================*/
30
rw_lock_t* lock, /* in: rw-lock */
31
ulint pass, /* in: pass value */
32
ulint lock_type, /* in: lock type */
33
const char* file_name, /* in: file where requested */
34
ulint line); /* in: line where requested */
35
/**********************************************************************
36
Removes a debug information struct for an rw-lock. */
39
rw_lock_remove_debug_info(
40
/*======================*/
41
rw_lock_t* lock, /* in: rw-lock */
42
ulint pass, /* in: pass value */
43
ulint lock_type); /* in: lock type */
44
#endif /* UNIV_SYNC_DEBUG */
46
/************************************************************************
47
Accessor functions for rw lock. */
54
return(lock->waiters);
84
rw_lock_get_reader_count(
85
/*=====================*/
88
return(lock->reader_count);
92
rw_lock_set_reader_count(
93
/*=====================*/
97
lock->reader_count = count;
105
return(&(lock->mutex));
108
/**********************************************************************
109
Returns the value of writer_count for the lock. Does not reserve the lock
110
mutex, so the caller must be sure it is not changed during the call. */
113
rw_lock_get_x_lock_count(
114
/*=====================*/
115
/* out: value of writer_count */
116
rw_lock_t* lock) /* in: rw-lock */
118
return(lock->writer_count);
121
/**********************************************************************
122
Low-level function which tries to lock an rw-lock in s-mode. Performs no
128
/* out: TRUE if success */
129
rw_lock_t* lock, /* in: pointer to rw-lock */
130
ulint pass __attribute__((unused)),
131
/* in: pass value; != 0, if the lock will be
132
passed to another thread to unlock */
133
const char* file_name, /* in: file name where lock requested */
134
ulint line) /* in: line where requested */
136
ut_ad(mutex_own(rw_lock_get_mutex(lock)));
138
/* Check if the writer field is free */
140
if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) {
141
/* Set the shared lock by incrementing the reader count */
142
lock->reader_count++;
144
#ifdef UNIV_SYNC_DEBUG
145
rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name,
148
lock->last_s_file_name = file_name;
149
lock->last_s_line = line;
151
return(TRUE); /* locking succeeded */
154
return(FALSE); /* locking did not succeed */
157
/**********************************************************************
158
Low-level function which locks an rw-lock in s-mode when we know that it
159
is possible and none else is currently accessing the rw-lock structure.
160
Then we can do the locking without reserving the mutex. */
163
rw_lock_s_lock_direct(
164
/*==================*/
165
rw_lock_t* lock, /* in: pointer to rw-lock */
166
const char* file_name, /* in: file name where requested */
167
ulint line) /* in: line where lock requested */
169
ut_ad(lock->writer == RW_LOCK_NOT_LOCKED);
170
ut_ad(rw_lock_get_reader_count(lock) == 0);
172
/* Set the shared lock by incrementing the reader count */
173
lock->reader_count++;
175
lock->last_s_file_name = file_name;
176
lock->last_s_line = line;
178
#ifdef UNIV_SYNC_DEBUG
179
rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);
183
/**********************************************************************
184
Low-level function which locks an rw-lock in x-mode when we know that it
185
is not locked and none else is currently accessing the rw-lock structure.
186
Then we can do the locking without reserving the mutex. */
189
rw_lock_x_lock_direct(
190
/*==================*/
191
rw_lock_t* lock, /* in: pointer to rw-lock */
192
const char* file_name, /* in: file name where requested */
193
ulint line) /* in: line where lock requested */
195
ut_ad(rw_lock_validate(lock));
196
ut_ad(rw_lock_get_reader_count(lock) == 0);
197
ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
199
rw_lock_set_writer(lock, RW_LOCK_EX);
200
lock->writer_thread = os_thread_get_curr_id();
201
lock->writer_count++;
204
lock->last_x_file_name = file_name;
205
lock->last_x_line = line;
207
#ifdef UNIV_SYNC_DEBUG
208
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
212
/**********************************************************************
213
NOTE! Use the corresponding macro, not directly this function! Lock an
214
rw-lock in shared mode for the current thread. If the rw-lock is locked
215
in exclusive mode, or there is an exclusive lock request waiting, the
216
function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for
217
the lock, before suspending the thread. */
222
rw_lock_t* lock, /* in: pointer to rw-lock */
223
ulint pass, /* in: pass value; != 0, if the lock will
224
be passed to another thread to unlock */
225
const char* file_name,/* in: file name where lock requested */
226
ulint line) /* in: line where requested */
228
/* NOTE: As we do not know the thread ids for threads which have
229
s-locked a latch, and s-lockers will be served only after waiting
230
x-lock requests have been fulfilled, then if this thread already
231
owns an s-lock here, it may end up in a deadlock with another thread
232
which requests an x-lock here. Therefore, we will forbid recursive
233
s-locking of a latch: the following assert will warn the programmer
234
of the possibility of this kind of a deadlock. If we want to implement
235
safe recursive s-locking, we should keep in a list the thread ids of
236
the threads which have s-locked a latch. This would use some CPU
239
#ifdef UNIV_SYNC_DEBUG
240
ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
241
#endif /* UNIV_SYNC_DEBUG */
243
mutex_enter(rw_lock_get_mutex(lock));
245
if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) {
246
mutex_exit(rw_lock_get_mutex(lock));
248
return; /* Success */
250
/* Did not succeed, try spin wait */
251
mutex_exit(rw_lock_get_mutex(lock));
253
rw_lock_s_lock_spin(lock, pass, file_name, line);
259
/**********************************************************************
260
NOTE! Use the corresponding macro, not directly this function! Lock an
261
rw-lock in shared mode for the current thread if the lock can be acquired
265
rw_lock_s_lock_func_nowait(
266
/*=======================*/
267
/* out: TRUE if success */
268
rw_lock_t* lock, /* in: pointer to rw-lock */
269
const char* file_name,/* in: file name where lock requested */
270
ulint line) /* in: line where requested */
272
ibool success = FALSE;
274
mutex_enter(rw_lock_get_mutex(lock));
276
if (lock->writer == RW_LOCK_NOT_LOCKED) {
277
/* Set the shared lock by incrementing the reader count */
278
lock->reader_count++;
280
#ifdef UNIV_SYNC_DEBUG
281
rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name,
285
lock->last_s_file_name = file_name;
286
lock->last_s_line = line;
291
mutex_exit(rw_lock_get_mutex(lock));
296
/**********************************************************************
297
NOTE! Use the corresponding macro, not directly this function! Lock an
298
rw-lock in exclusive mode for the current thread if the lock can be
299
obtained immediately. */
302
rw_lock_x_lock_func_nowait(
303
/*=======================*/
304
/* out: TRUE if success */
305
rw_lock_t* lock, /* in: pointer to rw-lock */
306
const char* file_name,/* in: file name where lock requested */
307
ulint line) /* in: line where requested */
309
ibool success = FALSE;
310
os_thread_id_t curr_thread = os_thread_get_curr_id();
311
mutex_enter(rw_lock_get_mutex(lock));
313
if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) {
314
} else if (UNIV_LIKELY(rw_lock_get_writer(lock)
315
== RW_LOCK_NOT_LOCKED)) {
316
rw_lock_set_writer(lock, RW_LOCK_EX);
317
lock->writer_thread = curr_thread;
320
lock->writer_count++;
322
#ifdef UNIV_SYNC_DEBUG
323
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
326
lock->last_x_file_name = file_name;
327
lock->last_x_line = line;
330
} else if (rw_lock_get_writer(lock) == RW_LOCK_EX
332
&& os_thread_eq(lock->writer_thread, curr_thread)) {
336
mutex_exit(rw_lock_get_mutex(lock));
338
ut_ad(rw_lock_validate(lock));
343
/**********************************************************************
344
Releases a shared mode lock. */
347
rw_lock_s_unlock_func(
348
/*==================*/
349
rw_lock_t* lock /* in: rw-lock */
350
#ifdef UNIV_SYNC_DEBUG
351
,ulint pass /* in: pass value; != 0, if the lock may have
352
been passed to another thread to unlock */
356
mutex_t* mutex = &(lock->mutex);
359
/* Acquire the mutex protecting the rw-lock fields */
362
/* Reset the shared lock by decrementing the reader count */
364
ut_a(lock->reader_count > 0);
365
lock->reader_count--;
367
#ifdef UNIV_SYNC_DEBUG
368
rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
371
/* If there may be waiters and this was the last s-lock,
374
if (UNIV_UNLIKELY(lock->waiters)
375
&& lock->reader_count == 0) {
378
rw_lock_set_waiters(lock, 0);
383
if (UNIV_UNLIKELY(sg)) {
384
sync_array_signal_object(sync_primary_wait_array, lock);
387
ut_ad(rw_lock_validate(lock));
389
#ifdef UNIV_SYNC_PERF_STAT
394
/**********************************************************************
395
Releases a shared mode lock when we know there are no waiters and none
396
else will access the lock during the time this function is executed. */
399
rw_lock_s_unlock_direct(
400
/*====================*/
401
rw_lock_t* lock) /* in: rw-lock */
403
/* Reset the shared lock by decrementing the reader count */
405
ut_ad(lock->reader_count > 0);
407
lock->reader_count--;
409
#ifdef UNIV_SYNC_DEBUG
410
rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
413
ut_ad(!lock->waiters);
414
ut_ad(rw_lock_validate(lock));
415
#ifdef UNIV_SYNC_PERF_STAT
420
/**********************************************************************
421
Releases an exclusive mode lock. */
424
rw_lock_x_unlock_func(
425
/*==================*/
426
rw_lock_t* lock /* in: rw-lock */
427
#ifdef UNIV_SYNC_DEBUG
428
,ulint pass /* in: pass value; != 0, if the lock may have
429
been passed to another thread to unlock */
435
/* Acquire the mutex protecting the rw-lock fields */
436
mutex_enter(&(lock->mutex));
438
/* Reset the exclusive lock if this thread no longer has an x-mode
441
ut_ad(lock->writer_count > 0);
443
lock->writer_count--;
445
if (lock->writer_count == 0) {
446
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
449
#ifdef UNIV_SYNC_DEBUG
450
rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
453
/* If there may be waiters, signal the lock */
454
if (UNIV_UNLIKELY(lock->waiters)
455
&& lock->writer_count == 0) {
458
rw_lock_set_waiters(lock, 0);
461
mutex_exit(&(lock->mutex));
463
if (UNIV_UNLIKELY(sg)) {
464
sync_array_signal_object(sync_primary_wait_array, lock);
467
ut_ad(rw_lock_validate(lock));
469
#ifdef UNIV_SYNC_PERF_STAT
474
/**********************************************************************
475
Releases an exclusive mode lock when we know there are no waiters, and
476
none else will access the lock durint the time this function is executed. */
479
rw_lock_x_unlock_direct(
480
/*====================*/
481
rw_lock_t* lock) /* in: rw-lock */
483
/* Reset the exclusive lock if this thread no longer has an x-mode
486
ut_ad(lock->writer_count > 0);
488
lock->writer_count--;
490
if (lock->writer_count == 0) {
491
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
494
#ifdef UNIV_SYNC_DEBUG
495
rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
498
ut_ad(!lock->waiters);
499
ut_ad(rw_lock_validate(lock));
501
#ifdef UNIV_SYNC_PERF_STAT