~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-12-03 22:33:50 UTC
  • mfrom: (641.3.4 devel)
  • Revision ID: brian@tangent.org-20081203223350-vyckv6v4vphpogpy
Import of upated Innodb Engine

Show diffs side-by-side

added added

removed removed

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