~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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