mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
a3edc742b9
Merge InnoDB-3.23.52d innobase/btr/btr0sea.c: Merge InnoDB-3.23.52d innobase/buf/buf0buf.c: Merge InnoDB-3.23.52d innobase/buf/buf0lru.c: Merge InnoDB-3.23.52d innobase/include/buf0buf.h: Merge InnoDB-3.23.52d innobase/include/ha0ha.h: Merge InnoDB-3.23.52d innobase/include/log0log.h: Merge InnoDB-3.23.52d innobase/include/os0file.h: Merge InnoDB-3.23.52d innobase/include/os0thread.h: Merge InnoDB-3.23.52d innobase/include/ha0ha.ic: Merge InnoDB-3.23.52d innobase/include/os0sync.ic: Merge InnoDB-3.23.52d innobase/include/srv0start.h: Merge InnoDB-3.23.52d innobase/include/sync0rw.ic: Merge InnoDB-3.23.52d innobase/include/sync0sync.ic: Merge InnoDB-3.23.52d innobase/include/ut0dbg.h: Merge InnoDB-3.23.52d innobase/include/univ.i: Merge InnoDB-3.23.52d innobase/lock/lock0lock.c: Merge InnoDB-3.23.52d innobase/log/log0log.c: Merge InnoDB-3.23.52d innobase/mem/mem0pool.c: Merge InnoDB-3.23.52d innobase/os/os0file.c: Merge InnoDB-3.23.52d innobase/os/os0thread.c: Merge InnoDB-3.23.52d innobase/srv/srv0srv.c: Merge InnoDB-3.23.52d innobase/srv/srv0start.c: Merge InnoDB-3.23.52d innobase/sync/sync0arr.c: Merge InnoDB-3.23.52d innobase/sync/sync0rw.c: Merge InnoDB-3.23.52d innobase/sync/sync0sync.c: Merge InnoDB-3.23.52d innobase/thr/thr0loc.c: Merge InnoDB-3.23.52d innobase/trx/trx0trx.c: Merge InnoDB-3.23.52d innobase/configure.in: Merge InnoDB-3.23.52d sql/ha_innobase.cc: Merge InnoDB-3.23.52d
498 lines
13 KiB
Text
498 lines
13 KiB
Text
/******************************************************
|
|
The read-write lock (for threads)
|
|
|
|
(c) 1995 Innobase Oy
|
|
|
|
Created 9/11/1995 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
/**********************************************************************
|
|
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. */
|
|
|
|
void
|
|
rw_lock_s_lock_spin(
|
|
/*================*/
|
|
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 */
|
|
char* file_name,/* in: file name where lock requested */
|
|
ulint line); /* in: line where requested */
|
|
/**********************************************************************
|
|
Inserts the debug information for an rw-lock. */
|
|
|
|
void
|
|
rw_lock_add_debug_info(
|
|
/*===================*/
|
|
rw_lock_t* lock, /* in: rw-lock */
|
|
ulint pass, /* in: pass value */
|
|
ulint lock_type, /* in: lock type */
|
|
char* file_name, /* in: file where requested */
|
|
ulint line); /* in: line where requested */
|
|
/**********************************************************************
|
|
Removes a debug information struct for an rw-lock. */
|
|
|
|
void
|
|
rw_lock_remove_debug_info(
|
|
/*======================*/
|
|
rw_lock_t* lock, /* in: rw-lock */
|
|
ulint pass, /* in: pass value */
|
|
ulint lock_type); /* in: lock type */
|
|
|
|
|
|
/************************************************************************
|
|
Accessor functions for rw lock. */
|
|
UNIV_INLINE
|
|
ulint
|
|
rw_lock_get_waiters(
|
|
/*================*/
|
|
rw_lock_t* lock)
|
|
{
|
|
return(lock->waiters);
|
|
}
|
|
UNIV_INLINE
|
|
void
|
|
rw_lock_set_waiters(
|
|
/*================*/
|
|
rw_lock_t* lock,
|
|
ulint flag)
|
|
{
|
|
lock->waiters = flag;
|
|
}
|
|
UNIV_INLINE
|
|
ulint
|
|
rw_lock_get_writer(
|
|
/*===============*/
|
|
rw_lock_t* lock)
|
|
{
|
|
return(lock->writer);
|
|
}
|
|
UNIV_INLINE
|
|
void
|
|
rw_lock_set_writer(
|
|
/*===============*/
|
|
rw_lock_t* lock,
|
|
ulint flag)
|
|
{
|
|
lock->writer = flag;
|
|
}
|
|
UNIV_INLINE
|
|
ulint
|
|
rw_lock_get_reader_count(
|
|
/*=====================*/
|
|
rw_lock_t* lock)
|
|
{
|
|
return(lock->reader_count);
|
|
}
|
|
UNIV_INLINE
|
|
void
|
|
rw_lock_set_reader_count(
|
|
/*=====================*/
|
|
rw_lock_t* lock,
|
|
ulint count)
|
|
{
|
|
lock->reader_count = count;
|
|
}
|
|
UNIV_INLINE
|
|
mutex_t*
|
|
rw_lock_get_mutex(
|
|
/*==============*/
|
|
rw_lock_t* lock)
|
|
{
|
|
return(&(lock->mutex));
|
|
}
|
|
|
|
/**********************************************************************
|
|
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 */
|
|
{
|
|
return(lock->writer_count);
|
|
}
|
|
|
|
/**********************************************************************
|
|
Low-level function which tries to lock an rw-lock in s-mode. Performs no
|
|
spinning. */
|
|
UNIV_INLINE
|
|
ibool
|
|
rw_lock_s_lock_low(
|
|
/*===============*/
|
|
/* out: TRUE if success */
|
|
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 */
|
|
char* file_name, /* in: file name where lock requested */
|
|
ulint line) /* in: line where requested */
|
|
{
|
|
ut_ad(mutex_own(rw_lock_get_mutex(lock)));
|
|
|
|
/* Check if the writer field is free */
|
|
|
|
if (lock->writer == RW_LOCK_NOT_LOCKED) {
|
|
/* Set the shared lock by incrementing the reader count */
|
|
lock->reader_count++;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name,
|
|
line);
|
|
#endif
|
|
|
|
lock->last_s_file_name = file_name;
|
|
lock->last_s_line = line;
|
|
|
|
return(TRUE); /* locking succeeded */
|
|
}
|
|
|
|
return(FALSE); /* locking did not succeed */
|
|
}
|
|
|
|
/**********************************************************************
|
|
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 */
|
|
char* file_name,/* in: file name where lock requested */
|
|
ulint line) /* in: line where requested */
|
|
{
|
|
ut_ad(lock->writer == RW_LOCK_NOT_LOCKED);
|
|
ut_ad(rw_lock_get_reader_count(lock) == 0);
|
|
|
|
/* Set the shared lock by incrementing the reader count */
|
|
lock->reader_count++;
|
|
|
|
lock->last_s_file_name = file_name;
|
|
lock->last_s_line = line;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);
|
|
#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 */
|
|
char* file_name, /* in: file name where lock requested */
|
|
ulint line) /* in: line where requested */
|
|
{
|
|
ut_ad(rw_lock_validate(lock));
|
|
ut_ad(rw_lock_get_reader_count(lock) == 0);
|
|
ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
|
|
|
|
rw_lock_set_writer(lock, RW_LOCK_EX);
|
|
lock->writer_thread = os_thread_get_curr_id();
|
|
lock->writer_count++;
|
|
lock->pass = 0;
|
|
|
|
lock->last_x_file_name = file_name;
|
|
lock->last_x_line = line;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
|
|
#endif
|
|
}
|
|
|
|
/**********************************************************************
|
|
NOTE! Use the corresponding macro, not directly this function! 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 */
|
|
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 */
|
|
{
|
|
/* NOTE: As we do not know the thread ids for threads which have
|
|
s-locked a latch, and s-lockers will be served only after waiting
|
|
x-lock requests have been fulfilled, then if this thread already
|
|
owns an s-lock here, it may end up in a deadlock with another thread
|
|
which requests an x-lock here. Therefore, we will forbid recursive
|
|
s-locking of a latch: the following assert will warn the programmer
|
|
of the possibility of a tjis kind of deadlock. If we want to implement
|
|
safe recursive s-locking, we should keep in a list the thread ids of
|
|
the threads which have s-locked a latch. This would use some CPU
|
|
time. */
|
|
|
|
ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
|
|
|
|
mutex_enter(rw_lock_get_mutex(lock));
|
|
|
|
if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
|
|
mutex_exit(rw_lock_get_mutex(lock));
|
|
|
|
return; /* Success */
|
|
} else {
|
|
/* Did not succeed, try spin wait */
|
|
mutex_exit(rw_lock_get_mutex(lock));
|
|
|
|
rw_lock_s_lock_spin(lock, pass, file_name, line);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
NOTE! Use the corresponding macro, not directly this function! 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 */
|
|
char* file_name,/* in: file name where lock requested */
|
|
ulint line) /* in: line where requested */
|
|
{
|
|
ibool success = FALSE;
|
|
|
|
mutex_enter(rw_lock_get_mutex(lock));
|
|
|
|
if (lock->writer == RW_LOCK_NOT_LOCKED) {
|
|
/* Set the shared lock by incrementing the reader count */
|
|
lock->reader_count++;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name,
|
|
line);
|
|
#endif
|
|
|
|
lock->last_s_file_name = file_name;
|
|
lock->last_s_line = line;
|
|
|
|
success = TRUE;
|
|
}
|
|
|
|
mutex_exit(rw_lock_get_mutex(lock));
|
|
|
|
return(success);
|
|
}
|
|
|
|
/**********************************************************************
|
|
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 */
|
|
char* file_name, /* in: file name where lock requested */
|
|
ulint line) /* in: line where requested */
|
|
{
|
|
ibool success = FALSE;
|
|
|
|
mutex_enter(rw_lock_get_mutex(lock));
|
|
|
|
if ((rw_lock_get_reader_count(lock) == 0)
|
|
&& ((rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED)
|
|
|| ((rw_lock_get_writer(lock) == RW_LOCK_EX)
|
|
&& (lock->pass == 0)
|
|
&& os_thread_eq(lock->writer_thread,
|
|
os_thread_get_curr_id())))) {
|
|
|
|
rw_lock_set_writer(lock, RW_LOCK_EX);
|
|
lock->writer_thread = os_thread_get_curr_id();
|
|
lock->writer_count++;
|
|
lock->pass = 0;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
|
|
#endif
|
|
|
|
lock->last_x_file_name = file_name;
|
|
lock->last_x_line = line;
|
|
|
|
success = TRUE;
|
|
}
|
|
|
|
mutex_exit(rw_lock_get_mutex(lock));
|
|
|
|
ut_ad(rw_lock_validate(lock));
|
|
|
|
return(success);
|
|
}
|
|
|
|
/**********************************************************************
|
|
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
|
|
)
|
|
{
|
|
mutex_t* mutex = &(lock->mutex);
|
|
ibool sg = FALSE;
|
|
|
|
/* Acquire the mutex protecting the rw-lock fields */
|
|
mutex_enter(mutex);
|
|
|
|
/* Reset the shared lock by decrementing the reader count */
|
|
|
|
ut_a(lock->reader_count > 0);
|
|
lock->reader_count--;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
|
|
#endif
|
|
|
|
/* If there may be waiters and this was the last s-lock,
|
|
signal the object */
|
|
|
|
if (lock->waiters && (lock->reader_count == 0)) {
|
|
sg = TRUE;
|
|
|
|
rw_lock_set_waiters(lock, 0);
|
|
}
|
|
|
|
mutex_exit(mutex);
|
|
|
|
if (sg == TRUE) {
|
|
sync_array_signal_object(sync_primary_wait_array, lock);
|
|
}
|
|
|
|
ut_ad(rw_lock_validate(lock));
|
|
|
|
#ifdef UNIV_SYNC_PERF_STAT
|
|
rw_s_exit_count++;
|
|
#endif
|
|
}
|
|
|
|
/**********************************************************************
|
|
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 */
|
|
{
|
|
/* Reset the shared lock by decrementing the reader count */
|
|
|
|
ut_ad(lock->reader_count > 0);
|
|
|
|
lock->reader_count--;
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
|
|
#endif
|
|
|
|
ut_ad(!lock->waiters);
|
|
ut_ad(rw_lock_validate(lock));
|
|
#ifdef UNIV_SYNC_PERF_STAT
|
|
rw_s_exit_count++;
|
|
#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
|
|
)
|
|
{
|
|
ibool sg = FALSE;
|
|
|
|
/* Acquire the mutex protecting the rw-lock fields */
|
|
mutex_enter(&(lock->mutex));
|
|
|
|
/* Reset the exclusive lock if this thread no longer has an x-mode
|
|
lock */
|
|
|
|
ut_ad(lock->writer_count > 0);
|
|
|
|
lock->writer_count--;
|
|
|
|
if (lock->writer_count == 0) {
|
|
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
|
|
}
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
|
|
#endif
|
|
|
|
/* If there may be waiters, signal the lock */
|
|
if (lock->waiters && (lock->writer_count == 0)) {
|
|
|
|
sg = TRUE;
|
|
rw_lock_set_waiters(lock, 0);
|
|
}
|
|
|
|
mutex_exit(&(lock->mutex));
|
|
|
|
if (sg == TRUE) {
|
|
sync_array_signal_object(sync_primary_wait_array, lock);
|
|
}
|
|
|
|
ut_ad(rw_lock_validate(lock));
|
|
|
|
#ifdef UNIV_SYNC_PERF_STAT
|
|
rw_x_exit_count++;
|
|
#endif
|
|
}
|
|
|
|
/**********************************************************************
|
|
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 */
|
|
{
|
|
/* Reset the exclusive lock if this thread no longer has an x-mode
|
|
lock */
|
|
|
|
ut_ad(lock->writer_count > 0);
|
|
|
|
lock->writer_count--;
|
|
|
|
if (lock->writer_count == 0) {
|
|
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
|
|
}
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
|
|
#endif
|
|
|
|
ut_ad(!lock->waiters);
|
|
ut_ad(rw_lock_validate(lock));
|
|
|
|
#ifdef UNIV_SYNC_PERF_STAT
|
|
rw_x_exit_count++;
|
|
#endif
|
|
}
|