~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Eric Day
  • Date: 2009-03-13 04:15:45 UTC
  • mto: (968.1.1 lib-merge)
  • mto: This revision was merged to the branch mainline in revision 969.
  • Revision ID: eday@oddments.org-20090313041545-fzgj8f26s10rcsv7
Started client changes.

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