~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

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
}