~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The read-write lock (for thread synchronization)
 
3
 
 
4
(c) 1995 Innobase Oy
 
5
 
 
6
Created 9/11/1995 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "sync0rw.h"
 
10
#ifdef UNIV_NONINL
 
11
#include "sync0rw.ic"
 
12
#endif
 
13
 
 
14
#include "os0thread.h"
 
15
#include "mem0mem.h"
 
16
#include "srv0srv.h"
 
17
 
 
18
/* number of system calls made during shared latching */
 
19
ulint   rw_s_system_call_count  = 0;
 
20
 
 
21
/* number of spin waits on rw-latches,
 
22
resulted during shared (read) locks */
 
23
ulint   rw_s_spin_wait_count    = 0;
 
24
 
 
25
/* number of OS waits on rw-latches,
 
26
resulted during shared (read) locks */
 
27
ulint   rw_s_os_wait_count      = 0;
 
28
 
 
29
/* number of unlocks (that unlock shared locks),
 
30
set only when UNIV_SYNC_PERF_STAT is defined */
 
31
ulint   rw_s_exit_count         = 0;
 
32
 
 
33
/* number of system calls made during exclusive latching */
 
34
ulint   rw_x_system_call_count  = 0;
 
35
 
 
36
/* number of spin waits on rw-latches,
 
37
resulted during exclusive (write) locks */
 
38
ulint   rw_x_spin_wait_count    = 0;
 
39
 
 
40
/* number of OS waits on rw-latches,
 
41
resulted during exclusive (write) locks */
 
42
ulint   rw_x_os_wait_count      = 0;
 
43
 
 
44
/* number of unlocks (that unlock exclusive locks),
 
45
set only when UNIV_SYNC_PERF_STAT is defined */
 
46
ulint   rw_x_exit_count         = 0;
 
47
 
 
48
/* The global list of rw-locks */
 
49
rw_lock_list_t  rw_lock_list;
 
50
mutex_t         rw_lock_list_mutex;
 
51
 
 
52
#ifdef UNIV_SYNC_DEBUG
 
53
/* The global mutex which protects debug info lists of all rw-locks.
 
54
To modify the debug info list of an rw-lock, this mutex has to be
 
55
acquired in addition to the mutex protecting the lock. */
 
56
 
 
57
mutex_t         rw_lock_debug_mutex;
 
58
os_event_t      rw_lock_debug_event;    /* If deadlock detection does not
 
59
                                        get immediately the mutex, it may
 
60
                                        wait for this event */
 
61
ibool           rw_lock_debug_waiters;  /* This is set to TRUE, if there may
 
62
                                        be waiters for the event */
 
63
 
 
64
/**********************************************************************
 
65
Creates a debug info struct. */
 
66
static
 
67
rw_lock_debug_t*
 
68
rw_lock_debug_create(void);
 
69
/*======================*/
 
70
/**********************************************************************
 
71
Frees a debug info struct. */
 
72
static
 
73
void
 
74
rw_lock_debug_free(
 
75
/*===============*/
 
76
        rw_lock_debug_t* info);
 
77
 
 
78
/**********************************************************************
 
79
Creates a debug info struct. */
 
80
static
 
81
rw_lock_debug_t*
 
82
rw_lock_debug_create(void)
 
83
/*======================*/
 
84
{
 
85
        return((rw_lock_debug_t*) mem_alloc(sizeof(rw_lock_debug_t)));
 
86
}
 
87
 
 
88
/**********************************************************************
 
89
Frees a debug info struct. */
 
90
static
 
91
void
 
92
rw_lock_debug_free(
 
93
/*===============*/
 
94
        rw_lock_debug_t* info)
 
95
{
 
96
        mem_free(info);
 
97
}
 
98
#endif /* UNIV_SYNC_DEBUG */
 
99
 
 
100
/**********************************************************************
 
101
Creates, or rather, initializes an rw-lock object in a specified memory
 
102
location (which must be appropriately aligned). The rw-lock is initialized
 
103
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
 
104
is necessary only if the memory block containing it is freed. */
 
105
 
 
106
void
 
107
rw_lock_create_func(
 
108
/*================*/
 
109
        rw_lock_t*      lock,           /* in: pointer to memory */
 
110
#ifdef UNIV_DEBUG
 
111
# ifdef UNIV_SYNC_DEBUG
 
112
        ulint           level,          /* in: level */
 
113
# endif /* UNIV_SYNC_DEBUG */
 
114
        const char*     cmutex_name,    /* in: mutex name */
 
115
#endif /* UNIV_DEBUG */
 
116
        const char*     cfile_name,     /* in: file name where created */
 
117
        ulint           cline)          /* in: file line where created */
 
118
{
 
119
        /* If this is the very first time a synchronization object is
 
120
        created, then the following call initializes the sync system. */
 
121
 
 
122
        mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
 
123
 
 
124
        lock->mutex.cfile_name = cfile_name;
 
125
        lock->mutex.cline = cline;
 
126
 
 
127
#if defined UNIV_DEBUG && !defined UNIV_HOTBACKUP
 
128
        lock->mutex.cmutex_name = cmutex_name;
 
129
        lock->mutex.mutex_type = 1;
 
130
#endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
 
131
 
 
132
        rw_lock_set_waiters(lock, 0);
 
133
        rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
 
134
        lock->writer_count = 0;
 
135
        rw_lock_set_reader_count(lock, 0);
 
136
 
 
137
        lock->writer_is_wait_ex = FALSE;
 
138
 
 
139
#ifdef UNIV_SYNC_DEBUG
 
140
        UT_LIST_INIT(lock->debug_list);
 
141
 
 
142
        lock->level = level;
 
143
#endif /* UNIV_SYNC_DEBUG */
 
144
 
 
145
        lock->magic_n = RW_LOCK_MAGIC_N;
 
146
 
 
147
        lock->cfile_name = cfile_name;
 
148
        lock->cline = (unsigned int) cline;
 
149
 
 
150
        lock->last_s_file_name = "not yet reserved";
 
151
        lock->last_x_file_name = "not yet reserved";
 
152
        lock->last_s_line = 0;
 
153
        lock->last_x_line = 0;
 
154
 
 
155
        mutex_enter(&rw_lock_list_mutex);
 
156
 
 
157
        if (UT_LIST_GET_LEN(rw_lock_list) > 0) {
 
158
                ut_a(UT_LIST_GET_FIRST(rw_lock_list)->magic_n
 
159
                     == RW_LOCK_MAGIC_N);
 
160
        }
 
161
 
 
162
        UT_LIST_ADD_FIRST(list, rw_lock_list, lock);
 
163
 
 
164
        mutex_exit(&rw_lock_list_mutex);
 
165
}
 
166
 
 
167
/**********************************************************************
 
168
Calling this function is obligatory only if the memory buffer containing
 
169
the rw-lock is freed. Removes an rw-lock object from the global list. The
 
170
rw-lock is checked to be in the non-locked state. */
 
171
 
 
172
void
 
173
rw_lock_free(
 
174
/*=========*/
 
175
        rw_lock_t*      lock)   /* in: rw-lock */
 
176
{
 
177
        ut_ad(rw_lock_validate(lock));
 
178
        ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
 
179
        ut_a(rw_lock_get_waiters(lock) == 0);
 
180
        ut_a(rw_lock_get_reader_count(lock) == 0);
 
181
 
 
182
        lock->magic_n = 0;
 
183
 
 
184
        mutex_free(rw_lock_get_mutex(lock));
 
185
 
 
186
        mutex_enter(&rw_lock_list_mutex);
 
187
 
 
188
        if (UT_LIST_GET_PREV(list, lock)) {
 
189
                ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
 
190
        }
 
191
        if (UT_LIST_GET_NEXT(list, lock)) {
 
192
                ut_a(UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N);
 
193
        }
 
194
 
 
195
        UT_LIST_REMOVE(list, rw_lock_list, lock);
 
196
 
 
197
        mutex_exit(&rw_lock_list_mutex);
 
198
}
 
199
 
 
200
#ifdef UNIV_DEBUG
 
201
/**********************************************************************
 
202
Checks that the rw-lock has been initialized and that there are no
 
203
simultaneous shared and exclusive locks. */
 
204
 
 
205
ibool
 
206
rw_lock_validate(
 
207
/*=============*/
 
208
        rw_lock_t*      lock)
 
209
{
 
210
        ut_a(lock);
 
211
 
 
212
        mutex_enter(rw_lock_get_mutex(lock));
 
213
 
 
214
        ut_a(lock->magic_n == RW_LOCK_MAGIC_N);
 
215
        ut_a((rw_lock_get_reader_count(lock) == 0)
 
216
             || (rw_lock_get_writer(lock) != RW_LOCK_EX));
 
217
        ut_a((rw_lock_get_writer(lock) == RW_LOCK_EX)
 
218
             || (rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX)
 
219
             || (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED));
 
220
        ut_a((rw_lock_get_waiters(lock) == 0)
 
221
             || (rw_lock_get_waiters(lock) == 1));
 
222
        ut_a((lock->writer != RW_LOCK_EX) || (lock->writer_count > 0));
 
223
 
 
224
        mutex_exit(rw_lock_get_mutex(lock));
 
225
 
 
226
        return(TRUE);
 
227
}
 
228
#endif /* UNIV_DEBUG */
 
229
 
 
230
/**********************************************************************
 
231
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
 
232
locked in exclusive mode, or there is an exclusive lock request waiting,
 
233
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
 
234
for the lock, before suspending the thread. */
 
235
 
 
236
void
 
237
rw_lock_s_lock_spin(
 
238
/*================*/
 
239
        rw_lock_t*      lock,   /* in: pointer to rw-lock */
 
240
        ulint           pass,   /* in: pass value; != 0, if the lock
 
241
                                will be passed to another thread to unlock */
 
242
        const char*     file_name, /* in: file name where lock requested */
 
243
        ulint           line)   /* in: line where requested */
 
244
{
 
245
        ulint    index; /* index of the reserved wait cell */
 
246
        ulint    i;     /* spin round count */
 
247
 
 
248
        ut_ad(rw_lock_validate(lock));
 
249
 
 
250
lock_loop:
 
251
        rw_s_spin_wait_count++;
 
252
 
 
253
        /* Spin waiting for the writer field to become free */
 
254
        i = 0;
 
255
 
 
256
        while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
 
257
               && i < SYNC_SPIN_ROUNDS) {
 
258
                if (srv_spin_wait_delay) {
 
259
                        ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
 
260
                }
 
261
 
 
262
                i++;
 
263
        }
 
264
 
 
265
        if (i == SYNC_SPIN_ROUNDS) {
 
266
                os_thread_yield();
 
267
        }
 
268
 
 
269
        if (srv_print_latch_waits) {
 
270
                fprintf(stderr,
 
271
                        "Thread %lu spin wait rw-s-lock at %p"
 
272
                        " cfile %s cline %lu rnds %lu\n",
 
273
                        (ulong) os_thread_pf(os_thread_get_curr_id()),
 
274
                        (void*) lock,
 
275
                        lock->cfile_name, (ulong) lock->cline, (ulong) i);
 
276
        }
 
277
 
 
278
        mutex_enter(rw_lock_get_mutex(lock));
 
279
 
 
280
        /* We try once again to obtain the lock */
 
281
 
 
282
        if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
 
283
                mutex_exit(rw_lock_get_mutex(lock));
 
284
 
 
285
                return; /* Success */
 
286
        } else {
 
287
                /* If we get here, locking did not succeed, we may
 
288
                suspend the thread to wait in the wait array */
 
289
 
 
290
                rw_s_system_call_count++;
 
291
 
 
292
                sync_array_reserve_cell(sync_primary_wait_array,
 
293
                                        lock, RW_LOCK_SHARED,
 
294
                                        file_name, line,
 
295
                                        &index);
 
296
 
 
297
                rw_lock_set_waiters(lock, 1);
 
298
 
 
299
                mutex_exit(rw_lock_get_mutex(lock));
 
300
 
 
301
                if (srv_print_latch_waits) {
 
302
                        fprintf(stderr,
 
303
                                "Thread %lu OS wait rw-s-lock at %p"
 
304
                                " cfile %s cline %lu\n",
 
305
                                os_thread_pf(os_thread_get_curr_id()),
 
306
                                (void*) lock, lock->cfile_name,
 
307
                                (ulong) lock->cline);
 
308
                }
 
309
 
 
310
                rw_s_system_call_count++;
 
311
                rw_s_os_wait_count++;
 
312
 
 
313
                sync_array_wait_event(sync_primary_wait_array, index);
 
314
 
 
315
                goto lock_loop;
 
316
        }
 
317
}
 
318
 
 
319
/**********************************************************************
 
320
This function is used in the insert buffer to move the ownership of an
 
321
x-latch on a buffer frame to the current thread. The x-latch was set by
 
322
the buffer read operation and it protected the buffer frame while the
 
323
read was done. The ownership is moved because we want that the current
 
324
thread is able to acquire a second x-latch which is stored in an mtr.
 
325
This, in turn, is needed to pass the debug checks of index page
 
326
operations. */
 
327
 
 
328
void
 
329
rw_lock_x_lock_move_ownership(
 
330
/*==========================*/
 
331
        rw_lock_t*      lock)   /* in: lock which was x-locked in the
 
332
                                buffer read */
 
333
{
 
334
        ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
 
335
 
 
336
        mutex_enter(&(lock->mutex));
 
337
 
 
338
        lock->writer_thread = os_thread_get_curr_id();
 
339
 
 
340
        lock->pass = 0;
 
341
 
 
342
        mutex_exit(&(lock->mutex));
 
343
}
 
344
 
 
345
/**********************************************************************
 
346
Low-level function for acquiring an exclusive lock. */
 
347
UNIV_INLINE
 
348
ulint
 
349
rw_lock_x_lock_low(
 
350
/*===============*/
 
351
                                /* out: RW_LOCK_NOT_LOCKED if did
 
352
                                not succeed, RW_LOCK_EX if success,
 
353
                                RW_LOCK_WAIT_EX, if got wait reservation */
 
354
        rw_lock_t*      lock,   /* in: pointer to rw-lock */
 
355
        ulint           pass,   /* in: pass value; != 0, if the lock will
 
356
                                be passed to another thread to unlock */
 
357
        const char*     file_name,/* in: file name where lock requested */
 
358
        ulint           line)   /* in: line where requested */
 
359
{
 
360
        ut_ad(mutex_own(rw_lock_get_mutex(lock)));
 
361
 
 
362
        if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {
 
363
 
 
364
                if (rw_lock_get_reader_count(lock) == 0) {
 
365
 
 
366
                        rw_lock_set_writer(lock, RW_LOCK_EX);
 
367
                        lock->writer_thread = os_thread_get_curr_id();
 
368
                        lock->writer_count++;
 
369
                        lock->pass = pass;
 
370
 
 
371
#ifdef UNIV_SYNC_DEBUG
 
372
                        rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
 
373
                                               file_name, line);
 
374
#endif
 
375
                        lock->last_x_file_name = file_name;
 
376
                        lock->last_x_line = (unsigned int) line;
 
377
 
 
378
                        /* Locking succeeded, we may return */
 
379
                        return(RW_LOCK_EX);
 
380
                } else {
 
381
                        /* There are readers, we have to wait */
 
382
                        rw_lock_set_writer(lock, RW_LOCK_WAIT_EX);
 
383
                        lock->writer_thread = os_thread_get_curr_id();
 
384
                        lock->pass = pass;
 
385
                        lock->writer_is_wait_ex = TRUE;
 
386
 
 
387
#ifdef UNIV_SYNC_DEBUG
 
388
                        rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
 
389
                                               file_name, line);
 
390
#endif
 
391
 
 
392
                        return(RW_LOCK_WAIT_EX);
 
393
                }
 
394
 
 
395
        } else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX)
 
396
                   && os_thread_eq(lock->writer_thread,
 
397
                                   os_thread_get_curr_id())) {
 
398
 
 
399
                if (rw_lock_get_reader_count(lock) == 0) {
 
400
 
 
401
                        rw_lock_set_writer(lock, RW_LOCK_EX);
 
402
                        lock->writer_count++;
 
403
                        lock->pass = pass;
 
404
                        lock->writer_is_wait_ex = FALSE;
 
405
 
 
406
#ifdef UNIV_SYNC_DEBUG
 
407
                        rw_lock_remove_debug_info(lock, pass, RW_LOCK_WAIT_EX);
 
408
                        rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
 
409
                                               file_name, line);
 
410
#endif
 
411
 
 
412
                        lock->last_x_file_name = file_name;
 
413
                        lock->last_x_line = (unsigned int) line;
 
414
 
 
415
                        /* Locking succeeded, we may return */
 
416
                        return(RW_LOCK_EX);
 
417
                }
 
418
 
 
419
                return(RW_LOCK_WAIT_EX);
 
420
 
 
421
        } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX)
 
422
                   && os_thread_eq(lock->writer_thread,
 
423
                                   os_thread_get_curr_id())
 
424
                   && (lock->pass == 0)
 
425
                   && (pass == 0)) {
 
426
 
 
427
                lock->writer_count++;
 
428
 
 
429
#ifdef UNIV_SYNC_DEBUG
 
430
                rw_lock_add_debug_info(lock, pass, RW_LOCK_EX, file_name,
 
431
                                       line);
 
432
#endif
 
433
 
 
434
                lock->last_x_file_name = file_name;
 
435
                lock->last_x_line = (unsigned int) line;
 
436
 
 
437
                /* Locking succeeded, we may return */
 
438
                return(RW_LOCK_EX);
 
439
        }
 
440
 
 
441
        /* Locking did not succeed */
 
442
        return(RW_LOCK_NOT_LOCKED);
 
443
}
 
444
 
 
445
/**********************************************************************
 
446
NOTE! Use the corresponding macro, not directly this function! Lock an
 
447
rw-lock in exclusive mode for the current thread. If the rw-lock is locked
 
448
in shared or exclusive mode, or there is an exclusive lock request waiting,
 
449
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
 
450
for the lock before suspending the thread. If the same thread has an x-lock
 
451
on the rw-lock, locking succeed, with the following exception: if pass != 0,
 
452
only a single x-lock may be taken on the lock. NOTE: If the same thread has
 
453
an s-lock, locking does not succeed! */
 
454
 
 
455
void
 
456
rw_lock_x_lock_func(
 
457
/*================*/
 
458
        rw_lock_t*      lock,   /* in: pointer to rw-lock */
 
459
        ulint           pass,   /* in: pass value; != 0, if the lock will
 
460
                                be passed to another thread to unlock */
 
461
        const char*     file_name,/* in: file name where lock requested */
 
462
        ulint           line)   /* in: line where requested */
 
463
{
 
464
        ulint   index;  /* index of the reserved wait cell */
 
465
        ulint   state;  /* lock state acquired */
 
466
        ulint   i;      /* spin round count */
 
467
 
 
468
        ut_ad(rw_lock_validate(lock));
 
469
 
 
470
lock_loop:
 
471
        /* Acquire the mutex protecting the rw-lock fields */
 
472
        mutex_enter_fast(&(lock->mutex));
 
473
 
 
474
        state = rw_lock_x_lock_low(lock, pass, file_name, line);
 
475
 
 
476
        mutex_exit(&(lock->mutex));
 
477
 
 
478
        if (state == RW_LOCK_EX) {
 
479
 
 
480
                return; /* Locking succeeded */
 
481
 
 
482
        } else if (state == RW_LOCK_NOT_LOCKED) {
 
483
 
 
484
                /* Spin waiting for the writer field to become free */
 
485
                i = 0;
 
486
 
 
487
                while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
 
488
                       && i < SYNC_SPIN_ROUNDS) {
 
489
                        if (srv_spin_wait_delay) {
 
490
                                ut_delay(ut_rnd_interval(0,
 
491
                                                         srv_spin_wait_delay));
 
492
                        }
 
493
 
 
494
                        i++;
 
495
                }
 
496
                if (i == SYNC_SPIN_ROUNDS) {
 
497
                        os_thread_yield();
 
498
                }
 
499
        } else if (state == RW_LOCK_WAIT_EX) {
 
500
 
 
501
                /* Spin waiting for the reader count field to become zero */
 
502
                i = 0;
 
503
 
 
504
                while (rw_lock_get_reader_count(lock) != 0
 
505
                       && i < SYNC_SPIN_ROUNDS) {
 
506
                        if (srv_spin_wait_delay) {
 
507
                                ut_delay(ut_rnd_interval(0,
 
508
                                                         srv_spin_wait_delay));
 
509
                        }
 
510
 
 
511
                        i++;
 
512
                }
 
513
                if (i == SYNC_SPIN_ROUNDS) {
 
514
                        os_thread_yield();
 
515
                }
 
516
        } else {
 
517
                i = 0; /* Eliminate a compiler warning */
 
518
                ut_error;
 
519
        }
 
520
 
 
521
        if (srv_print_latch_waits) {
 
522
                fprintf(stderr,
 
523
                        "Thread %lu spin wait rw-x-lock at %p"
 
524
                        " cfile %s cline %lu rnds %lu\n",
 
525
                        os_thread_pf(os_thread_get_curr_id()), (void*) lock,
 
526
                        lock->cfile_name, (ulong) lock->cline, (ulong) i);
 
527
        }
 
528
 
 
529
        rw_x_spin_wait_count++;
 
530
 
 
531
        /* We try once again to obtain the lock. Acquire the mutex protecting
 
532
        the rw-lock fields */
 
533
 
 
534
        mutex_enter(rw_lock_get_mutex(lock));
 
535
 
 
536
        state = rw_lock_x_lock_low(lock, pass, file_name, line);
 
537
 
 
538
        if (state == RW_LOCK_EX) {
 
539
                mutex_exit(rw_lock_get_mutex(lock));
 
540
 
 
541
                return; /* Locking succeeded */
 
542
        }
 
543
 
 
544
        rw_x_system_call_count++;
 
545
 
 
546
        sync_array_reserve_cell(sync_primary_wait_array,
 
547
                                lock, RW_LOCK_EX,
 
548
                                file_name, line,
 
549
                                &index);
 
550
 
 
551
        rw_lock_set_waiters(lock, 1);
 
552
 
 
553
        mutex_exit(rw_lock_get_mutex(lock));
 
554
 
 
555
        if (srv_print_latch_waits) {
 
556
                fprintf(stderr,
 
557
                        "Thread %lu OS wait for rw-x-lock at %p"
 
558
                        " cfile %s cline %lu\n",
 
559
                        os_thread_pf(os_thread_get_curr_id()), (void*) lock,
 
560
                        lock->cfile_name, (ulong) lock->cline);
 
561
        }
 
562
 
 
563
        rw_x_system_call_count++;
 
564
        rw_x_os_wait_count++;
 
565
 
 
566
        sync_array_wait_event(sync_primary_wait_array, index);
 
567
 
 
568
        goto lock_loop;
 
569
}
 
570
 
 
571
#ifdef UNIV_SYNC_DEBUG
 
572
/**********************************************************************
 
573
Acquires the debug mutex. We cannot use the mutex defined in sync0sync,
 
574
because the debug mutex is also acquired in sync0arr while holding the OS
 
575
mutex protecting the sync array, and the ordinary mutex_enter might
 
576
recursively call routines in sync0arr, leading to a deadlock on the OS
 
577
mutex. */
 
578
 
 
579
void
 
580
rw_lock_debug_mutex_enter(void)
 
581
/*==========================*/
 
582
{
 
583
loop:
 
584
        if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
 
585
                return;
 
586
        }
 
587
 
 
588
        os_event_reset(rw_lock_debug_event);
 
589
 
 
590
        rw_lock_debug_waiters = TRUE;
 
591
 
 
592
        if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
 
593
                return;
 
594
        }
 
595
 
 
596
        os_event_wait(rw_lock_debug_event);
 
597
 
 
598
        goto loop;
 
599
}
 
600
 
 
601
/**********************************************************************
 
602
Releases the debug mutex. */
 
603
 
 
604
void
 
605
rw_lock_debug_mutex_exit(void)
 
606
/*==========================*/
 
607
{
 
608
        mutex_exit(&rw_lock_debug_mutex);
 
609
 
 
610
        if (rw_lock_debug_waiters) {
 
611
                rw_lock_debug_waiters = FALSE;
 
612
                os_event_set(rw_lock_debug_event);
 
613
        }
 
614
}
 
615
 
 
616
/**********************************************************************
 
617
Inserts the debug information for an rw-lock. */
 
618
 
 
619
void
 
620
rw_lock_add_debug_info(
 
621
/*===================*/
 
622
        rw_lock_t*      lock,           /* in: rw-lock */
 
623
        ulint           pass,           /* in: pass value */
 
624
        ulint           lock_type,      /* in: lock type */
 
625
        const char*     file_name,      /* in: file where requested */
 
626
        ulint           line)           /* in: line where requested */
 
627
{
 
628
        rw_lock_debug_t*        info;
 
629
 
 
630
        ut_ad(lock);
 
631
        ut_ad(file_name);
 
632
 
 
633
        info = rw_lock_debug_create();
 
634
 
 
635
        rw_lock_debug_mutex_enter();
 
636
 
 
637
        info->file_name = file_name;
 
638
        info->line      = line;
 
639
        info->lock_type = lock_type;
 
640
        info->thread_id = os_thread_get_curr_id();
 
641
        info->pass      = pass;
 
642
 
 
643
        UT_LIST_ADD_FIRST(list, lock->debug_list, info);
 
644
 
 
645
        rw_lock_debug_mutex_exit();
 
646
 
 
647
        if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
 
648
                sync_thread_add_level(lock, lock->level);
 
649
        }
 
650
}
 
651
 
 
652
/**********************************************************************
 
653
Removes a debug information struct for an rw-lock. */
 
654
 
 
655
void
 
656
rw_lock_remove_debug_info(
 
657
/*======================*/
 
658
        rw_lock_t*      lock,           /* in: rw-lock */
 
659
        ulint           pass,           /* in: pass value */
 
660
        ulint           lock_type)      /* in: lock type */
 
661
{
 
662
        rw_lock_debug_t*        info;
 
663
 
 
664
        ut_ad(lock);
 
665
 
 
666
        if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
 
667
                sync_thread_reset_level(lock);
 
668
        }
 
669
 
 
670
        rw_lock_debug_mutex_enter();
 
671
 
 
672
        info = UT_LIST_GET_FIRST(lock->debug_list);
 
673
 
 
674
        while (info != NULL) {
 
675
                if ((pass == info->pass)
 
676
                    && ((pass != 0)
 
677
                        || os_thread_eq(info->thread_id,
 
678
                                        os_thread_get_curr_id()))
 
679
                    && (info->lock_type == lock_type)) {
 
680
 
 
681
                        /* Found! */
 
682
                        UT_LIST_REMOVE(list, lock->debug_list, info);
 
683
                        rw_lock_debug_mutex_exit();
 
684
 
 
685
                        rw_lock_debug_free(info);
 
686
 
 
687
                        return;
 
688
                }
 
689
 
 
690
                info = UT_LIST_GET_NEXT(list, info);
 
691
        }
 
692
 
 
693
        ut_error;
 
694
}
 
695
#endif /* UNIV_SYNC_DEBUG */
 
696
 
 
697
#ifdef UNIV_SYNC_DEBUG
 
698
/**********************************************************************
 
699
Checks if the thread has locked the rw-lock in the specified mode, with
 
700
the pass value == 0. */
 
701
 
 
702
ibool
 
703
rw_lock_own(
 
704
/*========*/
 
705
                                        /* out: TRUE if locked */
 
706
        rw_lock_t*      lock,           /* in: rw-lock */
 
707
        ulint           lock_type)      /* in: lock type: RW_LOCK_SHARED,
 
708
                                        RW_LOCK_EX */
 
709
{
 
710
        rw_lock_debug_t*        info;
 
711
 
 
712
        ut_ad(lock);
 
713
        ut_ad(rw_lock_validate(lock));
 
714
 
 
715
        mutex_enter(&(lock->mutex));
 
716
 
 
717
        info = UT_LIST_GET_FIRST(lock->debug_list);
 
718
 
 
719
        while (info != NULL) {
 
720
 
 
721
                if (os_thread_eq(info->thread_id, os_thread_get_curr_id())
 
722
                    && (info->pass == 0)
 
723
                    && (info->lock_type == lock_type)) {
 
724
 
 
725
                        mutex_exit(&(lock->mutex));
 
726
                        /* Found! */
 
727
 
 
728
                        return(TRUE);
 
729
                }
 
730
 
 
731
                info = UT_LIST_GET_NEXT(list, info);
 
732
        }
 
733
        mutex_exit(&(lock->mutex));
 
734
 
 
735
        return(FALSE);
 
736
}
 
737
#endif /* UNIV_SYNC_DEBUG */
 
738
 
 
739
/**********************************************************************
 
740
Checks if somebody has locked the rw-lock in the specified mode. */
 
741
 
 
742
ibool
 
743
rw_lock_is_locked(
 
744
/*==============*/
 
745
                                        /* out: TRUE if locked */
 
746
        rw_lock_t*      lock,           /* in: rw-lock */
 
747
        ulint           lock_type)      /* in: lock type: RW_LOCK_SHARED,
 
748
                                        RW_LOCK_EX */
 
749
{
 
750
        ibool   ret     = FALSE;
 
751
 
 
752
        ut_ad(lock);
 
753
        ut_ad(rw_lock_validate(lock));
 
754
 
 
755
        mutex_enter(&(lock->mutex));
 
756
 
 
757
        if (lock_type == RW_LOCK_SHARED) {
 
758
                if (lock->reader_count > 0) {
 
759
                        ret = TRUE;
 
760
                }
 
761
        } else if (lock_type == RW_LOCK_EX) {
 
762
                if (lock->writer == RW_LOCK_EX) {
 
763
                        ret = TRUE;
 
764
                }
 
765
        } else {
 
766
                ut_error;
 
767
        }
 
768
 
 
769
        mutex_exit(&(lock->mutex));
 
770
 
 
771
        return(ret);
 
772
}
 
773
 
 
774
#ifdef UNIV_SYNC_DEBUG
 
775
/*******************************************************************
 
776
Prints debug info of currently locked rw-locks. */
 
777
 
 
778
void
 
779
rw_lock_list_print_info(
 
780
/*====================*/
 
781
        FILE*   file)           /* in: file where to print */
 
782
{
 
783
        rw_lock_t*      lock;
 
784
        ulint           count           = 0;
 
785
        rw_lock_debug_t* info;
 
786
 
 
787
        mutex_enter(&rw_lock_list_mutex);
 
788
 
 
789
        fputs("-------------\n"
 
790
              "RW-LATCH INFO\n"
 
791
              "-------------\n", file);
 
792
 
 
793
        lock = UT_LIST_GET_FIRST(rw_lock_list);
 
794
 
 
795
        while (lock != NULL) {
 
796
 
 
797
                count++;
 
798
 
 
799
                mutex_enter(&(lock->mutex));
 
800
 
 
801
                if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
 
802
                    || (rw_lock_get_reader_count(lock) != 0)
 
803
                    || (rw_lock_get_waiters(lock) != 0)) {
 
804
 
 
805
                        fprintf(file, "RW-LOCK: %p ", (void*) lock);
 
806
 
 
807
                        if (rw_lock_get_waiters(lock)) {
 
808
                                fputs(" Waiters for the lock exist\n", file);
 
809
                        } else {
 
810
                                putc('\n', file);
 
811
                        }
 
812
 
 
813
                        info = UT_LIST_GET_FIRST(lock->debug_list);
 
814
                        while (info != NULL) {
 
815
                                rw_lock_debug_print(info);
 
816
                                info = UT_LIST_GET_NEXT(list, info);
 
817
                        }
 
818
                }
 
819
 
 
820
                mutex_exit(&(lock->mutex));
 
821
                lock = UT_LIST_GET_NEXT(list, lock);
 
822
        }
 
823
 
 
824
        fprintf(file, "Total number of rw-locks %ld\n", count);
 
825
        mutex_exit(&rw_lock_list_mutex);
 
826
}
 
827
 
 
828
/*******************************************************************
 
829
Prints debug info of an rw-lock. */
 
830
 
 
831
void
 
832
rw_lock_print(
 
833
/*==========*/
 
834
        rw_lock_t*      lock)   /* in: rw-lock */
 
835
{
 
836
        rw_lock_debug_t* info;
 
837
 
 
838
        fprintf(stderr,
 
839
                "-------------\n"
 
840
                "RW-LATCH INFO\n"
 
841
                "RW-LATCH: %p ", (void*) lock);
 
842
 
 
843
        if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
 
844
            || (rw_lock_get_reader_count(lock) != 0)
 
845
            || (rw_lock_get_waiters(lock) != 0)) {
 
846
 
 
847
                if (rw_lock_get_waiters(lock)) {
 
848
                        fputs(" Waiters for the lock exist\n", stderr);
 
849
                } else {
 
850
                        putc('\n', stderr);
 
851
                }
 
852
 
 
853
                info = UT_LIST_GET_FIRST(lock->debug_list);
 
854
                while (info != NULL) {
 
855
                        rw_lock_debug_print(info);
 
856
                        info = UT_LIST_GET_NEXT(list, info);
 
857
                }
 
858
        }
 
859
}
 
860
 
 
861
/*************************************************************************
 
862
Prints info of a debug struct. */
 
863
 
 
864
void
 
865
rw_lock_debug_print(
 
866
/*================*/
 
867
        rw_lock_debug_t*        info)   /* in: debug struct */
 
868
{
 
869
        ulint   rwt;
 
870
 
 
871
        rwt       = info->lock_type;
 
872
 
 
873
        fprintf(stderr, "Locked: thread %ld file %s line %ld  ",
 
874
                (ulong) os_thread_pf(info->thread_id), info->file_name,
 
875
                (ulong) info->line);
 
876
        if (rwt == RW_LOCK_SHARED) {
 
877
                fputs("S-LOCK", stderr);
 
878
        } else if (rwt == RW_LOCK_EX) {
 
879
                fputs("X-LOCK", stderr);
 
880
        } else if (rwt == RW_LOCK_WAIT_EX) {
 
881
                fputs("WAIT X-LOCK", stderr);
 
882
        } else {
 
883
                ut_error;
 
884
        }
 
885
        if (info->pass != 0) {
 
886
                fprintf(stderr, " pass value %lu", (ulong) info->pass);
 
887
        }
 
888
        putc('\n', stderr);
 
889
}
 
890
 
 
891
/*******************************************************************
 
892
Returns the number of currently locked rw-locks. Works only in the debug
 
893
version. */
 
894
 
 
895
ulint
 
896
rw_lock_n_locked(void)
 
897
/*==================*/
 
898
{
 
899
        rw_lock_t*      lock;
 
900
        ulint           count           = 0;
 
901
 
 
902
        mutex_enter(&rw_lock_list_mutex);
 
903
 
 
904
        lock = UT_LIST_GET_FIRST(rw_lock_list);
 
905
 
 
906
        while (lock != NULL) {
 
907
                mutex_enter(rw_lock_get_mutex(lock));
 
908
 
 
909
                if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
 
910
                    || (rw_lock_get_reader_count(lock) != 0)) {
 
911
                        count++;
 
912
                }
 
913
 
 
914
                mutex_exit(rw_lock_get_mutex(lock));
 
915
                lock = UT_LIST_GET_NEXT(list, lock);
 
916
        }
 
917
 
 
918
        mutex_exit(&rw_lock_list_mutex);
 
919
 
 
920
        return(count);
 
921
}
 
922
#endif /* UNIV_SYNC_DEBUG */