~ubuntu-branches/ubuntu/saucy/drizzle/saucy-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2011-01-04 09:31:58 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20110104093158-smhgvkfdi2y9au3i
Tags: 2011.01.07-0ubuntu1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
4
 
Copyright (C) 2008, Google Inc.
5
 
 
6
 
Portions of this file contain modifications contributed and copyrighted by
7
 
Google, Inc. Those modifications are gratefully acknowledged and are described
8
 
briefly in the InnoDB documentation. The contributions by Google are
9
 
incorporated with their permission, and subject to the conditions contained in
10
 
the file COPYING.Google.
11
 
 
12
 
This program is free software; you can redistribute it and/or modify it under
13
 
the terms of the GNU General Public License as published by the Free Software
14
 
Foundation; version 2 of the License.
15
 
 
16
 
This program is distributed in the hope that it will be useful, but WITHOUT
17
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19
 
 
20
 
You should have received a copy of the GNU General Public License along with
21
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22
 
St, Fifth Floor, Boston, MA 02110-1301 USA
23
 
 
24
 
*****************************************************************************/
25
 
 
26
 
/**************************************************//**
27
 
@file sync/sync0arr.c
28
 
The wait array used in synchronization primitives
29
 
 
30
 
Created 9/5/1995 Heikki Tuuri
31
 
*******************************************************/
32
 
 
33
 
#include "sync0arr.h"
34
 
#ifdef UNIV_NONINL
35
 
#include "sync0arr.ic"
36
 
#endif
37
 
 
38
 
#include "sync0sync.h"
39
 
#include "sync0rw.h"
40
 
#include "os0sync.h"
41
 
#include "os0file.h"
42
 
#include "srv0srv.h"
43
 
 
44
 
/*
45
 
                        WAIT ARRAY
46
 
                        ==========
47
 
 
48
 
The wait array consists of cells each of which has an
49
 
an operating system event object created for it. The threads
50
 
waiting for a mutex, for example, can reserve a cell
51
 
in the array and suspend themselves to wait for the event
52
 
to become signaled. When using the wait array, remember to make
53
 
sure that some thread holding the synchronization object
54
 
will eventually know that there is a waiter in the array and
55
 
signal the object, to prevent infinite wait.
56
 
Why we chose to implement a wait array? First, to make
57
 
mutexes fast, we had to code our own implementation of them,
58
 
which only in usually uncommon cases resorts to using
59
 
slow operating system primitives. Then we had the choice of
60
 
assigning a unique OS event for each mutex, which would
61
 
be simpler, or using a global wait array. In some operating systems,
62
 
the global wait array solution is more efficient and flexible,
63
 
because we can do with a very small number of OS events,
64
 
say 200. In NT 3.51, allocating events seems to be a quadratic
65
 
algorithm, because 10 000 events are created fast, but
66
 
100 000 events takes a couple of minutes to create.
67
 
 
68
 
As of 5.0.30 the above mentioned design is changed. Since now
69
 
OS can handle millions of wait events efficiently, we no longer
70
 
have this concept of each cell of wait array having one event.
71
 
Instead, now the event that a thread wants to wait on is embedded
72
 
in the wait object (mutex or rw_lock). We still keep the global
73
 
wait array for the sake of diagnostics and also to avoid infinite
74
 
wait The error_monitor thread scans the global wait array to signal
75
 
any waiting threads who have missed the signal. */
76
 
 
77
 
/** A cell where an individual thread may wait suspended
78
 
until a resource is released. The suspending is implemented
79
 
using an operating system event semaphore. */
80
 
struct sync_cell_struct {
81
 
        void*           wait_object;    /*!< pointer to the object the
82
 
                                        thread is waiting for; if NULL
83
 
                                        the cell is free for use */
84
 
        mutex_t*        old_wait_mutex; /*!< the latest wait mutex in cell */
85
 
        rw_lock_t*      old_wait_rw_lock;
86
 
                                        /*!< the latest wait rw-lock
87
 
                                        in cell */
88
 
        ulint           request_type;   /*!< lock type requested on the
89
 
                                        object */
90
 
        const char*     file;           /*!< in debug version file where
91
 
                                        requested */
92
 
        ulint           line;           /*!< in debug version line where
93
 
                                        requested */
94
 
        os_thread_id_t  thread;         /*!< thread id of this waiting
95
 
                                        thread */
96
 
        ibool           waiting;        /*!< TRUE if the thread has already
97
 
                                        called sync_array_event_wait
98
 
                                        on this cell */
99
 
        ib_int64_t      signal_count;   /*!< We capture the signal_count
100
 
                                        of the wait_object when we
101
 
                                        reset the event. This value is
102
 
                                        then passed on to os_event_wait
103
 
                                        and we wait only if the event
104
 
                                        has not been signalled in the
105
 
                                        period between the reset and
106
 
                                        wait call. */
107
 
        time_t          reservation_time;/*!< time when the thread reserved
108
 
                                        the wait cell */
109
 
};
110
 
 
111
 
/* NOTE: It is allowed for a thread to wait
112
 
for an event allocated for the array without owning the
113
 
protecting mutex (depending on the case: OS or database mutex), but
114
 
all changes (set or reset) to the state of the event must be made
115
 
while owning the mutex. */
116
 
 
117
 
/** Synchronization array */
118
 
struct sync_array_struct {
119
 
        ulint           n_reserved;     /*!< number of currently reserved
120
 
                                        cells in the wait array */
121
 
        ulint           n_cells;        /*!< number of cells in the
122
 
                                        wait array */
123
 
        sync_cell_t*    array;          /*!< pointer to wait array */
124
 
        ulint           protection;     /*!< this flag tells which
125
 
                                        mutex protects the data */
126
 
        mutex_t         mutex;          /*!< possible database mutex
127
 
                                        protecting this data structure */
128
 
        os_mutex_t      os_mutex;       /*!< Possible operating system mutex
129
 
                                        protecting the data structure.
130
 
                                        As this data structure is used in
131
 
                                        constructing the database mutex,
132
 
                                        to prevent infinite recursion
133
 
                                        in implementation, we fall back to
134
 
                                        an OS mutex. */
135
 
        ulint           sg_count;       /*!< count of how many times an
136
 
                                        object has been signalled */
137
 
        ulint           res_count;      /*!< count of cell reservations
138
 
                                        since creation of the array */
139
 
};
140
 
 
141
 
#ifdef UNIV_PFS_MUTEX
142
 
/* Key to register the mutex with performance schema */
143
 
UNIV_INTERN mysql_pfs_key_t     syn_arr_mutex_key;
144
 
#endif
145
 
 
146
 
#ifdef UNIV_SYNC_DEBUG
147
 
/******************************************************************//**
148
 
This function is called only in the debug version. Detects a deadlock
149
 
of one or more threads because of waits of semaphores.
150
 
@return TRUE if deadlock detected */
151
 
static
152
 
ibool
153
 
sync_array_detect_deadlock(
154
 
/*=======================*/
155
 
        sync_array_t*   arr,    /*!< in: wait array; NOTE! the caller must
156
 
                                own the mutex to array */
157
 
        sync_cell_t*    start,  /*!< in: cell where recursive search started */
158
 
        sync_cell_t*    cell,   /*!< in: cell to search */
159
 
        ulint           depth); /*!< in: recursion depth */
160
 
#endif /* UNIV_SYNC_DEBUG */
161
 
 
162
 
/*****************************************************************//**
163
 
Gets the nth cell in array.
164
 
@return cell */
165
 
static
166
 
sync_cell_t*
167
 
sync_array_get_nth_cell(
168
 
/*====================*/
169
 
        sync_array_t*   arr,    /*!< in: sync array */
170
 
        ulint           n)      /*!< in: index */
171
 
{
172
 
        ut_a(arr);
173
 
        ut_a(n < arr->n_cells);
174
 
 
175
 
        return(arr->array + n);
176
 
}
177
 
 
178
 
/******************************************************************//**
179
 
Reserves the mutex semaphore protecting a sync array. */
180
 
static
181
 
void
182
 
sync_array_enter(
183
 
/*=============*/
184
 
        sync_array_t*   arr)    /*!< in: sync wait array */
185
 
{
186
 
        ulint   protection;
187
 
 
188
 
        protection = arr->protection;
189
 
 
190
 
        if (protection == SYNC_ARRAY_OS_MUTEX) {
191
 
                os_mutex_enter(arr->os_mutex);
192
 
        } else if (protection == SYNC_ARRAY_MUTEX) {
193
 
                mutex_enter(&(arr->mutex));
194
 
        } else {
195
 
                ut_error;
196
 
        }
197
 
}
198
 
 
199
 
/******************************************************************//**
200
 
Releases the mutex semaphore protecting a sync array. */
201
 
static
202
 
void
203
 
sync_array_exit(
204
 
/*============*/
205
 
        sync_array_t*   arr)    /*!< in: sync wait array */
206
 
{
207
 
        ulint   protection;
208
 
 
209
 
        protection = arr->protection;
210
 
 
211
 
        if (protection == SYNC_ARRAY_OS_MUTEX) {
212
 
                os_mutex_exit(arr->os_mutex);
213
 
        } else if (protection == SYNC_ARRAY_MUTEX) {
214
 
                mutex_exit(&(arr->mutex));
215
 
        } else {
216
 
                ut_error;
217
 
        }
218
 
}
219
 
 
220
 
/*******************************************************************//**
221
 
Creates a synchronization wait array. It is protected by a mutex
222
 
which is automatically reserved when the functions operating on it
223
 
are called.
224
 
@return own: created wait array */
225
 
UNIV_INTERN
226
 
sync_array_t*
227
 
sync_array_create(
228
 
/*==============*/
229
 
        ulint   n_cells,        /*!< in: number of cells in the array
230
 
                                to create */
231
 
        ulint   protection)     /*!< in: either SYNC_ARRAY_OS_MUTEX or
232
 
                                SYNC_ARRAY_MUTEX: determines the type
233
 
                                of mutex protecting the data structure */
234
 
{
235
 
        ulint           sz;
236
 
        sync_array_t*   arr;
237
 
 
238
 
        ut_a(n_cells > 0);
239
 
 
240
 
        /* Allocate memory for the data structures */
241
 
        arr = ut_malloc(sizeof(sync_array_t));
242
 
        memset(arr, 0x0, sizeof(*arr));
243
 
 
244
 
        sz = sizeof(sync_cell_t) * n_cells;
245
 
        arr->array = ut_malloc(sz);
246
 
        memset(arr->array, 0x0, sz);
247
 
 
248
 
        arr->n_cells = n_cells;
249
 
        arr->protection = protection;
250
 
 
251
 
        /* Then create the mutex to protect the wait array complex */
252
 
        if (protection == SYNC_ARRAY_OS_MUTEX) {
253
 
                arr->os_mutex = os_mutex_create();
254
 
        } else if (protection == SYNC_ARRAY_MUTEX) {
255
 
                mutex_create(syn_arr_mutex_key,
256
 
                             &arr->mutex, SYNC_NO_ORDER_CHECK);
257
 
        } else {
258
 
                ut_error;
259
 
        }
260
 
 
261
 
        return(arr);
262
 
}
263
 
 
264
 
/******************************************************************//**
265
 
Frees the resources in a wait array. */
266
 
UNIV_INTERN
267
 
void
268
 
sync_array_free(
269
 
/*============*/
270
 
        sync_array_t*   arr)    /*!< in, own: sync wait array */
271
 
{
272
 
        ulint           protection;
273
 
 
274
 
        ut_a(arr->n_reserved == 0);
275
 
 
276
 
        sync_array_validate(arr);
277
 
 
278
 
        protection = arr->protection;
279
 
 
280
 
        /* Release the mutex protecting the wait array complex */
281
 
 
282
 
        if (protection == SYNC_ARRAY_OS_MUTEX) {
283
 
                os_mutex_free(arr->os_mutex);
284
 
        } else if (protection == SYNC_ARRAY_MUTEX) {
285
 
                mutex_free(&(arr->mutex));
286
 
        } else {
287
 
                ut_error;
288
 
        }
289
 
 
290
 
        ut_free(arr->array);
291
 
        ut_free(arr);
292
 
}
293
 
 
294
 
/********************************************************************//**
295
 
Validates the integrity of the wait array. Checks
296
 
that the number of reserved cells equals the count variable. */
297
 
UNIV_INTERN
298
 
void
299
 
sync_array_validate(
300
 
/*================*/
301
 
        sync_array_t*   arr)    /*!< in: sync wait array */
302
 
{
303
 
        ulint           i;
304
 
        sync_cell_t*    cell;
305
 
        ulint           count           = 0;
306
 
 
307
 
        sync_array_enter(arr);
308
 
 
309
 
        for (i = 0; i < arr->n_cells; i++) {
310
 
                cell = sync_array_get_nth_cell(arr, i);
311
 
                if (cell->wait_object != NULL) {
312
 
                        count++;
313
 
                }
314
 
        }
315
 
 
316
 
        ut_a(count == arr->n_reserved);
317
 
 
318
 
        sync_array_exit(arr);
319
 
}
320
 
 
321
 
/*******************************************************************//**
322
 
Returns the event that the thread owning the cell waits for. */
323
 
static
324
 
os_event_t
325
 
sync_cell_get_event(
326
 
/*================*/
327
 
        sync_cell_t*    cell) /*!< in: non-empty sync array cell */
328
 
{
329
 
        ulint type = cell->request_type;
330
 
 
331
 
        if (type == SYNC_MUTEX) {
332
 
                return(((mutex_t *) cell->wait_object)->event);
333
 
        } else if (type == RW_LOCK_WAIT_EX) {
334
 
                return(((rw_lock_t *) cell->wait_object)->wait_ex_event);
335
 
        } else { /* RW_LOCK_SHARED and RW_LOCK_EX wait on the same event */
336
 
                return(((rw_lock_t *) cell->wait_object)->event);
337
 
        }
338
 
}
339
 
 
340
 
/******************************************************************//**
341
 
Reserves a wait array cell for waiting for an object.
342
 
The event of the cell is reset to nonsignalled state. */
343
 
UNIV_INTERN
344
 
void
345
 
sync_array_reserve_cell(
346
 
/*====================*/
347
 
        sync_array_t*   arr,    /*!< in: wait array */
348
 
        void*           object, /*!< in: pointer to the object to wait for */
349
 
        ulint           type,   /*!< in: lock request type */
350
 
        const char*     file,   /*!< in: file where requested */
351
 
        ulint           line,   /*!< in: line where requested */
352
 
        ulint*          index)  /*!< out: index of the reserved cell */
353
 
{
354
 
        sync_cell_t*    cell;
355
 
        os_event_t      event;
356
 
        ulint           i;
357
 
 
358
 
        ut_a(object);
359
 
        ut_a(index);
360
 
 
361
 
        sync_array_enter(arr);
362
 
 
363
 
        arr->res_count++;
364
 
 
365
 
        /* Reserve a new cell. */
366
 
        for (i = 0; i < arr->n_cells; i++) {
367
 
                cell = sync_array_get_nth_cell(arr, i);
368
 
 
369
 
                if (cell->wait_object == NULL) {
370
 
 
371
 
                        cell->waiting = FALSE;
372
 
                        cell->wait_object = object;
373
 
 
374
 
                        if (type == SYNC_MUTEX) {
375
 
                                cell->old_wait_mutex = object;
376
 
                        } else {
377
 
                                cell->old_wait_rw_lock = object;
378
 
                        }
379
 
 
380
 
                        cell->request_type = type;
381
 
 
382
 
                        cell->file = file;
383
 
                        cell->line = line;
384
 
 
385
 
                        arr->n_reserved++;
386
 
 
387
 
                        *index = i;
388
 
 
389
 
                        sync_array_exit(arr);
390
 
 
391
 
                        /* Make sure the event is reset and also store
392
 
                        the value of signal_count at which the event
393
 
                        was reset. */
394
 
                        event = sync_cell_get_event(cell);
395
 
                        cell->signal_count = os_event_reset(event);
396
 
 
397
 
                        cell->reservation_time = time(NULL);
398
 
 
399
 
                        cell->thread = os_thread_get_curr_id();
400
 
 
401
 
                        return;
402
 
                }
403
 
        }
404
 
 
405
 
        ut_error; /* No free cell found */
406
 
 
407
 
        return;
408
 
}
409
 
 
410
 
/******************************************************************//**
411
 
This function should be called when a thread starts to wait on
412
 
a wait array cell. In the debug version this function checks
413
 
if the wait for a semaphore will result in a deadlock, in which
414
 
case prints info and asserts. */
415
 
UNIV_INTERN
416
 
void
417
 
sync_array_wait_event(
418
 
/*==================*/
419
 
        sync_array_t*   arr,    /*!< in: wait array */
420
 
        ulint           index)  /*!< in: index of the reserved cell */
421
 
{
422
 
        sync_cell_t*    cell;
423
 
        os_event_t      event;
424
 
 
425
 
        ut_a(arr);
426
 
 
427
 
        sync_array_enter(arr);
428
 
 
429
 
        cell = sync_array_get_nth_cell(arr, index);
430
 
 
431
 
        ut_a(cell->wait_object);
432
 
        ut_a(!cell->waiting);
433
 
        ut_ad(os_thread_get_curr_id() == cell->thread);
434
 
 
435
 
        event = sync_cell_get_event(cell);
436
 
                cell->waiting = TRUE;
437
 
 
438
 
#ifdef UNIV_SYNC_DEBUG
439
 
 
440
 
        /* We use simple enter to the mutex below, because if
441
 
        we cannot acquire it at once, mutex_enter would call
442
 
        recursively sync_array routines, leading to trouble.
443
 
        rw_lock_debug_mutex freezes the debug lists. */
444
 
 
445
 
        rw_lock_debug_mutex_enter();
446
 
 
447
 
        if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) {
448
 
 
449
 
                fputs("########################################\n", stderr);
450
 
                ut_error;
451
 
        }
452
 
 
453
 
        rw_lock_debug_mutex_exit();
454
 
#endif
455
 
        sync_array_exit(arr);
456
 
 
457
 
        os_event_wait_low(event, cell->signal_count);
458
 
 
459
 
        sync_array_free_cell(arr, index);
460
 
}
461
 
 
462
 
/******************************************************************//**
463
 
Reports info of a wait array cell. */
464
 
static
465
 
void
466
 
sync_array_cell_print(
467
 
/*==================*/
468
 
        FILE*           file,   /*!< in: file where to print */
469
 
        sync_cell_t*    cell)   /*!< in: sync cell */
470
 
{
471
 
        mutex_t*        mutex;
472
 
        rw_lock_t*      rwlock;
473
 
        ulint           type;
474
 
        ulint           writer;
475
 
 
476
 
        type = cell->request_type;
477
 
 
478
 
        fprintf(file,
479
 
                "--Thread %lu has waited at %s line %lu"
480
 
                " for %.2f seconds the semaphore:\n",
481
 
                (ulong) os_thread_pf(cell->thread), cell->file,
482
 
                (ulong) cell->line,
483
 
                difftime(time(NULL), cell->reservation_time));
484
 
 
485
 
        if (type == SYNC_MUTEX) {
486
 
                /* We use old_wait_mutex in case the cell has already
487
 
                been freed meanwhile */
488
 
                mutex = cell->old_wait_mutex;
489
 
 
490
 
                fprintf(file,
491
 
                        "Mutex at %p created file %s line %lu, lock var %lu\n"
492
 
#ifdef UNIV_SYNC_DEBUG
493
 
                        "Last time reserved in file %s line %lu, "
494
 
#endif /* UNIV_SYNC_DEBUG */
495
 
                        "waiters flag %lu\n",
496
 
                        (void*) mutex, mutex->cfile_name, (ulong) mutex->cline,
497
 
                        (ulong) mutex->lock_word,
498
 
#ifdef UNIV_SYNC_DEBUG
499
 
                        mutex->file_name, (ulong) mutex->line,
500
 
#endif /* UNIV_SYNC_DEBUG */
501
 
                        (ulong) mutex->waiters);
502
 
 
503
 
        } else if (type == RW_LOCK_EX
504
 
                   || type == RW_LOCK_WAIT_EX
505
 
                   || type == RW_LOCK_SHARED) {
506
 
 
507
 
                fputs(type == RW_LOCK_EX ? "X-lock on"
508
 
                      : type == RW_LOCK_WAIT_EX ? "X-lock (wait_ex) on"
509
 
                      : "S-lock on", file);
510
 
 
511
 
                rwlock = cell->old_wait_rw_lock;
512
 
 
513
 
                fprintf(file,
514
 
                        " RW-latch at %p created in file %s line %lu\n",
515
 
                        (void*) rwlock, rwlock->cfile_name,
516
 
                        (ulong) rwlock->cline);
517
 
                writer = rw_lock_get_writer(rwlock);
518
 
                if (writer != RW_LOCK_NOT_LOCKED) {
519
 
                        fprintf(file,
520
 
                                "a writer (thread id %lu) has"
521
 
                                " reserved it in mode %s",
522
 
                                (ulong) os_thread_pf(rwlock->writer_thread),
523
 
                                writer == RW_LOCK_EX
524
 
                                ? " exclusive\n"
525
 
                                : " wait exclusive\n");
526
 
                }
527
 
 
528
 
                fprintf(file,
529
 
                        "number of readers %lu, waiters flag %lu, "
530
 
                        "lock_word: %lx\n"
531
 
                        "Last time read locked in file %s line %lu\n"
532
 
                        "Last time write locked in file %s line %lu\n",
533
 
                        (ulong) rw_lock_get_reader_count(rwlock),
534
 
                        (ulong) rwlock->waiters,
535
 
                        rwlock->lock_word,
536
 
                        rwlock->last_s_file_name,
537
 
                        (ulong) rwlock->last_s_line,
538
 
                        rwlock->last_x_file_name,
539
 
                        (ulong) rwlock->last_x_line);
540
 
        } else {
541
 
                ut_error;
542
 
        }
543
 
 
544
 
        if (!cell->waiting) {
545
 
                fputs("wait has ended\n", file);
546
 
        }
547
 
}
548
 
 
549
 
#ifdef UNIV_SYNC_DEBUG
550
 
/******************************************************************//**
551
 
Looks for a cell with the given thread id.
552
 
@return pointer to cell or NULL if not found */
553
 
static
554
 
sync_cell_t*
555
 
sync_array_find_thread(
556
 
/*===================*/
557
 
        sync_array_t*   arr,    /*!< in: wait array */
558
 
        os_thread_id_t  thread) /*!< in: thread id */
559
 
{
560
 
        ulint           i;
561
 
        sync_cell_t*    cell;
562
 
 
563
 
        for (i = 0; i < arr->n_cells; i++) {
564
 
 
565
 
                cell = sync_array_get_nth_cell(arr, i);
566
 
 
567
 
                if (cell->wait_object != NULL
568
 
                    && os_thread_eq(cell->thread, thread)) {
569
 
 
570
 
                        return(cell);   /* Found */
571
 
                }
572
 
        }
573
 
 
574
 
        return(NULL);   /* Not found */
575
 
}
576
 
 
577
 
/******************************************************************//**
578
 
Recursion step for deadlock detection.
579
 
@return TRUE if deadlock detected */
580
 
static
581
 
ibool
582
 
sync_array_deadlock_step(
583
 
/*=====================*/
584
 
        sync_array_t*   arr,    /*!< in: wait array; NOTE! the caller must
585
 
                                own the mutex to array */
586
 
        sync_cell_t*    start,  /*!< in: cell where recursive search
587
 
                                started */
588
 
        os_thread_id_t  thread, /*!< in: thread to look at */
589
 
        ulint           pass,   /*!< in: pass value */
590
 
        ulint           depth)  /*!< in: recursion depth */
591
 
{
592
 
        sync_cell_t*    new;
593
 
        ibool           ret;
594
 
 
595
 
        depth++;
596
 
 
597
 
        if (pass != 0) {
598
 
                /* If pass != 0, then we do not know which threads are
599
 
                responsible of releasing the lock, and no deadlock can
600
 
                be detected. */
601
 
 
602
 
                return(FALSE);
603
 
        }
604
 
 
605
 
        new = sync_array_find_thread(arr, thread);
606
 
 
607
 
        if (new == start) {
608
 
                /* Stop running of other threads */
609
 
 
610
 
                ut_dbg_stop_threads = TRUE;
611
 
 
612
 
                /* Deadlock */
613
 
                fputs("########################################\n"
614
 
                      "DEADLOCK of threads detected!\n", stderr);
615
 
 
616
 
                return(TRUE);
617
 
 
618
 
        } else if (new) {
619
 
                ret = sync_array_detect_deadlock(arr, start, new, depth);
620
 
 
621
 
                if (ret) {
622
 
                        return(TRUE);
623
 
                }
624
 
        }
625
 
        return(FALSE);
626
 
}
627
 
 
628
 
/******************************************************************//**
629
 
This function is called only in the debug version. Detects a deadlock
630
 
of one or more threads because of waits of semaphores.
631
 
@return TRUE if deadlock detected */
632
 
static
633
 
ibool
634
 
sync_array_detect_deadlock(
635
 
/*=======================*/
636
 
        sync_array_t*   arr,    /*!< in: wait array; NOTE! the caller must
637
 
                                own the mutex to array */
638
 
        sync_cell_t*    start,  /*!< in: cell where recursive search started */
639
 
        sync_cell_t*    cell,   /*!< in: cell to search */
640
 
        ulint           depth)  /*!< in: recursion depth */
641
 
{
642
 
        mutex_t*        mutex;
643
 
        rw_lock_t*      lock;
644
 
        os_thread_id_t  thread;
645
 
        ibool           ret;
646
 
        rw_lock_debug_t*debug;
647
 
 
648
 
        ut_a(arr);
649
 
        ut_a(start);
650
 
        ut_a(cell);
651
 
        ut_ad(cell->wait_object);
652
 
        ut_ad(os_thread_get_curr_id() == start->thread);
653
 
        ut_ad(depth < 100);
654
 
 
655
 
        depth++;
656
 
 
657
 
        if (!cell->waiting) {
658
 
 
659
 
                return(FALSE); /* No deadlock here */
660
 
        }
661
 
 
662
 
        if (cell->request_type == SYNC_MUTEX) {
663
 
 
664
 
                mutex = cell->wait_object;
665
 
 
666
 
                if (mutex_get_lock_word(mutex) != 0) {
667
 
 
668
 
                        thread = mutex->thread_id;
669
 
 
670
 
                        /* Note that mutex->thread_id above may be
671
 
                        also OS_THREAD_ID_UNDEFINED, because the
672
 
                        thread which held the mutex maybe has not
673
 
                        yet updated the value, or it has already
674
 
                        released the mutex: in this case no deadlock
675
 
                        can occur, as the wait array cannot contain
676
 
                        a thread with ID_UNDEFINED value. */
677
 
 
678
 
                        ret = sync_array_deadlock_step(arr, start, thread, 0,
679
 
                                                       depth);
680
 
                        if (ret) {
681
 
                                fprintf(stderr,
682
 
                        "Mutex %p owned by thread %lu file %s line %lu\n",
683
 
                                        mutex, (ulong) os_thread_pf(mutex->thread_id),
684
 
                                        mutex->file_name, (ulong) mutex->line);
685
 
                                sync_array_cell_print(stderr, cell);
686
 
 
687
 
                                return(TRUE);
688
 
                        }
689
 
                }
690
 
 
691
 
                return(FALSE); /* No deadlock */
692
 
 
693
 
        } else if (cell->request_type == RW_LOCK_EX
694
 
                   || cell->request_type == RW_LOCK_WAIT_EX) {
695
 
 
696
 
                lock = cell->wait_object;
697
 
 
698
 
                debug = UT_LIST_GET_FIRST(lock->debug_list);
699
 
 
700
 
                while (debug != NULL) {
701
 
 
702
 
                        thread = debug->thread_id;
703
 
 
704
 
                        if (((debug->lock_type == RW_LOCK_EX)
705
 
                             && !os_thread_eq(thread, cell->thread))
706
 
                            || ((debug->lock_type == RW_LOCK_WAIT_EX)
707
 
                                && !os_thread_eq(thread, cell->thread))
708
 
                            || (debug->lock_type == RW_LOCK_SHARED)) {
709
 
 
710
 
                                /* The (wait) x-lock request can block
711
 
                                infinitely only if someone (can be also cell
712
 
                                thread) is holding s-lock, or someone
713
 
                                (cannot be cell thread) (wait) x-lock, and
714
 
                                he is blocked by start thread */
715
 
 
716
 
                                ret = sync_array_deadlock_step(
717
 
                                        arr, start, thread, debug->pass,
718
 
                                        depth);
719
 
                                if (ret) {
720
 
print:
721
 
                                        fprintf(stderr, "rw-lock %p ",
722
 
                                                (void*) lock);
723
 
                                        sync_array_cell_print(stderr, cell);
724
 
                                        rw_lock_debug_print(debug);
725
 
                                        return(TRUE);
726
 
                                }
727
 
                        }
728
 
 
729
 
                        debug = UT_LIST_GET_NEXT(list, debug);
730
 
                }
731
 
 
732
 
                return(FALSE);
733
 
 
734
 
        } else if (cell->request_type == RW_LOCK_SHARED) {
735
 
 
736
 
                lock = cell->wait_object;
737
 
                debug = UT_LIST_GET_FIRST(lock->debug_list);
738
 
 
739
 
                while (debug != NULL) {
740
 
 
741
 
                        thread = debug->thread_id;
742
 
 
743
 
                        if ((debug->lock_type == RW_LOCK_EX)
744
 
                            || (debug->lock_type == RW_LOCK_WAIT_EX)) {
745
 
 
746
 
                                /* The s-lock request can block infinitely
747
 
                                only if someone (can also be cell thread) is
748
 
                                holding (wait) x-lock, and he is blocked by
749
 
                                start thread */
750
 
 
751
 
                                ret = sync_array_deadlock_step(
752
 
                                        arr, start, thread, debug->pass,
753
 
                                        depth);
754
 
                                if (ret) {
755
 
                                        goto print;
756
 
                                }
757
 
                        }
758
 
 
759
 
                        debug = UT_LIST_GET_NEXT(list, debug);
760
 
                }
761
 
 
762
 
                return(FALSE);
763
 
 
764
 
        } else {
765
 
                ut_error;
766
 
        }
767
 
 
768
 
        return(TRUE);   /* Execution never reaches this line: for compiler
769
 
                        fooling only */
770
 
}
771
 
#endif /* UNIV_SYNC_DEBUG */
772
 
 
773
 
/******************************************************************//**
774
 
Determines if we can wake up the thread waiting for a sempahore. */
775
 
static
776
 
ibool
777
 
sync_arr_cell_can_wake_up(
778
 
/*======================*/
779
 
        sync_cell_t*    cell)   /*!< in: cell to search */
780
 
{
781
 
        mutex_t*        mutex;
782
 
        rw_lock_t*      lock;
783
 
 
784
 
        if (cell->request_type == SYNC_MUTEX) {
785
 
 
786
 
                mutex = cell->wait_object;
787
 
 
788
 
                if (mutex_get_lock_word(mutex) == 0) {
789
 
 
790
 
                        return(TRUE);
791
 
                }
792
 
 
793
 
        } else if (cell->request_type == RW_LOCK_EX) {
794
 
 
795
 
                lock = cell->wait_object;
796
 
 
797
 
                if (lock->lock_word > 0) {
798
 
                /* Either unlocked or only read locked. */
799
 
 
800
 
                        return(TRUE);
801
 
                }
802
 
 
803
 
        } else if (cell->request_type == RW_LOCK_WAIT_EX) {
804
 
 
805
 
                lock = cell->wait_object;
806
 
 
807
 
                /* lock_word == 0 means all readers have left */
808
 
                if (lock->lock_word == 0) {
809
 
 
810
 
                        return(TRUE);
811
 
                }
812
 
        } else if (cell->request_type == RW_LOCK_SHARED) {
813
 
                lock = cell->wait_object;
814
 
 
815
 
                /* lock_word > 0 means no writer or reserved writer */
816
 
                if (lock->lock_word > 0) {
817
 
 
818
 
                        return(TRUE);
819
 
                }
820
 
        }
821
 
 
822
 
        return(FALSE);
823
 
}
824
 
 
825
 
/******************************************************************//**
826
 
Frees the cell. NOTE! sync_array_wait_event frees the cell
827
 
automatically! */
828
 
UNIV_INTERN
829
 
void
830
 
sync_array_free_cell(
831
 
/*=================*/
832
 
        sync_array_t*   arr,    /*!< in: wait array */
833
 
        ulint           index)  /*!< in: index of the cell in array */
834
 
{
835
 
        sync_cell_t*    cell;
836
 
 
837
 
        sync_array_enter(arr);
838
 
 
839
 
        cell = sync_array_get_nth_cell(arr, index);
840
 
 
841
 
        ut_a(cell->wait_object != NULL);
842
 
 
843
 
        cell->waiting = FALSE;
844
 
        cell->wait_object =  NULL;
845
 
        cell->signal_count = 0;
846
 
 
847
 
        ut_a(arr->n_reserved > 0);
848
 
        arr->n_reserved--;
849
 
 
850
 
        sync_array_exit(arr);
851
 
}
852
 
 
853
 
/**********************************************************************//**
854
 
Increments the signalled count. */
855
 
UNIV_INTERN
856
 
void
857
 
sync_array_object_signalled(
858
 
/*========================*/
859
 
        sync_array_t*   arr)    /*!< in: wait array */
860
 
{
861
 
#ifdef HAVE_ATOMIC_BUILTINS
862
 
        (void) os_atomic_increment_ulint(&arr->sg_count, 1);
863
 
#else
864
 
        sync_array_enter(arr);
865
 
 
866
 
        arr->sg_count++;
867
 
 
868
 
        sync_array_exit(arr);
869
 
#endif
870
 
}
871
 
 
872
 
/**********************************************************************//**
873
 
If the wakeup algorithm does not work perfectly at semaphore relases,
874
 
this function will do the waking (see the comment in mutex_exit). This
875
 
function should be called about every 1 second in the server.
876
 
 
877
 
Note that there's a race condition between this thread and mutex_exit
878
 
changing the lock_word and calling signal_object, so sometimes this finds
879
 
threads to wake up even when nothing has gone wrong. */
880
 
UNIV_INTERN
881
 
void
882
 
sync_arr_wake_threads_if_sema_free(void)
883
 
/*====================================*/
884
 
{
885
 
        sync_array_t*   arr     = sync_primary_wait_array;
886
 
        sync_cell_t*    cell;
887
 
        ulint           count;
888
 
        ulint           i;
889
 
        os_event_t      event;
890
 
 
891
 
        sync_array_enter(arr);
892
 
 
893
 
        i = 0;
894
 
        count = 0;
895
 
 
896
 
        while (count < arr->n_reserved) {
897
 
 
898
 
                cell = sync_array_get_nth_cell(arr, i);
899
 
                i++;
900
 
 
901
 
                if (cell->wait_object == NULL) {
902
 
                        continue;
903
 
                }
904
 
                        count++;
905
 
 
906
 
                        if (sync_arr_cell_can_wake_up(cell)) {
907
 
 
908
 
                        event = sync_cell_get_event(cell);
909
 
 
910
 
                        os_event_set(event);
911
 
                }
912
 
 
913
 
        }
914
 
 
915
 
        sync_array_exit(arr);
916
 
}
917
 
 
918
 
/**********************************************************************//**
919
 
Prints warnings of long semaphore waits to stderr.
920
 
@return TRUE if fatal semaphore wait threshold was exceeded */
921
 
UNIV_INTERN
922
 
ibool
923
 
sync_array_print_long_waits(void)
924
 
/*=============================*/
925
 
{
926
 
        sync_cell_t*    cell;
927
 
        ibool           old_val;
928
 
        ibool           noticed = FALSE;
929
 
        ulint           i;
930
 
        ulint           fatal_timeout = srv_fatal_semaphore_wait_threshold;
931
 
        ibool           fatal = FALSE;
932
 
 
933
 
        for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
934
 
 
935
 
                cell = sync_array_get_nth_cell(sync_primary_wait_array, i);
936
 
 
937
 
                if (cell->wait_object != NULL && cell->waiting
938
 
                    && difftime(time(NULL), cell->reservation_time) > 240) {
939
 
                        fputs("InnoDB: Warning: a long semaphore wait:\n",
940
 
                              stderr);
941
 
                        sync_array_cell_print(stderr, cell);
942
 
                        noticed = TRUE;
943
 
                }
944
 
 
945
 
                if (cell->wait_object != NULL && cell->waiting
946
 
                    && difftime(time(NULL), cell->reservation_time)
947
 
                    > fatal_timeout) {
948
 
                        fatal = TRUE;
949
 
                }
950
 
        }
951
 
 
952
 
        if (noticed) {
953
 
                fprintf(stderr,
954
 
                        "InnoDB: ###### Starts InnoDB Monitor"
955
 
                        " for 30 secs to print diagnostic info:\n");
956
 
                old_val = srv_print_innodb_monitor;
957
 
 
958
 
                /* If some crucial semaphore is reserved, then also the InnoDB
959
 
                Monitor can hang, and we do not get diagnostics. Since in
960
 
                many cases an InnoDB hang is caused by a pwrite() or a pread()
961
 
                call hanging inside the operating system, let us print right
962
 
                now the values of pending calls of these. */
963
 
 
964
 
                fprintf(stderr,
965
 
                        "InnoDB: Pending preads %lu, pwrites %lu\n",
966
 
                        (ulong)os_file_n_pending_preads,
967
 
                        (ulong)os_file_n_pending_pwrites);
968
 
 
969
 
                srv_print_innodb_monitor = TRUE;
970
 
                os_event_set(srv_lock_timeout_thread_event);
971
 
 
972
 
                os_thread_sleep(30000000);
973
 
 
974
 
                srv_print_innodb_monitor = old_val;
975
 
                fprintf(stderr,
976
 
                        "InnoDB: ###### Diagnostic info printed"
977
 
                        " to the standard error stream\n");
978
 
        }
979
 
 
980
 
        return(fatal);
981
 
}
982
 
 
983
 
/**********************************************************************//**
984
 
Prints info of the wait array. */
985
 
static
986
 
void
987
 
sync_array_output_info(
988
 
/*===================*/
989
 
        FILE*           file,   /*!< in: file where to print */
990
 
        sync_array_t*   arr)    /*!< in: wait array; NOTE! caller must own the
991
 
                                mutex */
992
 
{
993
 
        sync_cell_t*    cell;
994
 
        ulint           count;
995
 
        ulint           i;
996
 
 
997
 
        fprintf(file,
998
 
                "OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n",
999
 
                                                (long) arr->res_count, (long) arr->sg_count);
1000
 
        i = 0;
1001
 
        count = 0;
1002
 
 
1003
 
        while (count < arr->n_reserved) {
1004
 
 
1005
 
                cell = sync_array_get_nth_cell(arr, i);
1006
 
 
1007
 
        if (cell->wait_object != NULL) {
1008
 
                count++;
1009
 
                        sync_array_cell_print(file, cell);
1010
 
                }
1011
 
 
1012
 
                i++;
1013
 
        }
1014
 
}
1015
 
 
1016
 
/**********************************************************************//**
1017
 
Prints info of the wait array. */
1018
 
UNIV_INTERN
1019
 
void
1020
 
sync_array_print_info(
1021
 
/*==================*/
1022
 
        FILE*           file,   /*!< in: file where to print */
1023
 
        sync_array_t*   arr)    /*!< in: wait array */
1024
 
{
1025
 
        sync_array_enter(arr);
1026
 
 
1027
 
        sync_array_output_info(file, arr);
1028
 
 
1029
 
        sync_array_exit(arr);
1030
 
}