~jaypipes/drizzle/new-test-runner

« back to all changes in this revision

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

  • Committer: Jay Pipes
  • Date: 2008-12-11 17:52:34 UTC
  • mfrom: (482.16.152 testable)
  • Revision ID: jpipes@serialcoder-20081211175234-uqsfvmgxejvmellq
merge with trunk

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