~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/innobase/sync/sync0sync.c

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

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 sync/sync0sync.c
 
28
Mutex, the basic synchronization primitive
 
29
 
 
30
Created 9/5/1995 Heikki Tuuri
 
31
*******************************************************/
 
32
 
 
33
#include "sync0sync.h"
 
34
#ifdef UNIV_NONINL
 
35
#include "sync0sync.ic"
 
36
#endif
 
37
 
 
38
#include "sync0rw.h"
 
39
#include "buf0buf.h"
 
40
#include "srv0srv.h"
 
41
#include "buf0types.h"
 
42
 
 
43
/*
 
44
        REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX
 
45
        ============================================
 
46
 
 
47
Semaphore operations in operating systems are slow: Solaris on a 1993 Sparc
 
48
takes 3 microseconds (us) for a lock-unlock pair and Windows NT on a 1995
 
49
Pentium takes 20 microseconds for a lock-unlock pair. Therefore, we have to
 
50
implement our own efficient spin lock mutex. Future operating systems may
 
51
provide efficient spin locks, but we cannot count on that.
 
52
 
 
53
Another reason for implementing a spin lock is that on multiprocessor systems
 
54
it can be more efficient for a processor to run a loop waiting for the
 
55
semaphore to be released than to switch to a different thread. A thread switch
 
56
takes 25 us on both platforms mentioned above. See Gray and Reuter's book
 
57
Transaction processing for background.
 
58
 
 
59
How long should the spin loop last before suspending the thread? On a
 
60
uniprocessor, spinning does not help at all, because if the thread owning the
 
61
mutex is not executing, it cannot be released. Spinning actually wastes
 
62
resources.
 
63
 
 
64
On a multiprocessor, we do not know if the thread owning the mutex is
 
65
executing or not. Thus it would make sense to spin as long as the operation
 
66
guarded by the mutex would typically last assuming that the thread is
 
67
executing. If the mutex is not released by that time, we may assume that the
 
68
thread owning the mutex is not executing and suspend the waiting thread.
 
69
 
 
70
A typical operation (where no i/o involved) guarded by a mutex or a read-write
 
71
lock may last 1 - 20 us on the current Pentium platform. The longest
 
72
operations are the binary searches on an index node.
 
73
 
 
74
We conclude that the best choice is to set the spin time at 20 us. Then the
 
75
system should work well on a multiprocessor. On a uniprocessor we have to
 
76
make sure that thread swithches due to mutex collisions are not frequent,
 
77
i.e., they do not happen every 100 us or so, because that wastes too much
 
78
resources. If the thread switches are not frequent, the 20 us wasted in spin
 
79
loop is not too much.
 
80
 
 
81
Empirical studies on the effect of spin time should be done for different
 
82
platforms.
 
83
 
 
84
 
 
85
        IMPLEMENTATION OF THE MUTEX
 
86
        ===========================
 
87
 
 
88
For background, see Curt Schimmel's book on Unix implementation on modern
 
89
architectures. The key points in the implementation are atomicity and
 
90
serialization of memory accesses. The test-and-set instruction (XCHG in
 
91
Pentium) must be atomic. As new processors may have weak memory models, also
 
92
serialization of memory references may be necessary. The successor of Pentium,
 
93
P6, has at least one mode where the memory model is weak. As far as we know,
 
94
in Pentium all memory accesses are serialized in the program order and we do
 
95
not have to worry about the memory model. On other processors there are
 
96
special machine instructions called a fence, memory barrier, or storage
 
97
barrier (STBAR in Sparc), which can be used to serialize the memory accesses
 
98
to happen in program order relative to the fence instruction.
 
99
 
 
100
Leslie Lamport has devised a "bakery algorithm" to implement a mutex without
 
101
the atomic test-and-set, but his algorithm should be modified for weak memory
 
102
models. We do not use Lamport's algorithm, because we guess it is slower than
 
103
the atomic test-and-set.
 
104
 
 
105
Our mutex implementation works as follows: After that we perform the atomic
 
106
test-and-set instruction on the memory word. If the test returns zero, we
 
107
know we got the lock first. If the test returns not zero, some other thread
 
108
was quicker and got the lock: then we spin in a loop reading the memory word,
 
109
waiting it to become zero. It is wise to just read the word in the loop, not
 
110
perform numerous test-and-set instructions, because they generate memory
 
111
traffic between the cache and the main memory. The read loop can just access
 
112
the cache, saving bus bandwidth.
 
113
 
 
114
If we cannot acquire the mutex lock in the specified time, we reserve a cell
 
115
in the wait array, set the waiters byte in the mutex to 1. To avoid a race
 
116
condition, after setting the waiters byte and before suspending the waiting
 
117
thread, we still have to check that the mutex is reserved, because it may
 
118
have happened that the thread which was holding the mutex has just released
 
119
it and did not see the waiters byte set to 1, a case which would lead the
 
120
other thread to an infinite wait.
 
121
 
 
122
LEMMA 1: After a thread resets the event of a mutex (or rw_lock), some
 
123
=======
 
124
thread will eventually call os_event_set() on that particular event.
 
125
Thus no infinite wait is possible in this case.
 
126
 
 
127
Proof:  After making the reservation the thread sets the waiters field in the
 
128
mutex to 1. Then it checks that the mutex is still reserved by some thread,
 
129
or it reserves the mutex for itself. In any case, some thread (which may be
 
130
also some earlier thread, not necessarily the one currently holding the mutex)
 
131
will set the waiters field to 0 in mutex_exit, and then call
 
132
os_event_set() with the mutex as an argument.
 
133
Q.E.D.
 
134
 
 
135
LEMMA 2: If an os_event_set() call is made after some thread has called
 
136
=======
 
137
the os_event_reset() and before it starts wait on that event, the call
 
138
will not be lost to the second thread. This is true even if there is an
 
139
intervening call to os_event_reset() by another thread.
 
140
Thus no infinite wait is possible in this case.
 
141
 
 
142
Proof (non-windows platforms): os_event_reset() returns a monotonically
 
143
increasing value of signal_count. This value is increased at every
 
144
call of os_event_set() If thread A has called os_event_reset() followed
 
145
by thread B calling os_event_set() and then some other thread C calling
 
146
os_event_reset(), the is_set flag of the event will be set to FALSE;
 
147
but now if thread A calls os_event_wait_low() with the signal_count
 
148
value returned from the earlier call of os_event_reset(), it will
 
149
return immediately without waiting.
 
150
Q.E.D.
 
151
 
 
152
Proof (windows): If there is a writer thread which is forced to wait for
 
153
the lock, it may be able to set the state of rw_lock to RW_LOCK_WAIT_EX
 
154
The design of rw_lock ensures that there is one and only one thread
 
155
that is able to change the state to RW_LOCK_WAIT_EX and this thread is
 
156
guaranteed to acquire the lock after it is released by the current
 
157
holders and before any other waiter gets the lock.
 
158
On windows this thread waits on a separate event i.e.: wait_ex_event.
 
159
Since only one thread can wait on this event there is no chance
 
160
of this event getting reset before the writer starts wait on it.
 
161
Therefore, this thread is guaranteed to catch the os_set_event()
 
162
signalled unconditionally at the release of the lock.
 
163
Q.E.D. */
 
164
 
 
165
/* Number of spin waits on mutexes: for performance monitoring */
 
166
 
 
167
/** The number of iterations in the mutex_spin_wait() spin loop.
 
168
Intended for performance monitoring. */
 
169
static ib_int64_t       mutex_spin_round_count          = 0;
 
170
/** The number of mutex_spin_wait() calls.  Intended for
 
171
performance monitoring. */
 
172
static ib_int64_t       mutex_spin_wait_count           = 0;
 
173
/** The number of OS waits in mutex_spin_wait().  Intended for
 
174
performance monitoring. */
 
175
static ib_int64_t       mutex_os_wait_count             = 0;
 
176
/** The number of mutex_exit() calls. Intended for performance
 
177
monitoring. */
 
178
UNIV_INTERN ib_int64_t  mutex_exit_count                = 0;
 
179
 
 
180
/** The global array of wait cells for implementation of the database's own
 
181
mutexes and read-write locks */
 
182
UNIV_INTERN sync_array_t*       sync_primary_wait_array;
 
183
 
 
184
/** This variable is set to TRUE when sync_init is called */
 
185
UNIV_INTERN ibool       sync_initialized        = FALSE;
 
186
 
 
187
/** An acquired mutex or rw-lock and its level in the latching order */
 
188
typedef struct sync_level_struct        sync_level_t;
 
189
/** Mutexes or rw-locks held by a thread */
 
190
typedef struct sync_thread_struct       sync_thread_t;
 
191
 
 
192
#ifdef UNIV_SYNC_DEBUG
 
193
/** The latch levels currently owned by threads are stored in this data
 
194
structure; the size of this array is OS_THREAD_MAX_N */
 
195
 
 
196
UNIV_INTERN sync_thread_t*      sync_thread_level_arrays;
 
197
 
 
198
/** Mutex protecting sync_thread_level_arrays */
 
199
UNIV_INTERN mutex_t             sync_thread_mutex;
 
200
#endif /* UNIV_SYNC_DEBUG */
 
201
 
 
202
/** Global list of database mutexes (not OS mutexes) created. */
 
203
UNIV_INTERN ut_list_base_node_t  mutex_list;
 
204
 
 
205
/** Mutex protecting the mutex_list variable */
 
206
UNIV_INTERN mutex_t mutex_list_mutex;
 
207
 
 
208
#ifdef UNIV_SYNC_DEBUG
 
209
/** Latching order checks start when this is set TRUE */
 
210
UNIV_INTERN ibool       sync_order_checks_on    = FALSE;
 
211
#endif /* UNIV_SYNC_DEBUG */
 
212
 
 
213
/** Mutexes or rw-locks held by a thread */
 
214
struct sync_thread_struct{
 
215
        os_thread_id_t  id;     /*!< OS thread id */
 
216
        sync_level_t*   levels; /*!< level array for this thread; if
 
217
                                this is NULL this slot is unused */
 
218
};
 
219
 
 
220
/** Number of slots reserved for each OS thread in the sync level array */
 
221
#define SYNC_THREAD_N_LEVELS    10000
 
222
 
 
223
/** An acquired mutex or rw-lock and its level in the latching order */
 
224
struct sync_level_struct{
 
225
        void*   latch;  /*!< pointer to a mutex or an rw-lock; NULL means that
 
226
                        the slot is empty */
 
227
        ulint   level;  /*!< level of the latch in the latching order */
 
228
};
 
229
 
 
230
/******************************************************************//**
 
231
Creates, or rather, initializes a mutex object in a specified memory
 
232
location (which must be appropriately aligned). The mutex is initialized
 
233
in the reset state. Explicit freeing of the mutex with mutex_free is
 
234
necessary only if the memory block containing it is freed. */
 
235
UNIV_INTERN
 
236
void
 
237
mutex_create_func(
 
238
/*==============*/
 
239
        mutex_t*        mutex,          /*!< in: pointer to memory */
 
240
#ifdef UNIV_DEBUG
 
241
        const char*     cmutex_name,    /*!< in: mutex name */
 
242
# ifdef UNIV_SYNC_DEBUG
 
243
        ulint           level,          /*!< in: level */
 
244
# endif /* UNIV_SYNC_DEBUG */
 
245
#endif /* UNIV_DEBUG */
 
246
        const char*     cfile_name,     /*!< in: file name where created */
 
247
        ulint           cline)          /*!< in: file line where created */
 
248
{
 
249
#if defined(HAVE_ATOMIC_BUILTINS)
 
250
        mutex_reset_lock_word(mutex);
 
251
#else
 
252
        os_fast_mutex_init(&(mutex->os_fast_mutex));
 
253
        mutex->lock_word = 0;
 
254
#endif
 
255
        mutex->event = os_event_create(NULL);
 
256
        mutex_set_waiters(mutex, 0);
 
257
#ifdef UNIV_DEBUG
 
258
        mutex->magic_n = MUTEX_MAGIC_N;
 
259
#endif /* UNIV_DEBUG */
 
260
#ifdef UNIV_SYNC_DEBUG
 
261
        mutex->line = 0;
 
262
        mutex->file_name = "not yet reserved";
 
263
        mutex->level = level;
 
264
#endif /* UNIV_SYNC_DEBUG */
 
265
        mutex->cfile_name = cfile_name;
 
266
        mutex->cline = cline;
 
267
        mutex->count_os_wait = 0;
 
268
#ifdef UNIV_DEBUG
 
269
        mutex->cmutex_name=       cmutex_name;
 
270
        mutex->count_using=       0;
 
271
        mutex->mutex_type=        0;
 
272
        mutex->lspent_time=       0;
 
273
        mutex->lmax_spent_time=     0;
 
274
        mutex->count_spin_loop= 0;
 
275
        mutex->count_spin_rounds=   0;
 
276
        mutex->count_os_yield=  0;
 
277
#endif /* UNIV_DEBUG */
 
278
 
 
279
        /* Check that lock_word is aligned; this is important on Intel */
 
280
        ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0);
 
281
 
 
282
        /* NOTE! The very first mutexes are not put to the mutex list */
 
283
 
 
284
        if ((mutex == &mutex_list_mutex)
 
285
#ifdef UNIV_SYNC_DEBUG
 
286
            || (mutex == &sync_thread_mutex)
 
287
#endif /* UNIV_SYNC_DEBUG */
 
288
            ) {
 
289
 
 
290
                return;
 
291
        }
 
292
 
 
293
        mutex_enter(&mutex_list_mutex);
 
294
 
 
295
        ut_ad(UT_LIST_GET_LEN(mutex_list) == 0
 
296
              || UT_LIST_GET_FIRST(mutex_list)->magic_n == MUTEX_MAGIC_N);
 
297
 
 
298
        UT_LIST_ADD_FIRST(list, mutex_list, mutex);
 
299
 
 
300
        mutex_exit(&mutex_list_mutex);
 
301
}
 
302
 
 
303
/******************************************************************//**
 
304
Calling this function is obligatory only if the memory buffer containing
 
305
the mutex is freed. Removes a mutex object from the mutex list. The mutex
 
306
is checked to be in the reset state. */
 
307
UNIV_INTERN
 
308
void
 
309
mutex_free(
 
310
/*=======*/
 
311
        mutex_t*        mutex)  /*!< in: mutex */
 
312
{
 
313
        ut_ad(mutex_validate(mutex));
 
314
        ut_a(mutex_get_lock_word(mutex) == 0);
 
315
        ut_a(mutex_get_waiters(mutex) == 0);
 
316
 
 
317
        if (mutex != &mutex_list_mutex
 
318
#ifdef UNIV_SYNC_DEBUG
 
319
            && mutex != &sync_thread_mutex
 
320
#endif /* UNIV_SYNC_DEBUG */
 
321
            ) {
 
322
 
 
323
                mutex_enter(&mutex_list_mutex);
 
324
 
 
325
                ut_ad(!UT_LIST_GET_PREV(list, mutex)
 
326
                      || UT_LIST_GET_PREV(list, mutex)->magic_n
 
327
                      == MUTEX_MAGIC_N);
 
328
                ut_ad(!UT_LIST_GET_NEXT(list, mutex)
 
329
                      || UT_LIST_GET_NEXT(list, mutex)->magic_n
 
330
                      == MUTEX_MAGIC_N);
 
331
 
 
332
                UT_LIST_REMOVE(list, mutex_list, mutex);
 
333
 
 
334
                mutex_exit(&mutex_list_mutex);
 
335
        }
 
336
 
 
337
        os_event_free(mutex->event);
 
338
 
 
339
#if !defined(HAVE_ATOMIC_BUILTINS)
 
340
        os_fast_mutex_free(&(mutex->os_fast_mutex));
 
341
#endif
 
342
        /* If we free the mutex protecting the mutex list (freeing is
 
343
        not necessary), we have to reset the magic number AFTER removing
 
344
        it from the list. */
 
345
#ifdef UNIV_DEBUG
 
346
        mutex->magic_n = 0;
 
347
#endif /* UNIV_DEBUG */
 
348
}
 
349
 
 
350
/********************************************************************//**
 
351
NOTE! Use the corresponding macro in the header file, not this function
 
352
directly. Tries to lock the mutex for the current thread. If the lock is not
 
353
acquired immediately, returns with return value 1.
 
354
@return 0 if succeed, 1 if not */
 
355
UNIV_INTERN
 
356
ulint
 
357
mutex_enter_nowait_func(
 
358
/*====================*/
 
359
        mutex_t*        mutex,          /*!< in: pointer to mutex */
 
360
        const char*     file_name __attribute__((unused)),
 
361
                                        /*!< in: file name where mutex
 
362
                                        requested */
 
363
        ulint           line __attribute__((unused)))
 
364
                                        /*!< in: line where requested */
 
365
{
 
366
        ut_ad(mutex_validate(mutex));
 
367
 
 
368
        if (!mutex_test_and_set(mutex)) {
 
369
 
 
370
                ut_d(mutex->thread_id = os_thread_get_curr_id());
 
371
#ifdef UNIV_SYNC_DEBUG
 
372
                mutex_set_debug_info(mutex, file_name, line);
 
373
#endif
 
374
 
 
375
                return(0);      /* Succeeded! */
 
376
        }
 
377
 
 
378
        return(1);
 
379
}
 
380
 
 
381
#ifdef UNIV_DEBUG
 
382
/******************************************************************//**
 
383
Checks that the mutex has been initialized.
 
384
@return TRUE */
 
385
UNIV_INTERN
 
386
ibool
 
387
mutex_validate(
 
388
/*===========*/
 
389
        const mutex_t*  mutex)  /*!< in: mutex */
 
390
{
 
391
        ut_a(mutex);
 
392
        ut_a(mutex->magic_n == MUTEX_MAGIC_N);
 
393
 
 
394
        return(TRUE);
 
395
}
 
396
 
 
397
/******************************************************************//**
 
398
Checks that the current thread owns the mutex. Works only in the debug
 
399
version.
 
400
@return TRUE if owns */
 
401
UNIV_INTERN
 
402
ibool
 
403
mutex_own(
 
404
/*======*/
 
405
        const mutex_t*  mutex)  /*!< in: mutex */
 
406
{
 
407
        ut_ad(mutex_validate(mutex));
 
408
 
 
409
        return(mutex_get_lock_word(mutex) == 1
 
410
               && os_thread_eq(mutex->thread_id, os_thread_get_curr_id()));
 
411
}
 
412
#endif /* UNIV_DEBUG */
 
413
 
 
414
/******************************************************************//**
 
415
Sets the waiters field in a mutex. */
 
416
UNIV_INTERN
 
417
void
 
418
mutex_set_waiters(
 
419
/*==============*/
 
420
        mutex_t*        mutex,  /*!< in: mutex */
 
421
        ulint           n)      /*!< in: value to set */
 
422
{
 
423
        volatile ulint* ptr;            /* declared volatile to ensure that
 
424
                                        the value is stored to memory */
 
425
        ut_ad(mutex);
 
426
 
 
427
        ptr = &(mutex->waiters);
 
428
 
 
429
        *ptr = n;               /* Here we assume that the write of a single
 
430
                                word in memory is atomic */
 
431
}
 
432
 
 
433
/******************************************************************//**
 
434
Reserves a mutex for the current thread. If the mutex is reserved, the
 
435
function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
 
436
for the mutex before suspending the thread. */
 
437
UNIV_INTERN
 
438
void
 
439
mutex_spin_wait(
 
440
/*============*/
 
441
        mutex_t*        mutex,          /*!< in: pointer to mutex */
 
442
        const char*     file_name,      /*!< in: file name where mutex
 
443
                                        requested */
 
444
        ulint           line)           /*!< in: line where requested */
 
445
{
 
446
        ulint      index; /* index of the reserved wait cell */
 
447
        ulint      i;     /* spin round count */
 
448
#ifdef UNIV_DEBUG
 
449
        ib_int64_t lstart_time = 0, lfinish_time; /* for timing os_wait */
 
450
        ulint ltime_diff;
 
451
        ulint sec;
 
452
        ulint ms;
 
453
        uint timer_started = 0;
 
454
#endif /* UNIV_DEBUG */
 
455
        ut_ad(mutex);
 
456
 
 
457
        /* This update is not thread safe, but we don't mind if the count
 
458
        isn't exact. Moved out of ifdef that follows because we are willing
 
459
        to sacrifice the cost of counting this as the data is valuable.
 
460
        Count the number of calls to mutex_spin_wait. */
 
461
        mutex_spin_wait_count++;
 
462
 
 
463
mutex_loop:
 
464
 
 
465
        i = 0;
 
466
 
 
467
        /* Spin waiting for the lock word to become zero. Note that we do
 
468
        not have to assume that the read access to the lock word is atomic,
 
469
        as the actual locking is always committed with atomic test-and-set.
 
470
        In reality, however, all processors probably have an atomic read of
 
471
        a memory word. */
 
472
 
 
473
spin_loop:
 
474
        ut_d(mutex->count_spin_loop++);
 
475
 
 
476
        while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS) {
 
477
                if (srv_spin_wait_delay) {
 
478
                        ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
 
479
                }
 
480
 
 
481
                i++;
 
482
        }
 
483
 
 
484
        if (i == SYNC_SPIN_ROUNDS) {
 
485
#ifdef UNIV_DEBUG
 
486
                mutex->count_os_yield++;
 
487
#ifndef UNIV_HOTBACKUP
 
488
                if (timed_mutexes && timer_started == 0) {
 
489
                        ut_usectime(&sec, &ms);
 
490
                        lstart_time= (ib_int64_t)sec * 1000000 + ms;
 
491
                        timer_started = 1;
 
492
                }
 
493
#endif /* UNIV_HOTBACKUP */
 
494
#endif /* UNIV_DEBUG */
 
495
                os_thread_yield();
 
496
        }
 
497
 
 
498
#ifdef UNIV_SRV_PRINT_LATCH_WAITS
 
499
        fprintf(stderr,
 
500
                "Thread %lu spin wait mutex at %p"
 
501
                " cfile %s cline %lu rnds %lu\n",
 
502
                (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex,
 
503
                mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
 
504
#endif
 
505
 
 
506
        mutex_spin_round_count += i;
 
507
 
 
508
        ut_d(mutex->count_spin_rounds += i);
 
509
 
 
510
        if (mutex_test_and_set(mutex) == 0) {
 
511
                /* Succeeded! */
 
512
 
 
513
                ut_d(mutex->thread_id = os_thread_get_curr_id());
 
514
#ifdef UNIV_SYNC_DEBUG
 
515
                mutex_set_debug_info(mutex, file_name, line);
 
516
#endif
 
517
 
 
518
                goto finish_timing;
 
519
        }
 
520
 
 
521
        /* We may end up with a situation where lock_word is 0 but the OS
 
522
        fast mutex is still reserved. On FreeBSD the OS does not seem to
 
523
        schedule a thread which is constantly calling pthread_mutex_trylock
 
524
        (in mutex_test_and_set implementation). Then we could end up
 
525
        spinning here indefinitely. The following 'i++' stops this infinite
 
526
        spin. */
 
527
 
 
528
        i++;
 
529
 
 
530
        if (i < SYNC_SPIN_ROUNDS) {
 
531
                goto spin_loop;
 
532
        }
 
533
 
 
534
        sync_array_reserve_cell(sync_primary_wait_array, mutex,
 
535
                                SYNC_MUTEX, file_name, line, &index);
 
536
 
 
537
        /* The memory order of the array reservation and the change in the
 
538
        waiters field is important: when we suspend a thread, we first
 
539
        reserve the cell and then set waiters field to 1. When threads are
 
540
        released in mutex_exit, the waiters field is first set to zero and
 
541
        then the event is set to the signaled state. */
 
542
 
 
543
        mutex_set_waiters(mutex, 1);
 
544
 
 
545
        /* Try to reserve still a few times */
 
546
        for (i = 0; i < 4; i++) {
 
547
                if (mutex_test_and_set(mutex) == 0) {
 
548
                        /* Succeeded! Free the reserved wait cell */
 
549
 
 
550
                        sync_array_free_cell(sync_primary_wait_array, index);
 
551
 
 
552
                        ut_d(mutex->thread_id = os_thread_get_curr_id());
 
553
#ifdef UNIV_SYNC_DEBUG
 
554
                        mutex_set_debug_info(mutex, file_name, line);
 
555
#endif
 
556
 
 
557
#ifdef UNIV_SRV_PRINT_LATCH_WAITS
 
558
                        fprintf(stderr, "Thread %lu spin wait succeeds at 2:"
 
559
                                " mutex at %p\n",
 
560
                                (ulong) os_thread_pf(os_thread_get_curr_id()),
 
561
                                (void*) mutex);
 
562
#endif
 
563
 
 
564
                        goto finish_timing;
 
565
 
 
566
                        /* Note that in this case we leave the waiters field
 
567
                        set to 1. We cannot reset it to zero, as we do not
 
568
                        know if there are other waiters. */
 
569
                }
 
570
        }
 
571
 
 
572
        /* Now we know that there has been some thread holding the mutex
 
573
        after the change in the wait array and the waiters field was made.
 
574
        Now there is no risk of infinite wait on the event. */
 
575
 
 
576
#ifdef UNIV_SRV_PRINT_LATCH_WAITS
 
577
        fprintf(stderr,
 
578
                "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
 
579
                (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex,
 
580
                mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
 
581
#endif
 
582
 
 
583
        mutex_os_wait_count++;
 
584
 
 
585
        mutex->count_os_wait++;
 
586
#ifdef UNIV_DEBUG
 
587
        /* !!!!! Sometimes os_wait can be called without os_thread_yield */
 
588
#ifndef UNIV_HOTBACKUP
 
589
        if (timed_mutexes == 1 && timer_started == 0) {
 
590
                ut_usectime(&sec, &ms);
 
591
                lstart_time= (ib_int64_t)sec * 1000000 + ms;
 
592
                timer_started = 1;
 
593
        }
 
594
#endif /* UNIV_HOTBACKUP */
 
595
#endif /* UNIV_DEBUG */
 
596
 
 
597
        sync_array_wait_event(sync_primary_wait_array, index);
 
598
        goto mutex_loop;
 
599
 
 
600
finish_timing:
 
601
#ifdef UNIV_DEBUG
 
602
        if (timed_mutexes == 1 && timer_started==1) {
 
603
                ut_usectime(&sec, &ms);
 
604
                lfinish_time= (ib_int64_t)sec * 1000000 + ms;
 
605
 
 
606
                ltime_diff= (ulint) (lfinish_time - lstart_time);
 
607
                mutex->lspent_time += ltime_diff;
 
608
 
 
609
                if (mutex->lmax_spent_time < ltime_diff) {
 
610
                        mutex->lmax_spent_time= ltime_diff;
 
611
                }
 
612
        }
 
613
#endif /* UNIV_DEBUG */
 
614
        return;
 
615
}
 
616
 
 
617
/******************************************************************//**
 
618
Releases the threads waiting in the primary wait array for this mutex. */
 
619
UNIV_INTERN
 
620
void
 
621
mutex_signal_object(
 
622
/*================*/
 
623
        mutex_t*        mutex)  /*!< in: mutex */
 
624
{
 
625
        mutex_set_waiters(mutex, 0);
 
626
 
 
627
        /* The memory order of resetting the waiters field and
 
628
        signaling the object is important. See LEMMA 1 above. */
 
629
        os_event_set(mutex->event);
 
630
        sync_array_object_signalled(sync_primary_wait_array);
 
631
}
 
632
 
 
633
#ifdef UNIV_SYNC_DEBUG
 
634
/******************************************************************//**
 
635
Sets the debug information for a reserved mutex. */
 
636
UNIV_INTERN
 
637
void
 
638
mutex_set_debug_info(
 
639
/*=================*/
 
640
        mutex_t*        mutex,          /*!< in: mutex */
 
641
        const char*     file_name,      /*!< in: file where requested */
 
642
        ulint           line)           /*!< in: line where requested */
 
643
{
 
644
        ut_ad(mutex);
 
645
        ut_ad(file_name);
 
646
 
 
647
        sync_thread_add_level(mutex, mutex->level);
 
648
 
 
649
        mutex->file_name = file_name;
 
650
        mutex->line      = line;
 
651
}
 
652
 
 
653
/******************************************************************//**
 
654
Gets the debug information for a reserved mutex. */
 
655
UNIV_INTERN
 
656
void
 
657
mutex_get_debug_info(
 
658
/*=================*/
 
659
        mutex_t*        mutex,          /*!< in: mutex */
 
660
        const char**    file_name,      /*!< out: file where requested */
 
661
        ulint*          line,           /*!< out: line where requested */
 
662
        os_thread_id_t* thread_id)      /*!< out: id of the thread which owns
 
663
                                        the mutex */
 
664
{
 
665
        ut_ad(mutex);
 
666
 
 
667
        *file_name = mutex->file_name;
 
668
        *line      = mutex->line;
 
669
        *thread_id = mutex->thread_id;
 
670
}
 
671
 
 
672
/******************************************************************//**
 
673
Prints debug info of currently reserved mutexes. */
 
674
static
 
675
void
 
676
mutex_list_print_info(
 
677
/*==================*/
 
678
        FILE*   file)           /*!< in: file where to print */
 
679
{
 
680
        mutex_t*        mutex;
 
681
        const char*     file_name;
 
682
        ulint           line;
 
683
        os_thread_id_t  thread_id;
 
684
        ulint           count           = 0;
 
685
 
 
686
        fputs("----------\n"
 
687
              "MUTEX INFO\n"
 
688
              "----------\n", file);
 
689
 
 
690
        mutex_enter(&mutex_list_mutex);
 
691
 
 
692
        mutex = UT_LIST_GET_FIRST(mutex_list);
 
693
 
 
694
        while (mutex != NULL) {
 
695
                count++;
 
696
 
 
697
                if (mutex_get_lock_word(mutex) != 0) {
 
698
                        mutex_get_debug_info(mutex, &file_name, &line,
 
699
                                             &thread_id);
 
700
                        fprintf(file,
 
701
                                "Locked mutex: addr %p thread %ld"
 
702
                                " file %s line %ld\n",
 
703
                                (void*) mutex, os_thread_pf(thread_id),
 
704
                                file_name, line);
 
705
                }
 
706
 
 
707
                mutex = UT_LIST_GET_NEXT(list, mutex);
 
708
        }
 
709
 
 
710
        fprintf(file, "Total number of mutexes %ld\n", count);
 
711
 
 
712
        mutex_exit(&mutex_list_mutex);
 
713
}
 
714
 
 
715
/******************************************************************//**
 
716
Counts currently reserved mutexes. Works only in the debug version.
 
717
@return number of reserved mutexes */
 
718
UNIV_INTERN
 
719
ulint
 
720
mutex_n_reserved(void)
 
721
/*==================*/
 
722
{
 
723
        mutex_t*        mutex;
 
724
        ulint           count           = 0;
 
725
 
 
726
        mutex_enter(&mutex_list_mutex);
 
727
 
 
728
        mutex = UT_LIST_GET_FIRST(mutex_list);
 
729
 
 
730
        while (mutex != NULL) {
 
731
                if (mutex_get_lock_word(mutex) != 0) {
 
732
 
 
733
                        count++;
 
734
                }
 
735
 
 
736
                mutex = UT_LIST_GET_NEXT(list, mutex);
 
737
        }
 
738
 
 
739
        mutex_exit(&mutex_list_mutex);
 
740
 
 
741
        ut_a(count >= 1);
 
742
 
 
743
        return(count - 1); /* Subtract one, because this function itself
 
744
                           was holding one mutex (mutex_list_mutex) */
 
745
}
 
746
 
 
747
/******************************************************************//**
 
748
Returns TRUE if no mutex or rw-lock is currently locked. Works only in
 
749
the debug version.
 
750
@return TRUE if no mutexes and rw-locks reserved */
 
751
UNIV_INTERN
 
752
ibool
 
753
sync_all_freed(void)
 
754
/*================*/
 
755
{
 
756
        return(mutex_n_reserved() + rw_lock_n_locked() == 0);
 
757
}
 
758
 
 
759
/******************************************************************//**
 
760
Gets the value in the nth slot in the thread level arrays.
 
761
@return pointer to thread slot */
 
762
static
 
763
sync_thread_t*
 
764
sync_thread_level_arrays_get_nth(
 
765
/*=============================*/
 
766
        ulint   n)      /*!< in: slot number */
 
767
{
 
768
        ut_ad(n < OS_THREAD_MAX_N);
 
769
 
 
770
        return(sync_thread_level_arrays + n);
 
771
}
 
772
 
 
773
/******************************************************************//**
 
774
Looks for the thread slot for the calling thread.
 
775
@return pointer to thread slot, NULL if not found */
 
776
static
 
777
sync_thread_t*
 
778
sync_thread_level_arrays_find_slot(void)
 
779
/*====================================*/
 
780
 
 
781
{
 
782
        sync_thread_t*  slot;
 
783
        os_thread_id_t  id;
 
784
        ulint           i;
 
785
 
 
786
        id = os_thread_get_curr_id();
 
787
 
 
788
        for (i = 0; i < OS_THREAD_MAX_N; i++) {
 
789
 
 
790
                slot = sync_thread_level_arrays_get_nth(i);
 
791
 
 
792
                if (slot->levels && os_thread_eq(slot->id, id)) {
 
793
 
 
794
                        return(slot);
 
795
                }
 
796
        }
 
797
 
 
798
        return(NULL);
 
799
}
 
800
 
 
801
/******************************************************************//**
 
802
Looks for an unused thread slot.
 
803
@return pointer to thread slot */
 
804
static
 
805
sync_thread_t*
 
806
sync_thread_level_arrays_find_free(void)
 
807
/*====================================*/
 
808
 
 
809
{
 
810
        sync_thread_t*  slot;
 
811
        ulint           i;
 
812
 
 
813
        for (i = 0; i < OS_THREAD_MAX_N; i++) {
 
814
 
 
815
                slot = sync_thread_level_arrays_get_nth(i);
 
816
 
 
817
                if (slot->levels == NULL) {
 
818
 
 
819
                        return(slot);
 
820
                }
 
821
        }
 
822
 
 
823
        return(NULL);
 
824
}
 
825
 
 
826
/******************************************************************//**
 
827
Gets the value in the nth slot in the thread level array.
 
828
@return pointer to level slot */
 
829
static
 
830
sync_level_t*
 
831
sync_thread_levels_get_nth(
 
832
/*=======================*/
 
833
        sync_level_t*   arr,    /*!< in: pointer to level array for an OS
 
834
                                thread */
 
835
        ulint           n)      /*!< in: slot number */
 
836
{
 
837
        ut_ad(n < SYNC_THREAD_N_LEVELS);
 
838
 
 
839
        return(arr + n);
 
840
}
 
841
 
 
842
/******************************************************************//**
 
843
Checks if all the level values stored in the level array are greater than
 
844
the given limit.
 
845
@return TRUE if all greater */
 
846
static
 
847
ibool
 
848
sync_thread_levels_g(
 
849
/*=================*/
 
850
        sync_level_t*   arr,    /*!< in: pointer to level array for an OS
 
851
                                thread */
 
852
        ulint           limit)  /*!< in: level limit */
 
853
{
 
854
        sync_level_t*   slot;
 
855
        rw_lock_t*      lock;
 
856
        mutex_t*        mutex;
 
857
        ulint           i;
 
858
 
 
859
        for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
 
860
 
 
861
                slot = sync_thread_levels_get_nth(arr, i);
 
862
 
 
863
                if (slot->latch != NULL) {
 
864
                        if (slot->level <= limit) {
 
865
 
 
866
                                lock = slot->latch;
 
867
                                mutex = slot->latch;
 
868
 
 
869
                                fprintf(stderr,
 
870
                                        "InnoDB: sync levels should be"
 
871
                                        " > %lu but a level is %lu\n",
 
872
                                        (ulong) limit, (ulong) slot->level);
 
873
 
 
874
                                if (mutex->magic_n == MUTEX_MAGIC_N) {
 
875
                                        fprintf(stderr,
 
876
                                                "Mutex created at %s %lu\n",
 
877
                                                mutex->cfile_name,
 
878
                                                (ulong) mutex->cline);
 
879
 
 
880
                                        if (mutex_get_lock_word(mutex) != 0) {
 
881
                                                const char*     file_name;
 
882
                                                ulint           line;
 
883
                                                os_thread_id_t  thread_id;
 
884
 
 
885
                                                mutex_get_debug_info(
 
886
                                                        mutex, &file_name,
 
887
                                                        &line, &thread_id);
 
888
 
 
889
                                                fprintf(stderr,
 
890
                                                        "InnoDB: Locked mutex:"
 
891
                                                        " addr %p thread %ld"
 
892
                                                        " file %s line %ld\n",
 
893
                                                        (void*) mutex,
 
894
                                                        os_thread_pf(
 
895
                                                                thread_id),
 
896
                                                        file_name,
 
897
                                                        (ulong) line);
 
898
                                        } else {
 
899
                                                fputs("Not locked\n", stderr);
 
900
                                        }
 
901
                                } else {
 
902
                                        rw_lock_print(lock);
 
903
                                }
 
904
 
 
905
                                return(FALSE);
 
906
                        }
 
907
                }
 
908
        }
 
909
 
 
910
        return(TRUE);
 
911
}
 
912
 
 
913
/******************************************************************//**
 
914
Checks if the level value is stored in the level array.
 
915
@return TRUE if stored */
 
916
static
 
917
ibool
 
918
sync_thread_levels_contain(
 
919
/*=======================*/
 
920
        sync_level_t*   arr,    /*!< in: pointer to level array for an OS
 
921
                                thread */
 
922
        ulint           level)  /*!< in: level */
 
923
{
 
924
        sync_level_t*   slot;
 
925
        ulint           i;
 
926
 
 
927
        for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
 
928
 
 
929
                slot = sync_thread_levels_get_nth(arr, i);
 
930
 
 
931
                if (slot->latch != NULL) {
 
932
                        if (slot->level == level) {
 
933
 
 
934
                                return(TRUE);
 
935
                        }
 
936
                }
 
937
        }
 
938
 
 
939
        return(FALSE);
 
940
}
 
941
 
 
942
/******************************************************************//**
 
943
Checks that the level array for the current thread is empty.
 
944
@return TRUE if empty except the exceptions specified below */
 
945
UNIV_INTERN
 
946
ibool
 
947
sync_thread_levels_empty_gen(
 
948
/*=========================*/
 
949
        ibool   dict_mutex_allowed)     /*!< in: TRUE if dictionary mutex is
 
950
                                        allowed to be owned by the thread,
 
951
                                        also purge_is_running mutex is
 
952
                                        allowed */
 
953
{
 
954
        sync_level_t*   arr;
 
955
        sync_thread_t*  thread_slot;
 
956
        sync_level_t*   slot;
 
957
        ulint           i;
 
958
 
 
959
        if (!sync_order_checks_on) {
 
960
 
 
961
                return(TRUE);
 
962
        }
 
963
 
 
964
        mutex_enter(&sync_thread_mutex);
 
965
 
 
966
        thread_slot = sync_thread_level_arrays_find_slot();
 
967
 
 
968
        if (thread_slot == NULL) {
 
969
 
 
970
                mutex_exit(&sync_thread_mutex);
 
971
 
 
972
                return(TRUE);
 
973
        }
 
974
 
 
975
        arr = thread_slot->levels;
 
976
 
 
977
        for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
 
978
 
 
979
                slot = sync_thread_levels_get_nth(arr, i);
 
980
 
 
981
                if (slot->latch != NULL
 
982
                    && (!dict_mutex_allowed
 
983
                        || (slot->level != SYNC_DICT
 
984
                            && slot->level != SYNC_DICT_OPERATION))) {
 
985
 
 
986
                        mutex_exit(&sync_thread_mutex);
 
987
                        ut_error;
 
988
 
 
989
                        return(FALSE);
 
990
                }
 
991
        }
 
992
 
 
993
        mutex_exit(&sync_thread_mutex);
 
994
 
 
995
        return(TRUE);
 
996
}
 
997
 
 
998
/******************************************************************//**
 
999
Checks that the level array for the current thread is empty.
 
1000
@return TRUE if empty */
 
1001
UNIV_INTERN
 
1002
ibool
 
1003
sync_thread_levels_empty(void)
 
1004
/*==========================*/
 
1005
{
 
1006
        return(sync_thread_levels_empty_gen(FALSE));
 
1007
}
 
1008
 
 
1009
/******************************************************************//**
 
1010
Adds a latch and its level in the thread level array. Allocates the memory
 
1011
for the array if called first time for this OS thread. Makes the checks
 
1012
against other latch levels stored in the array for this thread. */
 
1013
UNIV_INTERN
 
1014
void
 
1015
sync_thread_add_level(
 
1016
/*==================*/
 
1017
        void*   latch,  /*!< in: pointer to a mutex or an rw-lock */
 
1018
        ulint   level)  /*!< in: level in the latching order; if
 
1019
                        SYNC_LEVEL_VARYING, nothing is done */
 
1020
{
 
1021
        sync_level_t*   array;
 
1022
        sync_level_t*   slot;
 
1023
        sync_thread_t*  thread_slot;
 
1024
        ulint           i;
 
1025
 
 
1026
        if (!sync_order_checks_on) {
 
1027
 
 
1028
                return;
 
1029
        }
 
1030
 
 
1031
        if ((latch == (void*)&sync_thread_mutex)
 
1032
            || (latch == (void*)&mutex_list_mutex)
 
1033
            || (latch == (void*)&rw_lock_debug_mutex)
 
1034
            || (latch == (void*)&rw_lock_list_mutex)) {
 
1035
 
 
1036
                return;
 
1037
        }
 
1038
 
 
1039
        if (level == SYNC_LEVEL_VARYING) {
 
1040
 
 
1041
                return;
 
1042
        }
 
1043
 
 
1044
        mutex_enter(&sync_thread_mutex);
 
1045
 
 
1046
        thread_slot = sync_thread_level_arrays_find_slot();
 
1047
 
 
1048
        if (thread_slot == NULL) {
 
1049
                /* We have to allocate the level array for a new thread */
 
1050
                array = ut_malloc(sizeof(sync_level_t) * SYNC_THREAD_N_LEVELS);
 
1051
 
 
1052
                thread_slot = sync_thread_level_arrays_find_free();
 
1053
 
 
1054
                thread_slot->id = os_thread_get_curr_id();
 
1055
                thread_slot->levels = array;
 
1056
 
 
1057
                for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
 
1058
 
 
1059
                        slot = sync_thread_levels_get_nth(array, i);
 
1060
 
 
1061
                        slot->latch = NULL;
 
1062
                }
 
1063
        }
 
1064
 
 
1065
        array = thread_slot->levels;
 
1066
 
 
1067
        /* NOTE that there is a problem with _NODE and _LEAF levels: if the
 
1068
        B-tree height changes, then a leaf can change to an internal node
 
1069
        or the other way around. We do not know at present if this can cause
 
1070
        unnecessary assertion failures below. */
 
1071
 
 
1072
        switch (level) {
 
1073
        case SYNC_NO_ORDER_CHECK:
 
1074
        case SYNC_EXTERN_STORAGE:
 
1075
        case SYNC_TREE_NODE_FROM_HASH:
 
1076
                /* Do no order checking */
 
1077
                break;
 
1078
        case SYNC_MEM_POOL:
 
1079
        case SYNC_MEM_HASH:
 
1080
        case SYNC_RECV:
 
1081
        case SYNC_WORK_QUEUE:
 
1082
        case SYNC_LOG:
 
1083
        case SYNC_THR_LOCAL:
 
1084
        case SYNC_ANY_LATCH:
 
1085
        case SYNC_TRX_SYS_HEADER:
 
1086
        case SYNC_FILE_FORMAT_TAG:
 
1087
        case SYNC_DOUBLEWRITE:
 
1088
        case SYNC_BUF_POOL:
 
1089
        case SYNC_SEARCH_SYS:
 
1090
        case SYNC_SEARCH_SYS_CONF:
 
1091
        case SYNC_TRX_LOCK_HEAP:
 
1092
        case SYNC_KERNEL:
 
1093
        case SYNC_IBUF_BITMAP_MUTEX:
 
1094
        case SYNC_RSEG:
 
1095
        case SYNC_TRX_UNDO:
 
1096
        case SYNC_PURGE_LATCH:
 
1097
        case SYNC_PURGE_SYS:
 
1098
        case SYNC_DICT_AUTOINC_MUTEX:
 
1099
        case SYNC_DICT_OPERATION:
 
1100
        case SYNC_DICT_HEADER:
 
1101
        case SYNC_TRX_I_S_RWLOCK:
 
1102
        case SYNC_TRX_I_S_LAST_READ:
 
1103
                if (!sync_thread_levels_g(array, level)) {
 
1104
                        fprintf(stderr,
 
1105
                                "InnoDB: sync_thread_levels_g(array, %lu)"
 
1106
                                " does not hold!\n", level);
 
1107
                        ut_error;
 
1108
                }
 
1109
                break;
 
1110
        case SYNC_BUF_BLOCK:
 
1111
                /* Either the thread must own the buffer pool mutex
 
1112
                (buf_pool_mutex), or it is allowed to latch only ONE
 
1113
                buffer block (block->mutex or buf_pool_zip_mutex). */
 
1114
                if (!sync_thread_levels_g(array, level)) {
 
1115
                        ut_a(sync_thread_levels_g(array, level - 1));
 
1116
                        ut_a(sync_thread_levels_contain(array, SYNC_BUF_POOL));
 
1117
                }
 
1118
                break;
 
1119
        case SYNC_REC_LOCK:
 
1120
                ut_a((sync_thread_levels_contain(array, SYNC_KERNEL)
 
1121
                      && sync_thread_levels_g(array, SYNC_REC_LOCK - 1))
 
1122
                     || sync_thread_levels_g(array, SYNC_REC_LOCK));
 
1123
                break;
 
1124
        case SYNC_IBUF_BITMAP:
 
1125
                /* Either the thread must own the master mutex to all
 
1126
                the bitmap pages, or it is allowed to latch only ONE
 
1127
                bitmap page. */
 
1128
                ut_a((sync_thread_levels_contain(array, SYNC_IBUF_BITMAP_MUTEX)
 
1129
                      && sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1))
 
1130
                     || sync_thread_levels_g(array, SYNC_IBUF_BITMAP));
 
1131
                break;
 
1132
        case SYNC_FSP_PAGE:
 
1133
                ut_a(sync_thread_levels_contain(array, SYNC_FSP));
 
1134
                break;
 
1135
        case SYNC_FSP:
 
1136
                ut_a(sync_thread_levels_contain(array, SYNC_FSP)
 
1137
                     || sync_thread_levels_g(array, SYNC_FSP));
 
1138
                break;
 
1139
        case SYNC_TRX_UNDO_PAGE:
 
1140
                ut_a(sync_thread_levels_contain(array, SYNC_TRX_UNDO)
 
1141
                     || sync_thread_levels_contain(array, SYNC_RSEG)
 
1142
                     || sync_thread_levels_contain(array, SYNC_PURGE_SYS)
 
1143
                     || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE));
 
1144
                break;
 
1145
        case SYNC_RSEG_HEADER:
 
1146
                ut_a(sync_thread_levels_contain(array, SYNC_RSEG));
 
1147
                break;
 
1148
        case SYNC_RSEG_HEADER_NEW:
 
1149
                ut_a(sync_thread_levels_contain(array, SYNC_KERNEL)
 
1150
                     && sync_thread_levels_contain(array, SYNC_FSP_PAGE));
 
1151
                break;
 
1152
        case SYNC_TREE_NODE:
 
1153
                ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE)
 
1154
                     || sync_thread_levels_contain(array, SYNC_DICT_OPERATION)
 
1155
                     || sync_thread_levels_g(array, SYNC_TREE_NODE - 1));
 
1156
                break;
 
1157
        case SYNC_TREE_NODE_NEW:
 
1158
                ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE)
 
1159
                     || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
 
1160
                break;
 
1161
        case SYNC_INDEX_TREE:
 
1162
                ut_a((sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)
 
1163
                      && sync_thread_levels_contain(array, SYNC_FSP)
 
1164
                      && sync_thread_levels_g(array, SYNC_FSP_PAGE - 1))
 
1165
                     || sync_thread_levels_g(array, SYNC_TREE_NODE - 1));
 
1166
                break;
 
1167
        case SYNC_IBUF_MUTEX:
 
1168
                ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1));
 
1169
                break;
 
1170
        case SYNC_IBUF_PESS_INSERT_MUTEX:
 
1171
                ut_a(sync_thread_levels_g(array, SYNC_FSP - 1)
 
1172
                     && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
 
1173
                break;
 
1174
        case SYNC_IBUF_HEADER:
 
1175
                ut_a(sync_thread_levels_g(array, SYNC_FSP - 1)
 
1176
                     && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)
 
1177
                     && !sync_thread_levels_contain(
 
1178
                             array, SYNC_IBUF_PESS_INSERT_MUTEX));
 
1179
                break;
 
1180
        case SYNC_DICT:
 
1181
#ifdef UNIV_DEBUG
 
1182
                ut_a(buf_debug_prints
 
1183
                     || sync_thread_levels_g(array, SYNC_DICT));
 
1184
#else /* UNIV_DEBUG */
 
1185
                ut_a(sync_thread_levels_g(array, SYNC_DICT));
 
1186
#endif /* UNIV_DEBUG */
 
1187
                break;
 
1188
        default:
 
1189
                ut_error;
 
1190
        }
 
1191
 
 
1192
        for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
 
1193
 
 
1194
                slot = sync_thread_levels_get_nth(array, i);
 
1195
 
 
1196
                if (slot->latch == NULL) {
 
1197
                        slot->latch = latch;
 
1198
                        slot->level = level;
 
1199
 
 
1200
                        break;
 
1201
                }
 
1202
        }
 
1203
 
 
1204
        ut_a(i < SYNC_THREAD_N_LEVELS);
 
1205
 
 
1206
        mutex_exit(&sync_thread_mutex);
 
1207
}
 
1208
 
 
1209
/******************************************************************//**
 
1210
Removes a latch from the thread level array if it is found there.
 
1211
@return TRUE if found in the array; it is no error if the latch is
 
1212
not found, as we presently are not able to determine the level for
 
1213
every latch reservation the program does */
 
1214
UNIV_INTERN
 
1215
ibool
 
1216
sync_thread_reset_level(
 
1217
/*====================*/
 
1218
        void*   latch)  /*!< in: pointer to a mutex or an rw-lock */
 
1219
{
 
1220
        sync_level_t*   array;
 
1221
        sync_level_t*   slot;
 
1222
        sync_thread_t*  thread_slot;
 
1223
        ulint           i;
 
1224
 
 
1225
        if (!sync_order_checks_on) {
 
1226
 
 
1227
                return(FALSE);
 
1228
        }
 
1229
 
 
1230
        if ((latch == (void*)&sync_thread_mutex)
 
1231
            || (latch == (void*)&mutex_list_mutex)
 
1232
            || (latch == (void*)&rw_lock_debug_mutex)
 
1233
            || (latch == (void*)&rw_lock_list_mutex)) {
 
1234
 
 
1235
                return(FALSE);
 
1236
        }
 
1237
 
 
1238
        mutex_enter(&sync_thread_mutex);
 
1239
 
 
1240
        thread_slot = sync_thread_level_arrays_find_slot();
 
1241
 
 
1242
        if (thread_slot == NULL) {
 
1243
 
 
1244
                ut_error;
 
1245
 
 
1246
                mutex_exit(&sync_thread_mutex);
 
1247
                return(FALSE);
 
1248
        }
 
1249
 
 
1250
        array = thread_slot->levels;
 
1251
 
 
1252
        for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
 
1253
 
 
1254
                slot = sync_thread_levels_get_nth(array, i);
 
1255
 
 
1256
                if (slot->latch == latch) {
 
1257
                        slot->latch = NULL;
 
1258
 
 
1259
                        mutex_exit(&sync_thread_mutex);
 
1260
 
 
1261
                        return(TRUE);
 
1262
                }
 
1263
        }
 
1264
 
 
1265
        if (((mutex_t*) latch)->magic_n != MUTEX_MAGIC_N) {
 
1266
                rw_lock_t*      rw_lock;
 
1267
 
 
1268
                rw_lock = (rw_lock_t*) latch;
 
1269
 
 
1270
                if (rw_lock->level == SYNC_LEVEL_VARYING) {
 
1271
                        mutex_exit(&sync_thread_mutex);
 
1272
 
 
1273
                        return(TRUE);
 
1274
                }
 
1275
        }
 
1276
 
 
1277
        ut_error;
 
1278
 
 
1279
        mutex_exit(&sync_thread_mutex);
 
1280
 
 
1281
        return(FALSE);
 
1282
}
 
1283
#endif /* UNIV_SYNC_DEBUG */
 
1284
 
 
1285
/******************************************************************//**
 
1286
Initializes the synchronization data structures. */
 
1287
UNIV_INTERN
 
1288
void
 
1289
sync_init(void)
 
1290
/*===========*/
 
1291
{
 
1292
#ifdef UNIV_SYNC_DEBUG
 
1293
        sync_thread_t*  thread_slot;
 
1294
        ulint           i;
 
1295
#endif /* UNIV_SYNC_DEBUG */
 
1296
 
 
1297
        ut_a(sync_initialized == FALSE);
 
1298
 
 
1299
        sync_initialized = TRUE;
 
1300
 
 
1301
        /* Create the primary system wait array which is protected by an OS
 
1302
        mutex */
 
1303
 
 
1304
        sync_primary_wait_array = sync_array_create(OS_THREAD_MAX_N,
 
1305
                                                    SYNC_ARRAY_OS_MUTEX);
 
1306
#ifdef UNIV_SYNC_DEBUG
 
1307
        /* Create the thread latch level array where the latch levels
 
1308
        are stored for each OS thread */
 
1309
 
 
1310
        sync_thread_level_arrays = ut_malloc(OS_THREAD_MAX_N
 
1311
                                             * sizeof(sync_thread_t));
 
1312
        for (i = 0; i < OS_THREAD_MAX_N; i++) {
 
1313
 
 
1314
                thread_slot = sync_thread_level_arrays_get_nth(i);
 
1315
                thread_slot->levels = NULL;
 
1316
        }
 
1317
#endif /* UNIV_SYNC_DEBUG */
 
1318
        /* Init the mutex list and create the mutex to protect it. */
 
1319
 
 
1320
        UT_LIST_INIT(mutex_list);
 
1321
        mutex_create(&mutex_list_mutex, SYNC_NO_ORDER_CHECK);
 
1322
#ifdef UNIV_SYNC_DEBUG
 
1323
        mutex_create(&sync_thread_mutex, SYNC_NO_ORDER_CHECK);
 
1324
#endif /* UNIV_SYNC_DEBUG */
 
1325
 
 
1326
        /* Init the rw-lock list and create the mutex to protect it. */
 
1327
 
 
1328
        UT_LIST_INIT(rw_lock_list);
 
1329
        mutex_create(&rw_lock_list_mutex, SYNC_NO_ORDER_CHECK);
 
1330
 
 
1331
#ifdef UNIV_SYNC_DEBUG
 
1332
        mutex_create(&rw_lock_debug_mutex, SYNC_NO_ORDER_CHECK);
 
1333
 
 
1334
        rw_lock_debug_event = os_event_create(NULL);
 
1335
        rw_lock_debug_waiters = FALSE;
 
1336
#endif /* UNIV_SYNC_DEBUG */
 
1337
}
 
1338
 
 
1339
/******************************************************************//**
 
1340
Frees the resources in InnoDB's own synchronization data structures. Use
 
1341
os_sync_free() after calling this. */
 
1342
UNIV_INTERN
 
1343
void
 
1344
sync_close(void)
 
1345
/*===========*/
 
1346
{
 
1347
        mutex_t*        mutex;
 
1348
 
 
1349
        sync_array_free(sync_primary_wait_array);
 
1350
 
 
1351
        mutex = UT_LIST_GET_FIRST(mutex_list);
 
1352
 
 
1353
        while (mutex) {
 
1354
                mutex_free(mutex);
 
1355
                mutex = UT_LIST_GET_FIRST(mutex_list);
 
1356
        }
 
1357
 
 
1358
        mutex_free(&mutex_list_mutex);
 
1359
#ifdef UNIV_SYNC_DEBUG
 
1360
        mutex_free(&sync_thread_mutex);
 
1361
#endif /* UNIV_SYNC_DEBUG */
 
1362
}
 
1363
 
 
1364
/*******************************************************************//**
 
1365
Prints wait info of the sync system. */
 
1366
UNIV_INTERN
 
1367
void
 
1368
sync_print_wait_info(
 
1369
/*=================*/
 
1370
        FILE*   file)           /*!< in: file where to print */
 
1371
{
 
1372
#ifdef UNIV_SYNC_DEBUG
 
1373
        fprintf(file, "Mutex exits %llu, rws exits %llu, rwx exits %llu\n",
 
1374
                mutex_exit_count, rw_s_exit_count, rw_x_exit_count);
 
1375
#endif
 
1376
 
 
1377
        fprintf(file,
 
1378
                "Mutex spin waits %"PRId64", rounds %"PRId64", "
 
1379
                "OS waits %"PRId64"\n"
 
1380
                "RW-shared spins %"PRId64", OS waits %"PRId64";"
 
1381
                " RW-excl spins %"PRId64", OS waits %"PRId64"\n",
 
1382
                mutex_spin_wait_count,
 
1383
                mutex_spin_round_count,
 
1384
                mutex_os_wait_count,
 
1385
                rw_s_spin_wait_count,
 
1386
                rw_s_os_wait_count,
 
1387
                rw_x_spin_wait_count,
 
1388
                rw_x_os_wait_count);
 
1389
 
 
1390
        fprintf(file,
 
1391
                "Spin rounds per wait: %.2f mutex, %.2f RW-shared, "
 
1392
                "%.2f RW-excl\n",
 
1393
                (double) mutex_spin_round_count /
 
1394
                (mutex_spin_wait_count ? mutex_spin_wait_count : 1),
 
1395
                (double) rw_s_spin_round_count /
 
1396
                (rw_s_spin_wait_count ? rw_s_spin_wait_count : 1),
 
1397
                (double) rw_x_spin_round_count /
 
1398
                (rw_x_spin_wait_count ? rw_x_spin_wait_count : 1));
 
1399
}
 
1400
 
 
1401
/*******************************************************************//**
 
1402
Prints info of the sync system. */
 
1403
UNIV_INTERN
 
1404
void
 
1405
sync_print(
 
1406
/*=======*/
 
1407
        FILE*   file)           /*!< in: file where to print */
 
1408
{
 
1409
#ifdef UNIV_SYNC_DEBUG
 
1410
        mutex_list_print_info(file);
 
1411
 
 
1412
        rw_lock_list_print_info(file);
 
1413
#endif /* UNIV_SYNC_DEBUG */
 
1414
 
 
1415
        sync_array_print_info(file, sync_primary_wait_array);
 
1416
 
 
1417
        sync_print_wait_info(file);
 
1418
}