~ubuntu-branches/ubuntu/trusty/mariadb-5.5/trusty-proposed

« back to all changes in this revision

Viewing changes to storage/innobase/include/sync0sync.ic

  • Committer: Package Import Robot
  • Author(s): Otto Kekäläinen
  • Date: 2013-12-22 10:27:05 UTC
  • Revision ID: package-import@ubuntu.com-20131222102705-mndw7s12mz0szrcn
Tags: upstream-5.5.32
Import upstream version 5.5.32

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
 
4
Copyright (c) 2008, Google Inc.
 
5
 
 
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.
 
11
 
 
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.
 
15
 
 
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.
 
19
 
 
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
 
23
 
 
24
*****************************************************************************/
 
25
 
 
26
/**************************************************//**
 
27
@file include/sync0sync.ic
 
28
Mutex, the basic synchronization primitive
 
29
 
 
30
Created 9/5/1995 Heikki Tuuri
 
31
*******************************************************/
 
32
 
 
33
/******************************************************************//**
 
34
Sets the waiters field in a mutex. */
 
35
UNIV_INTERN
 
36
void
 
37
mutex_set_waiters(
 
38
/*==============*/
 
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. */
 
45
UNIV_INTERN
 
46
void
 
47
mutex_spin_wait(
 
48
/*============*/
 
49
        mutex_t*        mutex,          /*!< in: pointer to mutex */
 
50
        const char*     file_name,      /*!< in: file name where mutex
 
51
                                        requested */
 
52
        ulint           line);          /*!< in: line where requested */
 
53
#ifdef UNIV_SYNC_DEBUG
 
54
/******************************************************************//**
 
55
Sets the debug information for a reserved mutex. */
 
56
UNIV_INTERN
 
57
void
 
58
mutex_set_debug_info(
 
59
/*=================*/
 
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. */
 
66
UNIV_INTERN
 
67
void
 
68
mutex_signal_object(
 
69
/*================*/
 
70
        mutex_t*        mutex); /*!< in: mutex */
 
71
 
 
72
/******************************************************************//**
 
73
Performs an atomic test-and-set instruction to the lock_word field of a
 
74
mutex.
 
75
@return the previous value of lock_word: 0 or 1 */
 
76
UNIV_INLINE
 
77
byte
 
78
mutex_test_and_set(
 
79
/*===============*/
 
80
        mutex_t*        mutex)  /*!< in: mutex */
 
81
{
 
82
#if defined(HAVE_ATOMIC_BUILTINS)
 
83
        return(os_atomic_test_and_set_byte(&mutex->lock_word, 1));
 
84
#else
 
85
        ibool   ret;
 
86
 
 
87
        ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex));
 
88
 
 
89
        if (ret == 0) {
 
90
                /* We check that os_fast_mutex_trylock does not leak
 
91
                and allow race conditions */
 
92
                ut_a(mutex->lock_word == 0);
 
93
 
 
94
                mutex->lock_word = 1;
 
95
        }
 
96
 
 
97
        return((byte)ret);
 
98
#endif
 
99
}
 
100
 
 
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. */
 
104
UNIV_INLINE
 
105
void
 
106
mutex_reset_lock_word(
 
107
/*==================*/
 
108
        mutex_t*        mutex)  /*!< in: mutex */
 
109
{
 
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);
 
115
#else
 
116
        mutex->lock_word = 0;
 
117
 
 
118
        os_fast_mutex_unlock(&(mutex->os_fast_mutex));
 
119
#endif
 
120
}
 
121
 
 
122
/******************************************************************//**
 
123
Gets the value of the lock word. */
 
124
UNIV_INLINE
 
125
lock_word_t
 
126
mutex_get_lock_word(
 
127
/*================*/
 
128
        const mutex_t*  mutex)  /*!< in: mutex */
 
129
{
 
130
        ut_ad(mutex);
 
131
 
 
132
        return(mutex->lock_word);
 
133
}
 
134
 
 
135
/******************************************************************//**
 
136
Gets the waiters field in a mutex.
 
137
@return value to set */
 
138
UNIV_INLINE
 
139
ulint
 
140
mutex_get_waiters(
 
141
/*==============*/
 
142
        const mutex_t*  mutex)  /*!< in: mutex */
 
143
{
 
144
        const volatile ulint*   ptr;    /*!< declared volatile to ensure that
 
145
                                        the value is read from memory */
 
146
        ut_ad(mutex);
 
147
 
 
148
        ptr = &(mutex->waiters);
 
149
 
 
150
        return(*ptr);           /* Here we assume that the read of a single
 
151
                                word from memory is atomic */
 
152
}
 
153
 
 
154
/******************************************************************//**
 
155
NOTE! Use the corresponding macro mutex_exit(), not directly this function!
 
156
Unlocks a mutex owned by the current thread. */
 
157
UNIV_INLINE
 
158
void
 
159
mutex_exit_func(
 
160
/*============*/
 
161
        mutex_t*        mutex)  /*!< in: pointer to mutex */
 
162
{
 
163
        ut_ad(mutex_own(mutex));
 
164
 
 
165
        ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
 
166
 
 
167
#ifdef UNIV_SYNC_DEBUG
 
168
        sync_thread_reset_level(mutex);
 
169
#endif
 
170
        mutex_reset_lock_word(mutex);
 
171
 
 
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.
 
178
 
 
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. */
 
183
 
 
184
        if (mutex_get_waiters(mutex) != 0) {
 
185
 
 
186
                mutex_signal_object(mutex);
 
187
        }
 
188
 
 
189
#ifdef UNIV_SYNC_PERF_STAT
 
190
        mutex_exit_count++;
 
191
#endif
 
192
}
 
193
 
 
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. */
 
198
UNIV_INLINE
 
199
void
 
200
mutex_enter_func(
 
201
/*=============*/
 
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 */
 
205
{
 
206
        ut_ad(mutex_validate(mutex));
 
207
        ut_ad(!mutex_own(mutex));
 
208
 
 
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. */
 
211
 
 
212
        ut_d(mutex->count_using++);
 
213
 
 
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);
 
218
#endif
 
219
                return; /* Succeeded! */
 
220
        }
 
221
 
 
222
        mutex_spin_wait(mutex, file_name, line);
 
223
}
 
224
 
 
225
#ifdef UNIV_PFS_MUTEX
 
226
/******************************************************************//**
 
227
NOTE! Please use the corresponding macro mutex_enter(), not directly
 
228
this function!
 
229
This is a performance schema instrumented wrapper function for
 
230
mutex_enter_func(). */
 
231
UNIV_INLINE
 
232
void
 
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 */
 
238
{
 
239
        struct PSI_mutex_locker*        locker = NULL;
 
240
        PSI_mutex_locker_state          state;
 
241
        int     result = 0;
 
242
 
 
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);
 
246
                if (locker) {
 
247
                        PSI_server->start_mutex_wait(locker, file_name, line);
 
248
                }
 
249
        }
 
250
 
 
251
        mutex_enter_func(mutex, file_name, line);
 
252
 
 
253
        if (locker) {
 
254
                PSI_server->end_mutex_wait(locker, result);
 
255
        }
 
256
}
 
257
/********************************************************************//**
 
258
NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly
 
259
this function!
 
260
This is a performance schema instrumented wrapper function for
 
261
mutex_enter_nowait_func.
 
262
@return 0 if succeed, 1 if not */
 
263
UNIV_INLINE
 
264
ulint
 
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
 
269
                                        requested */
 
270
        ulint           line)           /*!< in: line where requested */
 
271
{
 
272
        ulint   ret;
 
273
        struct PSI_mutex_locker*        locker = NULL;
 
274
        PSI_mutex_locker_state          state;
 
275
 
 
276
        if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
 
277
                locker = PSI_server->get_thread_mutex_locker(
 
278
                                &state, mutex->pfs_psi, PSI_MUTEX_TRYLOCK);
 
279
                if (locker) {
 
280
                        PSI_server->start_mutex_wait(locker, file_name, line);
 
281
                }
 
282
        }
 
283
 
 
284
        ret = mutex_enter_nowait_func(mutex, file_name, line);
 
285
 
 
286
        if (locker) {
 
287
                PSI_server->end_mutex_wait(locker, ret);
 
288
        }
 
289
 
 
290
        return(ret);
 
291
}
 
292
/******************************************************************//**
 
293
NOTE! Please use the corresponding macro mutex_exit(), not directly
 
294
this function!
 
295
A wrap function of mutex_exit_func() with performance schema instrumentation.
 
296
Unlocks a mutex owned by the current thread. */
 
297
UNIV_INLINE
 
298
void
 
299
pfs_mutex_exit_func(
 
300
/*================*/
 
301
        mutex_t*        mutex)  /*!< in: pointer to mutex */
 
302
{
 
303
        if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
 
304
                PSI_server->unlock_mutex(mutex->pfs_psi);
 
305
        }
 
306
 
 
307
        mutex_exit_func(mutex);
 
308
}
 
309
 
 
310
/******************************************************************//**
 
311
NOTE! Please use the corresponding macro mutex_create(), not directly
 
312
this function!
 
313
A wrapper function for mutex_create_func(), registers the mutex
 
314
with performance schema if "UNIV_PFS_MUTEX" is defined when
 
315
creating the mutex */
 
316
UNIV_INLINE
 
317
void
 
318
pfs_mutex_create_func(
 
319
/*==================*/
 
320
        mysql_pfs_key_t key,            /*!< in: Performance Schema key */
 
321
        mutex_t*        mutex,          /*!< in: pointer to memory */
 
322
# ifdef UNIV_DEBUG
 
323
        const char*     cmutex_name,    /*!< in: mutex name */
 
324
#  ifdef UNIV_SYNC_DEBUG
 
325
        ulint           level,          /*!< in: level */
 
326
#  endif /* UNIV_SYNC_DEBUG */
 
327
# endif /* UNIV_DEBUG */
 
328
        const char*     cfile_name,     /*!< in: file name where created */
 
329
        ulint           cline)          /*!< in: file line where created */
 
330
{
 
331
        mutex->pfs_psi = (PSI_server && PFS_IS_INSTRUMENTED(key))
 
332
                                ? PSI_server->init_mutex(key, mutex)
 
333
                                : NULL;
 
334
 
 
335
        mutex_create_func(mutex,
 
336
# ifdef UNIV_DEBUG
 
337
                          cmutex_name,
 
338
#  ifdef UNIV_SYNC_DEBUG
 
339
                          level,
 
340
#  endif /* UNIV_SYNC_DEBUG */
 
341
# endif /* UNIV_DEBUG */
 
342
                          cfile_name,
 
343
                          cline);
 
344
}
 
345
/******************************************************************//**
 
346
NOTE! Please use the corresponding macro mutex_free(), not directly
 
347
this function!
 
348
Wrapper function for mutex_free_func(). Also destroys the performance
 
349
schema probes when freeing the mutex */
 
350
UNIV_INLINE
 
351
void
 
352
pfs_mutex_free_func(
 
353
/*================*/
 
354
        mutex_t*        mutex)  /*!< in: mutex */
 
355
{
 
356
        if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
 
357
                PSI_server->destroy_mutex(mutex->pfs_psi);
 
358
                mutex->pfs_psi = NULL;
 
359
        }
 
360
 
 
361
        mutex_free_func(mutex);
 
362
}
 
363
 
 
364
#endif /* UNIV_PFS_MUTEX */