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., 51 Franklin
22
St, Fifth Floor, Boston, MA 02110-1301 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
NOTE! Use the corresponding macro mutex_exit(), not directly this function!
156
Unlocks a mutex owned by the current thread. */
161
mutex_t* mutex) /*!< in: pointer to mutex */
163
ut_ad(mutex_own(mutex));
165
ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
167
#ifdef UNIV_SYNC_DEBUG
168
sync_thread_reset_level(mutex);
170
mutex_reset_lock_word(mutex);
172
/* A problem: we assume that mutex_reset_lock word
173
is a memory barrier, that is when we read the waiters
174
field next, the read must be serialized in memory
175
after the reset. A speculative processor might
176
perform the read first, which could leave a waiting
177
thread hanging indefinitely.
179
Our current solution call every second
180
sync_arr_wake_threads_if_sema_free()
181
to wake up possible hanging threads if
182
they are missed in mutex_signal_object. */
184
if (mutex_get_waiters(mutex) != 0) {
186
mutex_signal_object(mutex);
189
#ifdef UNIV_SYNC_PERF_STAT
194
/******************************************************************//**
195
Locks a mutex for the current thread. If the mutex is reserved, the function
196
spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the mutex
197
before suspending the thread. */
202
mutex_t* mutex, /*!< in: pointer to mutex */
203
const char* file_name, /*!< in: file name where locked */
204
ulint line) /*!< in: line where locked */
206
ut_ad(mutex_validate(mutex));
207
ut_ad(!mutex_own(mutex));
209
/* Note that we do not peek at the value of lock_word before trying
210
the atomic test_and_set; we could peek, and possibly save time. */
212
ut_d(mutex->count_using++);
214
if (!mutex_test_and_set(mutex)) {
215
ut_d(mutex->thread_id = os_thread_get_curr_id());
216
#ifdef UNIV_SYNC_DEBUG
217
mutex_set_debug_info(mutex, file_name, line);
219
return; /* Succeeded! */
222
mutex_spin_wait(mutex, file_name, line);
225
#ifdef UNIV_PFS_MUTEX
226
/******************************************************************//**
227
NOTE! Please use the corresponding macro mutex_enter(), not directly
229
This is a performance schema instrumented wrapper function for
230
mutex_enter_func(). */
233
pfs_mutex_enter_func(
234
/*=================*/
235
mutex_t* mutex, /*!< in: pointer to mutex */
236
const char* file_name, /*!< in: file name where locked */
237
ulint line) /*!< in: line where locked */
239
struct PSI_mutex_locker* locker = NULL;
240
PSI_mutex_locker_state state;
243
if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
244
locker = PSI_server->get_thread_mutex_locker(
245
&state, mutex->pfs_psi, PSI_MUTEX_LOCK);
247
PSI_server->start_mutex_wait(locker, file_name, line);
251
mutex_enter_func(mutex, file_name, line);
254
PSI_server->end_mutex_wait(locker, result);
257
/********************************************************************//**
258
NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
260
This is a performance schema instrumented wrapper function for
261
mutex_enter_nowait_func.
262
@return 0 if succeed, 1 if not */
265
pfs_mutex_enter_nowait_func(
266
/*========================*/
267
mutex_t* mutex, /*!< in: pointer to mutex */
268
const char* file_name, /*!< in: file name where mutex
270
ulint line) /*!< in: line where requested */
273
struct PSI_mutex_locker* locker = NULL;
274
PSI_mutex_locker_state state;
277
if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
278
locker = PSI_server->get_thread_mutex_locker(
279
&state, mutex->pfs_psi, PSI_MUTEX_LOCK);
281
PSI_server->start_mutex_wait(locker, file_name, line);
285
ret = mutex_enter_nowait_func(mutex, file_name, line);
288
PSI_server->end_mutex_wait(locker, result);
293
/******************************************************************//**
294
NOTE! Please use the corresponding macro mutex_exit(), not directly
296
A wrap function of mutex_exit_func() with performance schema instrumentation.
297
Unlocks a mutex owned by the current thread. */
302
mutex_t* mutex) /*!< in: pointer to mutex */
304
if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
305
PSI_server->unlock_mutex(mutex->pfs_psi);
308
mutex_exit_func(mutex);
311
/******************************************************************//**
312
NOTE! Please use the corresponding macro mutex_create(), not directly
314
A wrapper function for mutex_create_func(), registers the mutex
315
with performance schema if "UNIV_PFS_MUTEX" is defined when
316
creating the mutex */
319
pfs_mutex_create_func(
320
/*==================*/
321
mysql_pfs_key_t key, /*!< in: Performance Schema key */
322
mutex_t* mutex, /*!< in: pointer to memory */
324
const char* cmutex_name, /*!< in: mutex name */
325
# ifdef UNIV_SYNC_DEBUG
326
ulint level, /*!< in: level */
327
# endif /* UNIV_SYNC_DEBUG */
328
# endif /* UNIV_DEBUG */
329
const char* cfile_name, /*!< in: file name where created */
330
ulint cline) /*!< in: file line where created */
332
mutex->pfs_psi = (PSI_server && PFS_IS_INSTRUMENTED(key))
333
? PSI_server->init_mutex(key, mutex)
336
mutex_create_func(mutex,
339
# ifdef UNIV_SYNC_DEBUG
341
# endif /* UNIV_SYNC_DEBUG */
342
# endif /* UNIV_DEBUG */
346
/******************************************************************//**
347
NOTE! Please use the corresponding macro mutex_free(), not directly
349
Wrapper function for mutex_free_func(). Also destroys the performance
350
schema probes when freeing the mutex */
355
mutex_t* mutex) /*!< in: mutex */
357
if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
358
PSI_server->destroy_mutex(mutex->pfs_psi);
359
mutex->pfs_psi = NULL;
362
mutex_free_func(mutex);
365
#endif /* UNIV_PFS_MUTEX */