~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Tags: innodb-plugin-1.0.1
Imported 1.0.1 with clean - with no changes.

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
}