~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

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
 
}