~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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