2009-03-26 07:11:11 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
|
|
|
|
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
|
|
|
|
Copyright (c) 2008, Google Inc.
|
|
|
|
|
|
|
|
Portions of this file contain modifications contributed and copyrighted by
|
|
|
|
Google, Inc. Those modifications are gratefully acknowledged and are described
|
|
|
|
briefly in the InnoDB documentation. The contributions by Google are
|
|
|
|
incorporated with their permission, and subject to the conditions contained in
|
|
|
|
the file COPYING.Google.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
|
|
Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/**************************************************//**
|
|
|
|
@file include/sync0rw.h
|
2008-12-01 07:10:29 +01:00
|
|
|
The read-write lock (for threads, not for database transactions)
|
|
|
|
|
|
|
|
Created 9/11/1995 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#ifndef sync0rw_h
|
|
|
|
#define sync0rw_h
|
|
|
|
|
|
|
|
#include "univ.i"
|
2009-09-07 12:22:53 +02:00
|
|
|
#ifndef UNIV_HOTBACKUP
|
2008-12-01 07:10:29 +01:00
|
|
|
#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
|
2009-09-07 12:22:53 +02:00
|
|
|
#endif /* !UNIV_HOTBACKUP */
|
2008-12-01 07:10:29 +01:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
#ifndef UNIV_HOTBACKUP
|
2009-03-26 07:11:11 +01:00
|
|
|
/* We decrement lock_word by this amount for each x_lock. It is also the
|
|
|
|
start value for the lock_word, meaning that it limits the maximum number
|
|
|
|
of concurrent read locks before the rw_lock breaks. The current value of
|
|
|
|
0x00100000 allows 1,048,575 concurrent readers and 2047 recursive writers.*/
|
|
|
|
#define X_LOCK_DECR 0x00100000
|
|
|
|
|
2008-12-01 07:10:29 +01:00
|
|
|
typedef struct rw_lock_struct rw_lock_t;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
typedef struct rw_lock_debug_struct rw_lock_debug_t;
|
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
/* 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;
|
2009-09-07 12:22:53 +02:00
|
|
|
extern os_event_t rw_lock_debug_event; /*!< If deadlock detection does
|
2008-12-01 07:10:29 +01:00
|
|
|
not get immediately the mutex it
|
|
|
|
may wait for this event */
|
2009-09-07 12:22:53 +02:00
|
|
|
extern ibool rw_lock_debug_waiters; /*!< This is set to TRUE, if
|
2008-12-01 07:10:29 +01:00
|
|
|
there may be waiters for the event */
|
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of spin waits on rw-latches,
|
|
|
|
resulted during exclusive (write) locks */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_s_spin_wait_count;
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of spin loop rounds on rw-latches,
|
|
|
|
resulted during exclusive (write) locks */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_s_spin_round_count;
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of unlocks (that unlock shared locks),
|
|
|
|
set only when UNIV_SYNC_PERF_STAT is defined */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_s_exit_count;
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of OS waits on rw-latches,
|
|
|
|
resulted during shared (read) locks */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_s_os_wait_count;
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of spin waits on rw-latches,
|
|
|
|
resulted during shared (read) locks */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_x_spin_wait_count;
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of spin loop rounds on rw-latches,
|
|
|
|
resulted during shared (read) locks */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_x_spin_round_count;
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of OS waits on rw-latches,
|
|
|
|
resulted during exclusive (write) locks */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_x_os_wait_count;
|
2009-09-07 12:22:53 +02:00
|
|
|
/** number of unlocks (that unlock exclusive locks),
|
|
|
|
set only when UNIV_SYNC_PERF_STAT is defined */
|
2009-03-26 07:11:11 +01:00
|
|
|
extern ib_int64_t rw_x_exit_count;
|
2008-12-01 07:10:29 +01:00
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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. */
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
# ifdef UNIV_SYNC_DEBUG
|
|
|
|
# define rw_lock_create(L, level) \
|
|
|
|
rw_lock_create_func((L), (level), #L, __FILE__, __LINE__)
|
|
|
|
# else /* UNIV_SYNC_DEBUG */
|
|
|
|
# define rw_lock_create(L, level) \
|
|
|
|
rw_lock_create_func((L), #L, __FILE__, __LINE__)
|
|
|
|
# endif /* UNIV_SYNC_DEBUG */
|
|
|
|
#else /* UNIV_DEBUG */
|
|
|
|
# define rw_lock_create(L, level) \
|
|
|
|
rw_lock_create_func((L), __FILE__, __LINE__)
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_create_func(
|
|
|
|
/*================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in: pointer to memory */
|
2008-12-01 07:10:29 +01:00
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
# ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
ulint level, /*!< in: level */
|
2008-12-01 07:10:29 +01:00
|
|
|
# endif /* UNIV_SYNC_DEBUG */
|
2009-09-07 12:22:53 +02:00
|
|
|
const char* cmutex_name, /*!< in: mutex name */
|
2008-12-01 07:10:29 +01:00
|
|
|
#endif /* UNIV_DEBUG */
|
2009-09-07 12:22:53 +02:00
|
|
|
const char* cfile_name, /*!< in: file name where created */
|
|
|
|
ulint cline); /*!< in: file line where created */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_free(
|
|
|
|
/*=========*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in: rw-lock */
|
2008-12-01 07:10:29 +01:00
|
|
|
#ifdef UNIV_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Checks that the rw-lock has been initialized and that there are no
|
2009-09-07 12:22:53 +02:00
|
|
|
simultaneous shared and exclusive locks.
|
|
|
|
@return TRUE */
|
2008-12-01 07:10:29 +01:00
|
|
|
UNIV_INTERN
|
|
|
|
ibool
|
|
|
|
rw_lock_validate(
|
|
|
|
/*=============*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in: rw-lock */
|
2008-12-01 07:10:29 +01:00
|
|
|
#endif /* UNIV_DEBUG */
|
2009-09-07 12:22:53 +02:00
|
|
|
/**************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
NOTE! The following macros should be used in rw s-locking, not the
|
|
|
|
corresponding function. */
|
|
|
|
|
|
|
|
#define rw_lock_s_lock(M) rw_lock_s_lock_func(\
|
|
|
|
(M), 0, __FILE__, __LINE__)
|
2009-09-07 12:22:53 +02:00
|
|
|
/**************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
NOTE! The following macros should be used in rw s-locking, not the
|
|
|
|
corresponding function. */
|
|
|
|
|
|
|
|
#define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(\
|
|
|
|
(M), (P), __FILE__, __LINE__)
|
2009-09-07 12:22:53 +02:00
|
|
|
/**************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
NOTE! The following macros should be used in rw s-locking, not the
|
|
|
|
corresponding function. */
|
|
|
|
|
2009-03-26 07:11:11 +01:00
|
|
|
#define rw_lock_s_lock_nowait(M, F, L) rw_lock_s_lock_low(\
|
|
|
|
(M), 0, (F), (L))
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2009-03-26 07:11:11 +01:00
|
|
|
Low-level function which tries to lock an rw-lock in s-mode. Performs no
|
2009-09-07 12:22:53 +02:00
|
|
|
spinning.
|
|
|
|
@return TRUE if success */
|
2009-03-26 07:11:11 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
rw_lock_s_lock_low(
|
|
|
|
/*===============*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in: pointer to rw-lock */
|
2009-03-26 07:11:11 +01:00
|
|
|
ulint pass __attribute__((unused)),
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< in: pass value; != 0, if the lock will be
|
2009-03-26 07:11:11 +01:00
|
|
|
passed to another thread to unlock */
|
2009-09-07 12:22:53 +02:00
|
|
|
const char* file_name, /*!< in: file name where lock requested */
|
|
|
|
ulint line); /*!< in: line where requested */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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(
|
|
|
|
/*================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in: pointer to rw-lock */
|
|
|
|
ulint pass, /*!< in: pass value; != 0, if the lock will
|
2008-12-01 07:10:29 +01:00
|
|
|
be passed to another thread to unlock */
|
2009-09-07 12:22:53 +02:00
|
|
|
const char* file_name,/*!< in: file name where lock requested */
|
|
|
|
ulint line); /*!< in: line where requested */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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
|
2009-09-07 12:22:53 +02:00
|
|
|
obtained immediately.
|
|
|
|
@return TRUE if success */
|
2008-12-01 07:10:29 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
rw_lock_x_lock_func_nowait(
|
|
|
|
/*=======================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in: pointer to rw-lock */
|
|
|
|
const char* file_name,/*!< in: file name where lock requested */
|
|
|
|
ulint line); /*!< in: line where requested */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Releases a shared mode lock. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
rw_lock_s_unlock_func(
|
|
|
|
/*==================*/
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
ulint pass, /*!< in: pass value; != 0, if the lock may have
|
2008-12-01 07:10:29 +01:00
|
|
|
been passed to another thread to unlock */
|
|
|
|
#endif
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in/out: rw-lock */
|
2008-12-01 07:10:29 +01:00
|
|
|
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(P, L)
|
2008-12-01 07:10:29 +01:00
|
|
|
#else
|
2009-09-07 12:22:53 +02:00
|
|
|
# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L)
|
2008-12-01 07:10:29 +01:00
|
|
|
#endif
|
2009-09-07 12:22:53 +02:00
|
|
|
/*******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Releases a shared mode lock. */
|
2009-09-07 12:22:53 +02:00
|
|
|
#define rw_lock_s_unlock(L) rw_lock_s_unlock_gen(L, 0)
|
2008-12-01 07:10:29 +01:00
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/**************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
NOTE! The following macro should be used in rw x-locking, not the
|
|
|
|
corresponding function. */
|
|
|
|
|
|
|
|
#define rw_lock_x_lock(M) rw_lock_x_lock_func(\
|
|
|
|
(M), 0, __FILE__, __LINE__)
|
2009-09-07 12:22:53 +02:00
|
|
|
/**************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
NOTE! The following macro should be used in rw x-locking, not the
|
|
|
|
corresponding function. */
|
|
|
|
|
|
|
|
#define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(\
|
|
|
|
(M), (P), __FILE__, __LINE__)
|
2009-09-07 12:22:53 +02:00
|
|
|
/**************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
NOTE! The following macros should be used in rw x-locking, not the
|
|
|
|
corresponding function. */
|
|
|
|
|
|
|
|
#define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(\
|
|
|
|
(M), __FILE__, __LINE__)
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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! */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_x_lock_func(
|
|
|
|
/*================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in: pointer to rw-lock */
|
|
|
|
ulint pass, /*!< in: pass value; != 0, if the lock will
|
2008-12-01 07:10:29 +01:00
|
|
|
be passed to another thread to unlock */
|
2009-09-07 12:22:53 +02:00
|
|
|
const char* file_name,/*!< in: file name where lock requested */
|
|
|
|
ulint line); /*!< in: line where requested */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Releases an exclusive mode lock. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
rw_lock_x_unlock_func(
|
|
|
|
/*==================*/
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
ulint pass, /*!< in: pass value; != 0, if the lock may have
|
2008-12-01 07:10:29 +01:00
|
|
|
been passed to another thread to unlock */
|
|
|
|
#endif
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in/out: rw-lock */
|
2008-12-01 07:10:29 +01:00
|
|
|
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(P, L)
|
2008-12-01 07:10:29 +01:00
|
|
|
#else
|
2009-09-07 12:22:53 +02:00
|
|
|
# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L)
|
2008-12-01 07:10:29 +01:00
|
|
|
#endif
|
2009-09-07 12:22:53 +02:00
|
|
|
/*******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Releases an exclusive mode lock. */
|
2009-09-07 12:22:53 +02:00
|
|
|
#define rw_lock_x_unlock(L) rw_lock_x_unlock_gen(L, 0)
|
2008-12-01 07:10:29 +01:00
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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(
|
|
|
|
/*==================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in/out: rw-lock */
|
|
|
|
const char* file_name, /*!< in: file name where requested */
|
|
|
|
ulint line); /*!< in: line where lock requested */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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(
|
|
|
|
/*==================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in/out: rw-lock */
|
|
|
|
const char* file_name, /*!< in: file name where requested */
|
|
|
|
ulint line); /*!< in: line where lock requested */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_x_lock_move_ownership(
|
|
|
|
/*==========================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in: lock which was x-locked in the
|
2008-12-01 07:10:29 +01:00
|
|
|
buffer read */
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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(
|
|
|
|
/*====================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in/out: rw-lock */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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(
|
|
|
|
/*====================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in/out: rw-lock */
|
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Returns the value of writer_count for the lock. Does not reserve the lock
|
2009-09-07 12:22:53 +02:00
|
|
|
mutex, so the caller must be sure it is not changed during the call.
|
|
|
|
@return value of writer_count */
|
2008-12-01 07:10:29 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
|
|
|
rw_lock_get_x_lock_count(
|
|
|
|
/*=====================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
const rw_lock_t* lock); /*!< in: rw-lock */
|
|
|
|
/********************************************************************//**
|
|
|
|
Check if there are threads waiting for the rw-lock.
|
|
|
|
@return 1 if waiters, 0 otherwise */
|
2008-12-01 07:10:29 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
2009-04-27 06:54:14 +02:00
|
|
|
rw_lock_get_waiters(
|
2008-12-01 07:10:29 +01:00
|
|
|
/*================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
const rw_lock_t* lock); /*!< in: rw-lock */
|
|
|
|
/******************************************************************//**
|
|
|
|
Returns the write-status of the lock - this function made more sense
|
|
|
|
with the old rw_lock implementation.
|
|
|
|
@return RW_LOCK_NOT_LOCKED, RW_LOCK_EX, RW_LOCK_WAIT_EX */
|
2008-12-01 07:10:29 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
|
|
|
rw_lock_get_writer(
|
|
|
|
/*===============*/
|
2009-09-07 12:22:53 +02:00
|
|
|
const rw_lock_t* lock); /*!< in: rw-lock */
|
|
|
|
/******************************************************************//**
|
|
|
|
Returns the number of readers.
|
|
|
|
@return number of readers */
|
2008-12-01 07:10:29 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
|
|
|
rw_lock_get_reader_count(
|
|
|
|
/*=====================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
const rw_lock_t* lock); /*!< in: rw-lock */
|
|
|
|
/******************************************************************//**
|
2009-03-26 07:11:11 +01:00
|
|
|
Decrements lock_word the specified amount if it is greater than 0.
|
2009-09-07 12:22:53 +02:00
|
|
|
This is used by both s_lock and x_lock operations.
|
|
|
|
@return TRUE if decr occurs */
|
2009-03-26 07:11:11 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
ibool
|
|
|
|
rw_lock_lock_word_decr(
|
|
|
|
/*===================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in/out: rw-lock */
|
|
|
|
ulint amount); /*!< in: amount to decrement */
|
|
|
|
/******************************************************************//**
|
|
|
|
Increments lock_word the specified amount and returns new value.
|
|
|
|
@return lock->lock_word after increment */
|
2009-03-26 07:11:11 +01:00
|
|
|
UNIV_INLINE
|
|
|
|
lint
|
|
|
|
rw_lock_lock_word_incr(
|
|
|
|
/*===================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in/out: rw-lock */
|
|
|
|
ulint amount); /*!< in: amount to increment */
|
|
|
|
/******************************************************************//**
|
2009-03-26 07:11:11 +01:00
|
|
|
This function sets the lock->writer_thread and lock->recursive fields.
|
|
|
|
For platforms where we are using atomic builtins instead of lock->mutex
|
|
|
|
it sets the lock->writer_thread field using atomics to ensure memory
|
|
|
|
ordering. Note that it is assumed that the caller of this function
|
|
|
|
effectively owns the lock i.e.: nobody else is allowed to modify
|
|
|
|
lock->writer_thread at this point in time.
|
|
|
|
The protocol is that lock->writer_thread MUST be updated BEFORE the
|
|
|
|
lock->recursive flag is set. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
rw_lock_set_writer_id_and_recursion_flag(
|
|
|
|
/*=====================================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in/out: lock to work on */
|
|
|
|
ibool recursive); /*!< in: TRUE if recursion
|
2009-03-26 07:11:11 +01:00
|
|
|
allowed */
|
2008-12-01 07:10:29 +01:00
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Checks if the thread has locked the rw-lock in the specified mode, with
|
|
|
|
the pass value == 0. */
|
|
|
|
UNIV_INTERN
|
|
|
|
ibool
|
|
|
|
rw_lock_own(
|
|
|
|
/*========*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in: rw-lock */
|
|
|
|
ulint lock_type); /*!< in: lock type: RW_LOCK_SHARED,
|
2008-12-01 07:10:29 +01:00
|
|
|
RW_LOCK_EX */
|
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Checks if somebody has locked the rw-lock in the specified mode. */
|
|
|
|
UNIV_INTERN
|
|
|
|
ibool
|
|
|
|
rw_lock_is_locked(
|
|
|
|
/*==============*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock, /*!< in: rw-lock */
|
|
|
|
ulint lock_type); /*!< in: lock type: RW_LOCK_SHARED,
|
2008-12-01 07:10:29 +01:00
|
|
|
RW_LOCK_EX */
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
/***************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Prints debug info of an rw-lock. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_print(
|
|
|
|
/*==========*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_t* lock); /*!< in: rw-lock */
|
|
|
|
/***************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Prints debug info of currently locked rw-locks. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_list_print_info(
|
|
|
|
/*====================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
FILE* file); /*!< in: file where to print */
|
|
|
|
/***************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Returns the number of currently locked rw-locks.
|
2009-09-07 12:22:53 +02:00
|
|
|
Works only in the debug version.
|
|
|
|
@return number of locked rw-locks */
|
2008-12-01 07:10:29 +01:00
|
|
|
UNIV_INTERN
|
|
|
|
ulint
|
|
|
|
rw_lock_n_locked(void);
|
|
|
|
/*==================*/
|
|
|
|
|
|
|
|
/*#####################################################################*/
|
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
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. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_debug_mutex_enter(void);
|
|
|
|
/*==========================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
/******************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Releases the debug mutex. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_debug_mutex_exit(void);
|
|
|
|
/*==========================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
/*********************************************************************//**
|
2008-12-01 07:10:29 +01:00
|
|
|
Prints info of a debug struct. */
|
|
|
|
UNIV_INTERN
|
|
|
|
void
|
|
|
|
rw_lock_debug_print(
|
|
|
|
/*================*/
|
2009-09-07 12:22:53 +02:00
|
|
|
rw_lock_debug_t* info); /*!< in: debug struct */
|
2008-12-01 07:10:29 +01:00
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
|
|
|
|
/* NOTE! The structure appears here only for the compiler to know its size.
|
2009-09-07 12:22:53 +02:00
|
|
|
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 x-lock by decrementing lock_word: no
|
|
|
|
new readers will be let in while the thread waits for readers to
|
|
|
|
exit. */
|
2008-12-01 07:10:29 +01:00
|
|
|
struct rw_lock_struct {
|
2009-03-26 07:11:11 +01:00
|
|
|
volatile lint lock_word;
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< Holds the state of the lock. */
|
|
|
|
volatile ulint waiters;/*!< 1: there are waiters */
|
|
|
|
volatile ibool recursive;/*!< Default value FALSE which means the lock
|
2009-03-26 07:11:11 +01:00
|
|
|
is non-recursive. The value is typically set
|
|
|
|
to TRUE making normal rw_locks recursive. In
|
|
|
|
case of asynchronous IO, when a non-zero
|
|
|
|
value of 'pass' is passed then we keep the
|
|
|
|
lock non-recursive.
|
|
|
|
This flag also tells us about the state of
|
|
|
|
writer_thread field. If this flag is set
|
|
|
|
then writer_thread MUST contain the thread
|
|
|
|
id of the current x-holder or wait-x thread.
|
|
|
|
This flag must be reset in x_unlock
|
|
|
|
functions before incrementing the lock_word */
|
|
|
|
volatile os_thread_id_t writer_thread;
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< Thread id of writer thread. Is only
|
2009-03-26 07:11:11 +01:00
|
|
|
guaranteed to have sane and non-stale
|
|
|
|
value iff recursive flag is set. */
|
2009-09-07 12:22:53 +02:00
|
|
|
os_event_t event; /*!< Used by sync0arr.c for thread queueing */
|
2009-03-26 07:11:11 +01:00
|
|
|
os_event_t wait_ex_event;
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< Event for next-writer to wait on. A thread
|
2009-03-26 07:11:11 +01:00
|
|
|
must decrement lock_word before waiting. */
|
|
|
|
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
|
2009-09-07 12:22:53 +02:00
|
|
|
mutex_t mutex; /*!< The mutex protecting rw_lock_struct */
|
2009-03-26 07:11:11 +01:00
|
|
|
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
|
|
|
|
|
2008-12-01 07:10:29 +01:00
|
|
|
UT_LIST_NODE_T(rw_lock_t) list;
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< All allocated rw locks are put into a
|
2008-12-01 07:10:29 +01:00
|
|
|
list */
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
UT_LIST_BASE_NODE_T(rw_lock_debug_t) debug_list;
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< In the debug version: pointer to the debug
|
2008-12-01 07:10:29 +01:00
|
|
|
info list of the lock */
|
2009-09-07 12:22:53 +02:00
|
|
|
ulint level; /*!< Level in the global latching order. */
|
2008-12-01 07:10:29 +01:00
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
2009-09-07 12:22:53 +02:00
|
|
|
ulint count_os_wait; /*!< Count of os_waits. May not be accurate */
|
|
|
|
const char* cfile_name;/*!< File name where lock created */
|
2009-03-26 07:11:11 +01:00
|
|
|
/* last s-lock file/line is not guaranteed to be correct */
|
2009-09-07 12:22:53 +02:00
|
|
|
const char* last_s_file_name;/*!< File name where last s-locked */
|
|
|
|
const char* last_x_file_name;/*!< File name where last x-locked */
|
2009-04-27 06:54:14 +02:00
|
|
|
ibool writer_is_wait_ex;
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< This is TRUE if the writer field is
|
2008-12-01 07:10:29 +01:00
|
|
|
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 */
|
2009-09-07 12:22:53 +02:00
|
|
|
unsigned cline:14; /*!< Line where created */
|
|
|
|
unsigned last_s_line:14; /*!< Line number where last time s-locked */
|
|
|
|
unsigned last_x_line:14; /*!< Line number where last time x-locked */
|
|
|
|
ulint magic_n; /*!< RW_LOCK_MAGIC_N */
|
2008-12-01 07:10:29 +01:00
|
|
|
};
|
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
/** Value of rw_lock_struct::magic_n */
|
2008-12-01 07:10:29 +01:00
|
|
|
#define RW_LOCK_MAGIC_N 22643
|
|
|
|
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2009-09-07 12:22:53 +02:00
|
|
|
/** The structure for storing debug info of an rw-lock */
|
2008-12-01 07:10:29 +01:00
|
|
|
struct rw_lock_debug_struct {
|
|
|
|
|
2009-09-07 12:22:53 +02:00
|
|
|
os_thread_id_t thread_id; /*!< The thread id of the thread which
|
2008-12-01 07:10:29 +01:00
|
|
|
locked the rw-lock */
|
2009-09-07 12:22:53 +02:00
|
|
|
ulint pass; /*!< Pass value given in the lock operation */
|
|
|
|
ulint lock_type; /*!< Type of the lock: RW_LOCK_EX,
|
2008-12-01 07:10:29 +01:00
|
|
|
RW_LOCK_SHARED, RW_LOCK_WAIT_EX */
|
2009-09-07 12:22:53 +02:00
|
|
|
const char* file_name;/*!< File name where the lock was obtained */
|
|
|
|
ulint line; /*!< Line where the rw-lock was locked */
|
2008-12-01 07:10:29 +01:00
|
|
|
UT_LIST_NODE_T(rw_lock_debug_t) list;
|
2009-09-07 12:22:53 +02:00
|
|
|
/*!< Debug structs are linked in a two-way
|
2008-12-01 07:10:29 +01:00
|
|
|
list */
|
|
|
|
};
|
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
|
|
|
|
#ifndef UNIV_NONINL
|
|
|
|
#include "sync0rw.ic"
|
|
|
|
#endif
|
2009-09-07 12:22:53 +02:00
|
|
|
#endif /* !UNIV_HOTBACKUP */
|
2008-12-01 07:10:29 +01:00
|
|
|
|
|
|
|
#endif
|