1
/*****************************************************************************
3
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
4
Copyright (c) 2008, Google Inc.
6
Portions of this file contain modifications contributed and copyrighted by
7
Google, Inc. Those modifications are gratefully acknowledged and are described
8
briefly in the InnoDB documentation. The contributions by Google are
9
incorporated with their permission, and subject to the conditions contained in
10
the file COPYING.Google.
12
This program is free software; you can redistribute it and/or modify it under
13
the terms of the GNU General Public License as published by the Free Software
14
Foundation; version 2 of the License.
16
This program is distributed in the hope that it will be useful, but WITHOUT
17
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License along with
21
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22
St, Fifth Floor, Boston, MA 02110-1301 USA
24
*****************************************************************************/
26
/**************************************************//**
27
@file include/sync0rw.h
28
The read-write lock (for threads, not for database transactions)
30
Created 9/11/1995 Heikki Tuuri
31
*******************************************************/
37
#ifndef UNIV_HOTBACKUP
39
#include "sync0sync.h"
42
/* The following undef is to prevent a name conflict with a macro
45
#endif /* !UNIV_HOTBACKUP */
47
/* Latch types; these are used also in btr0btr.h: keep the numerical values
48
smaller than 30 and the order of the numerical values like below! */
53
#ifndef UNIV_HOTBACKUP
54
/* We decrement lock_word by this amount for each x_lock. It is also the
55
start value for the lock_word, meaning that it limits the maximum number
56
of concurrent read locks before the rw_lock breaks. The current value of
57
0x00100000 allows 1,048,575 concurrent readers and 2047 recursive writers.*/
58
#define X_LOCK_DECR 0x00100000
60
typedef struct rw_lock_struct rw_lock_t;
61
#ifdef UNIV_SYNC_DEBUG
62
typedef struct rw_lock_debug_struct rw_lock_debug_t;
63
#endif /* UNIV_SYNC_DEBUG */
65
typedef UT_LIST_BASE_NODE_T(rw_lock_t) rw_lock_list_t;
67
extern rw_lock_list_t rw_lock_list;
68
extern mutex_t rw_lock_list_mutex;
70
#ifdef UNIV_SYNC_DEBUG
71
/* The global mutex which protects debug info lists of all rw-locks.
72
To modify the debug info list of an rw-lock, this mutex has to be
74
acquired in addition to the mutex protecting the lock. */
75
extern mutex_t rw_lock_debug_mutex;
76
extern os_event_t rw_lock_debug_event; /*!< If deadlock detection does
77
not get immediately the mutex it
78
may wait for this event */
79
extern ibool rw_lock_debug_waiters; /*!< This is set to TRUE, if
80
there may be waiters for the event */
81
#endif /* UNIV_SYNC_DEBUG */
83
/** number of spin waits on rw-latches,
84
resulted during exclusive (write) locks */
85
extern ib_int64_t rw_s_spin_wait_count;
86
/** number of spin loop rounds on rw-latches,
87
resulted during exclusive (write) locks */
88
extern ib_int64_t rw_s_spin_round_count;
89
/** number of unlocks (that unlock shared locks),
90
set only when UNIV_SYNC_PERF_STAT is defined */
91
extern ib_int64_t rw_s_exit_count;
92
/** number of OS waits on rw-latches,
93
resulted during shared (read) locks */
94
extern ib_int64_t rw_s_os_wait_count;
95
/** number of spin waits on rw-latches,
96
resulted during shared (read) locks */
97
extern ib_int64_t rw_x_spin_wait_count;
98
/** number of spin loop rounds on rw-latches,
99
resulted during shared (read) locks */
100
extern ib_int64_t rw_x_spin_round_count;
101
/** number of OS waits on rw-latches,
102
resulted during exclusive (write) locks */
103
extern ib_int64_t rw_x_os_wait_count;
104
/** number of unlocks (that unlock exclusive locks),
105
set only when UNIV_SYNC_PERF_STAT is defined */
106
extern ib_int64_t rw_x_exit_count;
108
/******************************************************************//**
109
Creates, or rather, initializes an rw-lock object in a specified memory
110
location (which must be appropriately aligned). The rw-lock is initialized
111
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
112
is necessary only if the memory block containing it is freed. */
114
# ifdef UNIV_SYNC_DEBUG
115
# define rw_lock_create(L, level) \
116
rw_lock_create_func((L), (level), #L, __FILE__, __LINE__)
117
# else /* UNIV_SYNC_DEBUG */
118
# define rw_lock_create(L, level) \
119
rw_lock_create_func((L), #L, __FILE__, __LINE__)
120
# endif /* UNIV_SYNC_DEBUG */
121
#else /* UNIV_DEBUG */
122
# define rw_lock_create(L, level) \
123
rw_lock_create_func((L), __FILE__, __LINE__)
124
#endif /* UNIV_DEBUG */
126
/******************************************************************//**
127
Creates, or rather, initializes an rw-lock object in a specified memory
128
location (which must be appropriately aligned). The rw-lock is initialized
129
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
130
is necessary only if the memory block containing it is freed. */
135
rw_lock_t* lock, /*!< in: pointer to memory */
137
# ifdef UNIV_SYNC_DEBUG
138
ulint level, /*!< in: level */
139
# endif /* UNIV_SYNC_DEBUG */
140
const char* cmutex_name, /*!< in: mutex name */
141
#endif /* UNIV_DEBUG */
142
const char* cfile_name, /*!< in: file name where created */
143
ulint cline); /*!< in: file line where created */
144
/******************************************************************//**
145
Calling this function is obligatory only if the memory buffer containing
146
the rw-lock is freed. Removes an rw-lock object from the global list. The
147
rw-lock is checked to be in the non-locked state. */
152
rw_lock_t* lock); /*!< in: rw-lock */
154
/******************************************************************//**
155
Checks that the rw-lock has been initialized and that there are no
156
simultaneous shared and exclusive locks.
162
rw_lock_t* lock); /*!< in: rw-lock */
163
#endif /* UNIV_DEBUG */
164
/**************************************************************//**
165
NOTE! The following macros should be used in rw s-locking, not the
166
corresponding function. */
168
#define rw_lock_s_lock(M) rw_lock_s_lock_func(\
169
(M), 0, __FILE__, __LINE__)
170
/**************************************************************//**
171
NOTE! The following macros should be used in rw s-locking, not the
172
corresponding function. */
174
#define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(\
175
(M), (P), __FILE__, __LINE__)
176
/**************************************************************//**
177
NOTE! The following macros should be used in rw s-locking, not the
178
corresponding function. */
180
#define rw_lock_s_lock_nowait(M, F, L) rw_lock_s_lock_low(\
182
/******************************************************************//**
183
Low-level function which tries to lock an rw-lock in s-mode. Performs no
185
@return TRUE if success */
190
rw_lock_t* lock, /*!< in: pointer to rw-lock */
191
ulint pass __attribute__((unused)),
192
/*!< in: pass value; != 0, if the lock will be
193
passed to another thread to unlock */
194
const char* file_name, /*!< in: file name where lock requested */
195
ulint line); /*!< in: line where requested */
196
/******************************************************************//**
197
NOTE! Use the corresponding macro, not directly this function, except if
198
you supply the file name and line number. Lock an rw-lock in shared mode
199
for the current thread. If the rw-lock is locked in exclusive mode, or
200
there is an exclusive lock request waiting, the function spins a preset
201
time (controlled by SYNC_SPIN_ROUNDS), waiting for the lock, before
202
suspending the thread. */
207
rw_lock_t* lock, /*!< in: pointer to rw-lock */
208
ulint pass, /*!< in: pass value; != 0, if the lock will
209
be passed to another thread to unlock */
210
const char* file_name,/*!< in: file name where lock requested */
211
ulint line); /*!< in: line where requested */
212
/******************************************************************//**
213
NOTE! Use the corresponding macro, not directly this function! Lock an
214
rw-lock in exclusive mode for the current thread if the lock can be
215
obtained immediately.
216
@return TRUE if success */
219
rw_lock_x_lock_func_nowait(
220
/*=======================*/
221
rw_lock_t* lock, /*!< in: pointer to rw-lock */
222
const char* file_name,/*!< in: file name where lock requested */
223
ulint line); /*!< in: line where requested */
224
/******************************************************************//**
225
Releases a shared mode lock. */
228
rw_lock_s_unlock_func(
229
/*==================*/
230
#ifdef UNIV_SYNC_DEBUG
231
ulint pass, /*!< in: pass value; != 0, if the lock may have
232
been passed to another thread to unlock */
234
rw_lock_t* lock); /*!< in/out: rw-lock */
236
#ifdef UNIV_SYNC_DEBUG
237
# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(P, L)
239
# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L)
241
/*******************************************************************//**
242
Releases a shared mode lock. */
243
#define rw_lock_s_unlock(L) rw_lock_s_unlock_gen(L, 0)
245
/**************************************************************//**
246
NOTE! The following macro should be used in rw x-locking, not the
247
corresponding function. */
249
#define rw_lock_x_lock(M) rw_lock_x_lock_func(\
250
(M), 0, __FILE__, __LINE__)
251
/**************************************************************//**
252
NOTE! The following macro should be used in rw x-locking, not the
253
corresponding function. */
255
#define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(\
256
(M), (P), __FILE__, __LINE__)
257
/**************************************************************//**
258
NOTE! The following macros should be used in rw x-locking, not the
259
corresponding function. */
261
#define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(\
262
(M), __FILE__, __LINE__)
263
/******************************************************************//**
264
NOTE! Use the corresponding macro, not directly this function! Lock an
265
rw-lock in exclusive mode for the current thread. If the rw-lock is locked
266
in shared or exclusive mode, or there is an exclusive lock request waiting,
267
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
268
for the lock, before suspending the thread. If the same thread has an x-lock
269
on the rw-lock, locking succeed, with the following exception: if pass != 0,
270
only a single x-lock may be taken on the lock. NOTE: If the same thread has
271
an s-lock, locking does not succeed! */
276
rw_lock_t* lock, /*!< in: pointer to rw-lock */
277
ulint pass, /*!< in: pass value; != 0, if the lock will
278
be passed to another thread to unlock */
279
const char* file_name,/*!< in: file name where lock requested */
280
ulint line); /*!< in: line where requested */
281
/******************************************************************//**
282
Releases an exclusive mode lock. */
285
rw_lock_x_unlock_func(
286
/*==================*/
287
#ifdef UNIV_SYNC_DEBUG
288
ulint pass, /*!< in: pass value; != 0, if the lock may have
289
been passed to another thread to unlock */
291
rw_lock_t* lock); /*!< in/out: rw-lock */
293
#ifdef UNIV_SYNC_DEBUG
294
# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(P, L)
296
# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L)
298
/*******************************************************************//**
299
Releases an exclusive mode lock. */
300
#define rw_lock_x_unlock(L) rw_lock_x_unlock_gen(L, 0)
302
/******************************************************************//**
303
Low-level function which locks an rw-lock in s-mode when we know that it
304
is possible and none else is currently accessing the rw-lock structure.
305
Then we can do the locking without reserving the mutex. */
308
rw_lock_s_lock_direct(
309
/*==================*/
310
rw_lock_t* lock, /*!< in/out: rw-lock */
311
const char* file_name, /*!< in: file name where requested */
312
ulint line); /*!< in: line where lock requested */
313
/******************************************************************//**
314
Low-level function which locks an rw-lock in x-mode when we know that it
315
is not locked and none else is currently accessing the rw-lock structure.
316
Then we can do the locking without reserving the mutex. */
319
rw_lock_x_lock_direct(
320
/*==================*/
321
rw_lock_t* lock, /*!< in/out: rw-lock */
322
const char* file_name, /*!< in: file name where requested */
323
ulint line); /*!< in: line where lock requested */
324
/******************************************************************//**
325
This function is used in the insert buffer to move the ownership of an
326
x-latch on a buffer frame to the current thread. The x-latch was set by
327
the buffer read operation and it protected the buffer frame while the
328
read was done. The ownership is moved because we want that the current
329
thread is able to acquire a second x-latch which is stored in an mtr.
330
This, in turn, is needed to pass the debug checks of index page
334
rw_lock_x_lock_move_ownership(
335
/*==========================*/
336
rw_lock_t* lock); /*!< in: lock which was x-locked in the
338
/******************************************************************//**
339
Releases a shared mode lock when we know there are no waiters and none
340
else will access the lock during the time this function is executed. */
343
rw_lock_s_unlock_direct(
344
/*====================*/
345
rw_lock_t* lock); /*!< in/out: rw-lock */
346
/******************************************************************//**
347
Releases an exclusive mode lock when we know there are no waiters, and
348
none else will access the lock durint the time this function is executed. */
351
rw_lock_x_unlock_direct(
352
/*====================*/
353
rw_lock_t* lock); /*!< in/out: rw-lock */
354
/******************************************************************//**
355
Returns the value of writer_count for the lock. Does not reserve the lock
356
mutex, so the caller must be sure it is not changed during the call.
357
@return value of writer_count */
360
rw_lock_get_x_lock_count(
361
/*=====================*/
362
const rw_lock_t* lock); /*!< in: rw-lock */
363
/********************************************************************//**
364
Check if there are threads waiting for the rw-lock.
365
@return 1 if waiters, 0 otherwise */
370
const rw_lock_t* lock); /*!< in: rw-lock */
371
/******************************************************************//**
372
Returns the write-status of the lock - this function made more sense
373
with the old rw_lock implementation.
374
@return RW_LOCK_NOT_LOCKED, RW_LOCK_EX, RW_LOCK_WAIT_EX */
379
const rw_lock_t* lock); /*!< in: rw-lock */
380
/******************************************************************//**
381
Returns the number of readers.
382
@return number of readers */
385
rw_lock_get_reader_count(
386
/*=====================*/
387
const rw_lock_t* lock); /*!< in: rw-lock */
388
/******************************************************************//**
389
Decrements lock_word the specified amount if it is greater than 0.
390
This is used by both s_lock and x_lock operations.
391
@return TRUE if decr occurs */
394
rw_lock_lock_word_decr(
395
/*===================*/
396
rw_lock_t* lock, /*!< in/out: rw-lock */
397
ulint amount); /*!< in: amount to decrement */
398
/******************************************************************//**
399
Increments lock_word the specified amount and returns new value.
400
@return lock->lock_word after increment */
403
rw_lock_lock_word_incr(
404
/*===================*/
405
rw_lock_t* lock, /*!< in/out: rw-lock */
406
ulint amount); /*!< in: amount to increment */
407
/******************************************************************//**
408
This function sets the lock->writer_thread and lock->recursive fields.
409
For platforms where we are using atomic builtins instead of lock->mutex
410
it sets the lock->writer_thread field using atomics to ensure memory
411
ordering. Note that it is assumed that the caller of this function
412
effectively owns the lock i.e.: nobody else is allowed to modify
413
lock->writer_thread at this point in time.
414
The protocol is that lock->writer_thread MUST be updated BEFORE the
415
lock->recursive flag is set. */
418
rw_lock_set_writer_id_and_recursion_flag(
419
/*=====================================*/
420
rw_lock_t* lock, /*!< in/out: lock to work on */
421
ibool recursive); /*!< in: TRUE if recursion
423
#ifdef UNIV_SYNC_DEBUG
424
/******************************************************************//**
425
Checks if the thread has locked the rw-lock in the specified mode, with
426
the pass value == 0. */
431
rw_lock_t* lock, /*!< in: rw-lock */
432
ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED,
434
__attribute__((warn_unused_result));
435
#endif /* UNIV_SYNC_DEBUG */
436
/******************************************************************//**
437
Checks if somebody has locked the rw-lock in the specified mode. */
442
rw_lock_t* lock, /*!< in: rw-lock */
443
ulint lock_type); /*!< in: lock type: RW_LOCK_SHARED,
445
#ifdef UNIV_SYNC_DEBUG
446
/***************************************************************//**
447
Prints debug info of an rw-lock. */
452
rw_lock_t* lock); /*!< in: rw-lock */
453
/***************************************************************//**
454
Prints debug info of currently locked rw-locks. */
457
rw_lock_list_print_info(
458
/*====================*/
459
FILE* file); /*!< in: file where to print */
460
/***************************************************************//**
461
Returns the number of currently locked rw-locks.
462
Works only in the debug version.
463
@return number of locked rw-locks */
466
rw_lock_n_locked(void);
467
/*==================*/
469
/*#####################################################################*/
471
/******************************************************************//**
472
Acquires the debug mutex. We cannot use the mutex defined in sync0sync,
473
because the debug mutex is also acquired in sync0arr while holding the OS
474
mutex protecting the sync array, and the ordinary mutex_enter might
475
recursively call routines in sync0arr, leading to a deadlock on the OS
479
rw_lock_debug_mutex_enter(void);
480
/*==========================*/
481
/******************************************************************//**
482
Releases the debug mutex. */
485
rw_lock_debug_mutex_exit(void);
486
/*==========================*/
487
/*********************************************************************//**
488
Prints info of a debug struct. */
493
rw_lock_debug_t* info); /*!< in: debug struct */
494
#endif /* UNIV_SYNC_DEBUG */
496
/* NOTE! The structure appears here only for the compiler to know its size.
497
Do not use its fields directly! */
499
/** The structure used in the spin lock implementation of a read-write
500
lock. Several threads may have a shared lock simultaneously in this
501
lock, but only one writer may have an exclusive lock, in which case no
502
shared locks are allowed. To prevent starving of a writer blocked by
503
readers, a writer may queue for x-lock by decrementing lock_word: no
504
new readers will be let in while the thread waits for readers to
506
struct rw_lock_struct {
507
volatile lint lock_word;
508
/*!< Holds the state of the lock. */
509
volatile ulint waiters;/*!< 1: there are waiters */
510
volatile ibool recursive;/*!< Default value FALSE which means the lock
511
is non-recursive. The value is typically set
512
to TRUE making normal rw_locks recursive. In
513
case of asynchronous IO, when a non-zero
514
value of 'pass' is passed then we keep the
516
This flag also tells us about the state of
517
writer_thread field. If this flag is set
518
then writer_thread MUST contain the thread
519
id of the current x-holder or wait-x thread.
520
This flag must be reset in x_unlock
521
functions before incrementing the lock_word */
522
volatile os_thread_id_t writer_thread;
523
/*!< Thread id of writer thread. Is only
524
guaranteed to have sane and non-stale
525
value iff recursive flag is set. */
526
os_event_t event; /*!< Used by sync0arr.c for thread queueing */
527
os_event_t wait_ex_event;
528
/*!< Event for next-writer to wait on. A thread
529
must decrement lock_word before waiting. */
530
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
531
mutex_t mutex; /*!< The mutex protecting rw_lock_struct */
532
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
534
UT_LIST_NODE_T(rw_lock_t) list;
535
/*!< All allocated rw locks are put into a
537
#ifdef UNIV_SYNC_DEBUG
538
UT_LIST_BASE_NODE_T(rw_lock_debug_t) debug_list;
539
/*!< In the debug version: pointer to the debug
540
info list of the lock */
541
ulint level; /*!< Level in the global latching order. */
542
#endif /* UNIV_SYNC_DEBUG */
543
ulint count_os_wait; /*!< Count of os_waits. May not be accurate */
544
const char* cfile_name;/*!< File name where lock created */
545
/* last s-lock file/line is not guaranteed to be correct */
546
const char* last_s_file_name;/*!< File name where last s-locked */
547
const char* last_x_file_name;/*!< File name where last x-locked */
548
ibool writer_is_wait_ex;
549
/*!< This is TRUE if the writer field is
550
RW_LOCK_WAIT_EX; this field is located far
551
from the memory update hotspot fields which
552
are at the start of this struct, thus we can
553
peek this field without causing much memory
555
unsigned cline:14; /*!< Line where created */
556
unsigned last_s_line:14; /*!< Line number where last time s-locked */
557
unsigned last_x_line:14; /*!< Line number where last time x-locked */
558
ulint magic_n; /*!< RW_LOCK_MAGIC_N */
561
/** Value of rw_lock_struct::magic_n */
562
#define RW_LOCK_MAGIC_N 22643
564
#ifdef UNIV_SYNC_DEBUG
565
/** The structure for storing debug info of an rw-lock */
566
struct rw_lock_debug_struct {
568
os_thread_id_t thread_id; /*!< The thread id of the thread which
569
locked the rw-lock */
570
ulint pass; /*!< Pass value given in the lock operation */
571
ulint lock_type; /*!< Type of the lock: RW_LOCK_EX,
572
RW_LOCK_SHARED, RW_LOCK_WAIT_EX */
573
const char* file_name;/*!< File name where the lock was obtained */
574
ulint line; /*!< Line where the rw-lock was locked */
575
UT_LIST_NODE_T(rw_lock_debug_t) list;
576
/*!< Debug structs are linked in a two-way
579
#endif /* UNIV_SYNC_DEBUG */
582
#include "sync0rw.ic"
584
#endif /* !UNIV_HOTBACKUP */