~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Further drizzleclient cleanup. Starting to move all NET related functions into Protocol, removed some dead code, removing drizzleclient dependencies spread throughout drizzled.

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
 
}