~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Reverted 1103

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., 51 Franklin
22
 
St, Fifth Floor, Boston, MA 02110-1301 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
 
        int     result = 0;
276
 
 
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);
280
 
                if (locker) {
281
 
                        PSI_server->start_mutex_wait(locker, file_name, line);
282
 
                }
283
 
        }
284
 
 
285
 
        ret = mutex_enter_nowait_func(mutex, file_name, line);
286
 
 
287
 
        if (locker) {
288
 
                PSI_server->end_mutex_wait(locker, result);
289
 
        }
290
 
 
291
 
        return(ret);
292
 
}
293
 
/******************************************************************//**
294
 
NOTE! Please use the corresponding macro mutex_exit(), not directly
295
 
this function!
296
 
A wrap function of mutex_exit_func() with performance schema instrumentation.
297
 
Unlocks a mutex owned by the current thread. */
298
 
UNIV_INLINE
299
 
void
300
 
pfs_mutex_exit_func(
301
 
/*================*/
302
 
        mutex_t*        mutex)  /*!< in: pointer to mutex */
303
 
{
304
 
        if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
305
 
                PSI_server->unlock_mutex(mutex->pfs_psi);
306
 
        }
307
 
 
308
 
        mutex_exit_func(mutex);
309
 
}
310
 
 
311
 
/******************************************************************//**
312
 
NOTE! Please use the corresponding macro mutex_create(), not directly
313
 
this function!
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 */
317
 
UNIV_INLINE
318
 
void
319
 
pfs_mutex_create_func(
320
 
/*==================*/
321
 
        mysql_pfs_key_t key,            /*!< in: Performance Schema key */
322
 
        mutex_t*        mutex,          /*!< in: pointer to memory */
323
 
# ifdef UNIV_DEBUG
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 */
331
 
{
332
 
        mutex->pfs_psi = (PSI_server && PFS_IS_INSTRUMENTED(key))
333
 
                                ? PSI_server->init_mutex(key, mutex)
334
 
                                : NULL;
335
 
 
336
 
        mutex_create_func(mutex,
337
 
# ifdef UNIV_DEBUG
338
 
                          cmutex_name,
339
 
#  ifdef UNIV_SYNC_DEBUG
340
 
                          level,
341
 
#  endif /* UNIV_SYNC_DEBUG */
342
 
# endif /* UNIV_DEBUG */
343
 
                          cfile_name,
344
 
                          cline);
345
 
}
346
 
/******************************************************************//**
347
 
NOTE! Please use the corresponding macro mutex_free(), not directly
348
 
this function!
349
 
Wrapper function for mutex_free_func(). Also destroys the performance
350
 
schema probes when freeing the mutex */
351
 
UNIV_INLINE
352
 
void
353
 
pfs_mutex_free_func(
354
 
/*================*/
355
 
        mutex_t*        mutex)  /*!< in: mutex */
356
 
{
357
 
        if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) {
358
 
                PSI_server->destroy_mutex(mutex->pfs_psi);
359
 
                mutex->pfs_psi = NULL;
360
 
        }
361
 
 
362
 
        mutex_free_func(mutex);
363
 
}
364
 
 
365
 
#endif /* UNIV_PFS_MUTEX */