~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2009-07-11 19:23:04 UTC
  • mfrom: (1089.1.14 merge)
  • Revision ID: brian@gaz-20090711192304-ootijyl5yf9jq9kd
Merge Brian

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 */