1
/*****************************************************************************
3
Copyright (c) 1995, 2009, 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., 59 Temple
22
Place, Suite 330, Boston, MA 02111-1307 USA
24
*****************************************************************************/
26
/**************************************************//**
27
@file include/sync0sync.ic
28
Mutex, the basic synchronization primitive
30
Created 9/5/1995 Heikki Tuuri
31
*******************************************************/
33
/******************************************************************//**
34
Sets the waiters field in a mutex. */
39
mutex_t* mutex, /*!< in: mutex */
40
ulint n); /*!< in: value to set */
41
/******************************************************************//**
42
Reserves a mutex for the current thread. If the mutex is reserved, the
43
function spins a preset time (controlled by SYNC_SPIN_ROUNDS) waiting
44
for the mutex before suspending the thread. */
49
mutex_t* mutex, /*!< in: pointer to mutex */
50
const char* file_name, /*!< in: file name where mutex
52
ulint line); /*!< in: line where requested */
53
#ifdef UNIV_SYNC_DEBUG
54
/******************************************************************//**
55
Sets the debug information for a reserved mutex. */
60
mutex_t* mutex, /*!< in: mutex */
61
const char* file_name, /*!< in: file where requested */
62
ulint line); /*!< in: line where requested */
63
#endif /* UNIV_SYNC_DEBUG */
64
/******************************************************************//**
65
Releases the threads waiting in the primary wait array for this mutex. */
70
mutex_t* mutex); /*!< in: mutex */
72
/******************************************************************//**
73
Performs an atomic test-and-set instruction to the lock_word field of a
75
@return the previous value of lock_word: 0 or 1 */
80
mutex_t* mutex) /*!< in: mutex */
82
#if defined(HAVE_ATOMIC_BUILTINS)
83
return(os_atomic_test_and_set_byte(&mutex->lock_word, 1));
87
ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex));
90
/* We check that os_fast_mutex_trylock does not leak
91
and allow race conditions */
92
ut_a(mutex->lock_word == 0);
101
/******************************************************************//**
102
Performs a reset instruction to the lock_word field of a mutex. This
103
instruction also serializes memory operations to the program order. */
106
mutex_reset_lock_word(
107
/*==================*/
108
mutex_t* mutex) /*!< in: mutex */
110
#if defined(HAVE_ATOMIC_BUILTINS)
111
/* In theory __sync_lock_release should be used to release the lock.
112
Unfortunately, it does not work properly alone. The workaround is
113
that more conservative __sync_lock_test_and_set is used instead. */
114
os_atomic_test_and_set_byte(&mutex->lock_word, 0);
116
mutex->lock_word = 0;
118
os_fast_mutex_unlock(&(mutex->os_fast_mutex));
122
/******************************************************************//**
123
Gets the value of the lock word. */
128
const mutex_t* mutex) /*!< in: mutex */
132
return(mutex->lock_word);
135
/******************************************************************//**
136
Gets the waiters field in a mutex.
137
@return value to set */
142
const mutex_t* mutex) /*!< in: mutex */
144
const volatile ulint* ptr; /*!< declared volatile to ensure that
145
the value is read from memory */
148
ptr = &(mutex->waiters);
150
return(*ptr); /* Here we assume that the read of a single
151
word from memory is atomic */
154
/******************************************************************//**
155
Unlocks a mutex owned by the current thread. */
160
mutex_t* mutex) /*!< in: pointer to mutex */
162
ut_ad(mutex_own(mutex));
164
ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
166
#ifdef UNIV_SYNC_DEBUG
167
sync_thread_reset_level(mutex);
169
mutex_reset_lock_word(mutex);
171
/* A problem: we assume that mutex_reset_lock word
172
is a memory barrier, that is when we read the waiters
173
field next, the read must be serialized in memory
174
after the reset. A speculative processor might
175
perform the read first, which could leave a waiting
176
thread hanging indefinitely.
178
Our current solution call every second
179
sync_arr_wake_threads_if_sema_free()
180
to wake up possible hanging threads if
181
they are missed in mutex_signal_object. */
183
if (mutex_get_waiters(mutex) != 0) {
185
mutex_signal_object(mutex);
188
#ifdef UNIV_SYNC_PERF_STAT
193
/******************************************************************//**
194
Locks a mutex for the current thread. If the mutex is reserved, the function
195
spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the mutex
196
before suspending the thread. */
201
mutex_t* mutex, /*!< in: pointer to mutex */
202
const char* file_name, /*!< in: file name where locked */
203
ulint line) /*!< in: line where locked */
205
ut_ad(mutex_validate(mutex));
206
ut_ad(!mutex_own(mutex));
208
/* Note that we do not peek at the value of lock_word before trying
209
the atomic test_and_set; we could peek, and possibly save time. */
211
ut_d(mutex->count_using++);
213
if (!mutex_test_and_set(mutex)) {
214
ut_d(mutex->thread_id = os_thread_get_curr_id());
215
#ifdef UNIV_SYNC_DEBUG
216
mutex_set_debug_info(mutex, file_name, line);
218
return; /* Succeeded! */
221
mutex_spin_wait(mutex, file_name, line);