diff options
Diffstat (limited to 'innobase/include/sync0rw.h')
-rw-r--r-- | innobase/include/sync0rw.h | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/innobase/include/sync0rw.h b/innobase/include/sync0rw.h new file mode 100644 index 00000000000..20afdfb025f --- /dev/null +++ b/innobase/include/sync0rw.h @@ -0,0 +1,493 @@ +/****************************************************** +The read-write lock (for threads, not for database transactions) + +(c) 1995 Innobase Oy + +Created 9/11/1995 Heikki Tuuri +*******************************************************/ + +#ifndef sync0rw_h +#define sync0rw_h + +#include "univ.i" +#include "ut0lst.h" +#include "sync0sync.h" +#include "os0sync.h" + +/* The following undef is to prevent a name conflict with a macro +in MySQL: */ +#undef rw_lock_t + +/* Latch types; these are used also in btr0btr.h: keep the numerical values +smaller than 30 and the order of the numerical values like below! */ +#define RW_S_LATCH 1 +#define RW_X_LATCH 2 +#define RW_NO_LATCH 3 + +typedef struct rw_lock_struct rw_lock_t; +typedef struct rw_lock_debug_struct rw_lock_debug_t; + +typedef UT_LIST_BASE_NODE_T(rw_lock_t) rw_lock_list_t; + +extern rw_lock_list_t rw_lock_list; +extern mutex_t rw_lock_list_mutex; + +/* The global mutex which protects debug info lists of all rw-locks. +To modify the debug info list of an rw-lock, this mutex has to be + +acquired in addition to the mutex protecting the lock. */ +extern mutex_t rw_lock_debug_mutex; +extern os_event_t rw_lock_debug_event; /* If deadlock detection does + not get immediately the mutex it + may wait for this event */ +extern ibool rw_lock_debug_waiters; /* This is set to TRUE, if + there may be waiters for the event */ + +extern ulint rw_s_system_call_count; +extern ulint rw_s_spin_wait_count; +extern ulint rw_s_exit_count; + +extern ulint rw_x_system_call_count; +extern ulint rw_x_spin_wait_count; +extern ulint rw_x_exit_count; + +/********************************************************************** +Creates, or rather, initializes an rw-lock object in a specified memory +location (which must be appropriately aligned). The rw-lock is initialized +to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free +is necessary only if the memory block containing it is freed. */ + +#define rw_lock_create(L) rw_lock_create_func((L), __FILE__, __LINE__) +/*=====================*/ +/********************************************************************** +Creates, or rather, initializes an rw-lock object in a specified memory +location (which must be appropriately aligned). The rw-lock is initialized +to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free +is necessary only if the memory block containing it is freed. */ + +void +rw_lock_create_func( +/*================*/ + rw_lock_t* lock, /* in: pointer to memory */ + char* cfile_name, /* in: file name where created */ + ulint cline); /* in: file line where created */ +/********************************************************************** +Calling this function is obligatory only if the memory buffer containing +the rw-lock is freed. Removes an rw-lock object from the global list. The +rw-lock is checked to be in the non-locked state. */ + +void +rw_lock_free( +/*=========*/ + rw_lock_t* lock); /* in: rw-lock */ +/********************************************************************** +Checks that the rw-lock has been initialized and that there are no +simultaneous shared and exclusive locks. */ + +ibool +rw_lock_validate( +/*=============*/ + rw_lock_t* lock); +/****************************************************************** +NOTE! The following macros should be used in rw s-locking, not the +corresponding function. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_s_lock(M) rw_lock_s_lock_func(\ + (M), 0, __FILE__, __LINE__) +#else +#define rw_lock_s_lock(M) rw_lock_s_lock_func(M) +#endif +/****************************************************************** +NOTE! The following macros should be used in rw s-locking, not the +corresponding function. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(\ + (M), (P), __FILE__, __LINE__) +#else +#define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(M) +#endif +/****************************************************************** +NOTE! The following macros should be used in rw s-locking, not the +corresponding function. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_s_lock_nowait(M) rw_lock_s_lock_func_nowait(\ + (M), __FILE__, __LINE__) +#else +#define rw_lock_s_lock_nowait(M) rw_lock_s_lock_func_nowait(M) +#endif +/********************************************************************** +NOTE! Use the corresponding macro, not directly this function, except if +you supply the file name and line number. Lock an rw-lock in shared mode +for the current thread. If the rw-lock is locked in exclusive mode, or +there is an exclusive lock request waiting, the function spins a preset +time (controlled by SYNC_SPIN_ROUNDS), waiting for the lock, before +suspending the thread. */ +UNIV_INLINE +void +rw_lock_s_lock_func( +/*================*/ + rw_lock_t* lock /* in: pointer to rw-lock */ + #ifdef UNIV_SYNC_DEBUG + ,ulint pass, /* in: pass value; != 0, if the lock will + be passed to another thread to unlock */ + char* file_name, /* in: file name where lock requested */ + ulint line /* in: line where requested */ + #endif +); +/********************************************************************** +NOTE! Use the corresponding macro, not directly this function, except if +you supply the file name and line number. Lock an rw-lock in shared mode +for the current thread if the lock can be acquired immediately. */ +UNIV_INLINE +ibool +rw_lock_s_lock_func_nowait( +/*=======================*/ + /* out: TRUE if success */ + rw_lock_t* lock /* in: pointer to rw-lock */ + #ifdef UNIV_SYNC_DEBUG + ,char* file_name, /* in: file name where lock requested */ + ulint line /* in: line where requested */ + #endif +); +/********************************************************************** +NOTE! Use the corresponding macro, not directly this function! Lock an +rw-lock in exclusive mode for the current thread if the lock can be +obtained immediately. */ +UNIV_INLINE +ibool +rw_lock_x_lock_func_nowait( +/*=======================*/ + /* out: TRUE if success */ + rw_lock_t* lock /* in: pointer to rw-lock */ + #ifdef UNIV_SYNC_DEBUG + ,char* file_name, /* in: file name where lock requested */ + ulint line /* in: line where requested */ + #endif +); +/********************************************************************** +Releases a shared mode lock. */ +UNIV_INLINE +void +rw_lock_s_unlock_func( +/*==================*/ + rw_lock_t* lock /* in: rw-lock */ +#ifdef UNIV_SYNC_DEBUG + ,ulint pass /* in: pass value; != 0, if the lock may have + been passed to another thread to unlock */ +#endif + ); +/*********************************************************************** +Releases a shared mode lock. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_s_unlock(L) rw_lock_s_unlock_func(L, 0) +#else +#define rw_lock_s_unlock(L) rw_lock_s_unlock_func(L) +#endif +/*********************************************************************** +Releases a shared mode lock. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L, P) +#else +#define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L) +#endif +/****************************************************************** +NOTE! The following macro should be used in rw x-locking, not the +corresponding function. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_x_lock(M) rw_lock_x_lock_func(\ + (M), 0, __FILE__, __LINE__) +#else +#define rw_lock_x_lock(M) rw_lock_x_lock_func(M, 0) +#endif +/****************************************************************** +NOTE! The following macro should be used in rw x-locking, not the +corresponding function. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(\ + (M), (P), __FILE__, __LINE__) +#else +#define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(M, P) +#endif +/****************************************************************** +NOTE! The following macros should be used in rw x-locking, not the +corresponding function. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(\ + (M), __FILE__, __LINE__) +#else +#define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(M) +#endif +/********************************************************************** +NOTE! Use the corresponding macro, not directly this function! Lock an +rw-lock in exclusive mode for the current thread. If the rw-lock is locked +in shared or exclusive mode, or there is an exclusive lock request waiting, +the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting +for the lock, before suspending the thread. If the same thread has an x-lock +on the rw-lock, locking succeed, with the following exception: if pass != 0, +only a single x-lock may be taken on the lock. NOTE: If the same thread has +an s-lock, locking does not succeed! */ + +void +rw_lock_x_lock_func( +/*================*/ + rw_lock_t* lock, /* in: pointer to rw-lock */ + ulint pass /* in: pass value; != 0, if the lock will + be passed to another thread to unlock */ + #ifdef UNIV_SYNC_DEBUG + ,char* file_name, /* in: file name where lock requested */ + ulint line /* in: line where requested */ + #endif +); +/********************************************************************** +Releases an exclusive mode lock. */ +UNIV_INLINE +void +rw_lock_x_unlock_func( +/*==================*/ + rw_lock_t* lock /* in: rw-lock */ +#ifdef UNIV_SYNC_DEBUG + ,ulint pass /* in: pass value; != 0, if the lock may have + been passed to another thread to unlock */ +#endif + ); +/*********************************************************************** +Releases an exclusive mode lock. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_x_unlock(L) rw_lock_x_unlock_func(L, 0) +#else +#define rw_lock_x_unlock(L) rw_lock_x_unlock_func(L) +#endif +/*********************************************************************** +Releases an exclusive mode lock. */ + +#ifdef UNIV_SYNC_DEBUG +#define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L, P) +#else +#define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L) +#endif +/********************************************************************** +Low-level function which locks an rw-lock in s-mode when we know that it +is possible and none else is currently accessing the rw-lock structure. +Then we can do the locking without reserving the mutex. */ +UNIV_INLINE +void +rw_lock_s_lock_direct( +/*==================*/ + rw_lock_t* lock /* in: pointer to rw-lock */ + #ifdef UNIV_SYNC_DEBUG + ,char* file_name, /* in: file name where lock requested */ + ulint line /* in: line where requested */ + #endif +); +/********************************************************************** +Low-level function which locks an rw-lock in x-mode when we know that it +is not locked and none else is currently accessing the rw-lock structure. +Then we can do the locking without reserving the mutex. */ +UNIV_INLINE +void +rw_lock_x_lock_direct( +/*==================*/ + rw_lock_t* lock /* in: pointer to rw-lock */ + #ifdef UNIV_SYNC_DEBUG + ,char* file_name, /* in: file name where lock requested */ + ulint line /* in: line where requested */ + #endif +); +/********************************************************************** +This function is used in the insert buffer to move the ownership of an +x-latch on a buffer frame to the current thread. The x-latch was set by +the buffer read operation and it protected the buffer frame while the +read was done. The ownership is moved because we want that the current +thread is able to acquire a second x-latch which is stored in an mtr. +This, in turn, is needed to pass the debug checks of index page +operations. */ + +void +rw_lock_x_lock_move_ownership( +/*==========================*/ + rw_lock_t* lock); /* in: lock which was x-locked in the + buffer read */ +/********************************************************************** +Releases a shared mode lock when we know there are no waiters and none +else will access the lock during the time this function is executed. */ +UNIV_INLINE +void +rw_lock_s_unlock_direct( +/*====================*/ + rw_lock_t* lock); /* in: rw-lock */ +/********************************************************************** +Releases an exclusive mode lock when we know there are no waiters, and +none else will access the lock durint the time this function is executed. */ +UNIV_INLINE +void +rw_lock_x_unlock_direct( +/*====================*/ + rw_lock_t* lock); /* in: rw-lock */ +/********************************************************************** +Sets the rw-lock latching level field. */ + +void +rw_lock_set_level( +/*==============*/ + rw_lock_t* lock, /* in: rw-lock */ + ulint level); /* in: level */ +/********************************************************************** +Returns the value of writer_count for the lock. Does not reserve the lock +mutex, so the caller must be sure it is not changed during the call. */ +UNIV_INLINE +ulint +rw_lock_get_x_lock_count( +/*=====================*/ + /* out: value of writer_count */ + rw_lock_t* lock); /* in: rw-lock */ +/********************************************************************** +Checks if the thread has locked the rw-lock in the specified mode, with +the pass value == 0. */ + +ibool +rw_lock_own( +/*========*/ + rw_lock_t* lock, /* in: rw-lock */ + ulint lock_type); /* in: lock type */ +/********************************************************************** +Checks if somebody has locked the rw-lock in the specified mode. */ + +ibool +rw_lock_is_locked( +/*==============*/ + rw_lock_t* lock, /* in: rw-lock */ + ulint lock_type); /* in: lock type: RW_LOCK_SHARED, + RW_LOCK_EX */ +/******************************************************************* +Prints debug info of an rw-lock. */ + +void +rw_lock_print( +/*==========*/ + rw_lock_t* lock); /* in: rw-lock */ +/******************************************************************* +Prints debug info of currently locked rw-locks. */ + +void +rw_lock_list_print_info(void); +/*=========================*/ +/******************************************************************* +Returns the number of currently locked rw-locks. +Works only in the debug version. */ + +ulint +rw_lock_n_locked(void); +/*==================*/ + +/*#####################################################################*/ + +/********************************************************************** +Acquires the debug mutex. We cannot use the mutex defined in sync0sync, +because the debug mutex is also acquired in sync0arr while holding the OS +mutex protecting the sync array, and the ordinary mutex_enter might +recursively call routines in sync0arr, leading to a deadlock on the OS +mutex. */ + +void +rw_lock_debug_mutex_enter(void); +/*==========================*/ +/********************************************************************** +Releases the debug mutex. */ + +void +rw_lock_debug_mutex_exit(void); +/*==========================*/ +/************************************************************************* +Prints info of a debug struct. */ + +void +rw_lock_debug_print( +/*================*/ + rw_lock_debug_t* info); /* in: debug struct */ + + +#define RW_CNAME_LEN 8 + +/* NOTE! The structure appears here only for the compiler to know its size. +Do not use its fields directly! The structure used in the spin lock +implementation of a read-write lock. Several threads may have a shared lock +simultaneously in this lock, but only one writer may have an exclusive lock, +in which case no shared locks are allowed. To prevent starving of a writer +blocked by readers, a writer may queue for the lock by setting the writer +field. Then no new readers are allowed in. */ + +struct rw_lock_struct { + ulint reader_count; /* Number of readers who have locked this + lock in the shared mode */ + ulint writer; /* This field is set to RW_LOCK_EX if there + is a writer owning the lock (in exclusive + mode), RW_LOCK_WAIT_EX if a writer is + queueing for the lock, and + RW_LOCK_NOT_LOCKED, otherwise. */ + os_thread_id_t writer_thread; + /* Thread id of a possible writer thread */ + ulint writer_count; /* Number of times the same thread has + recursively locked the lock in the exclusive + mode */ + mutex_t mutex; /* The mutex protecting rw_lock_struct */ + ulint pass; /* Default value 0. This is set to some + value != 0 given by the caller of an x-lock + operation, if the x-lock is to be passed to + another thread to unlock (which happens in + asynchronous i/o). */ + ulint waiters; /* This ulint is set to 1 if there are + waiters (readers or writers) in the global + wait array, waiting for this rw_lock. + Otherwise, = 0. */ + ibool writer_is_wait_ex; + /* This is TRUE if the writer field is + RW_LOCK_WAIT_EX; this field is located far + from the memory update hotspot fields which + are at the start of this struct, thus we can + peek this field without causing much memory + bus traffic */ + UT_LIST_NODE_T(rw_lock_t) list; + /* All allocated rw locks are put into a + list */ + UT_LIST_BASE_NODE_T(rw_lock_debug_t) debug_list; + /* In the debug version: pointer to the debug + info list of the lock */ + ulint level; /* Debug version: level in the global latching + order; default SYNC_LEVEL_NONE */ + char cfile_name[RW_CNAME_LEN]; + /* File name where lock created */ + ulint cline; /* Line where created */ + ulint magic_n; +}; + +#define RW_LOCK_MAGIC_N 22643 + +/* The structure for storing debug info of an rw-lock */ +struct rw_lock_debug_struct { + + os_thread_id_t thread_id; /* The thread id of the thread which + locked the rw-lock */ + ulint pass; /* Pass value given in the lock operation */ + ulint lock_type; /* Type of the lock: RW_LOCK_EX, + RW_LOCK_SHARED, RW_LOCK_WAIT_EX */ + char* file_name; /* File name where the lock was obtained */ + ulint line; /* Line where the rw-lock was locked */ + UT_LIST_NODE_T(rw_lock_debug_t) list; + /* Debug structs are linked in a two-way + list */ +}; + +#ifndef UNIV_NONINL +#include "sync0rw.ic" +#endif + +#endif |