~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2009-02-05 09:11:16 UTC
  • Revision ID: brian@tangent.org-20090205091116-iy0ersp6bhyzt1ad
Removed dead variables.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
4
 
Copyright (C) 2008, Google Inc.
5
 
 
6
 
Portions of this file contain modifications contributed and copyrighted by
7
 
Google, Inc. Those modifications are gratefully acknowledged and are described
8
 
briefly in the InnoDB documentation. The contributions by Google are
9
 
incorporated with their permission, and subject to the conditions contained in
10
 
the file COPYING.Google.
11
 
 
12
 
This program is free software; you can redistribute it and/or modify it under
13
 
the terms of the GNU General Public License as published by the Free Software
14
 
Foundation; version 2 of the License.
15
 
 
16
 
This program is distributed in the hope that it will be useful, but WITHOUT
17
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19
 
 
20
 
You should have received a copy of the GNU General Public License along with
21
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22
 
St, Fifth Floor, Boston, MA 02110-1301 USA
23
 
 
24
 
*****************************************************************************/
25
 
 
26
 
/**************************************************//**
27
 
@file sync/sync0rw.c
 
1
/******************************************************
28
2
The read-write lock (for thread synchronization)
29
3
 
 
4
(c) 1995 Innobase Oy
 
5
 
30
6
Created 9/11/1995 Heikki Tuuri
31
7
*******************************************************/
32
8
 
38
14
#include "os0thread.h"
39
15
#include "mem0mem.h"
40
16
#include "srv0srv.h"
41
 
#include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */
42
 
 
43
 
/*
44
 
        IMPLEMENTATION OF THE RW_LOCK
45
 
        =============================
46
 
The status of a rw_lock is held in lock_word. The initial value of lock_word is
47
 
X_LOCK_DECR. lock_word is decremented by 1 for each s-lock and by X_LOCK_DECR
48
 
for each x-lock. This describes the lock state for each value of lock_word:
49
 
 
50
 
lock_word == X_LOCK_DECR:      Unlocked.
51
 
0 < lock_word < X_LOCK_DECR:   Read locked, no waiting writers.
52
 
                               (X_LOCK_DECR - lock_word) is the
53
 
                               number of readers that hold the lock.
54
 
lock_word == 0:                Write locked
55
 
-X_LOCK_DECR < lock_word < 0:  Read locked, with a waiting writer.
56
 
                               (-lock_word) is the number of readers
57
 
                               that hold the lock.
58
 
lock_word <= -X_LOCK_DECR:     Recursively write locked. lock_word has been
59
 
                               decremented by X_LOCK_DECR once for each lock,
60
 
                               so the number of locks is:
61
 
                               ((-lock_word) / X_LOCK_DECR) + 1
62
 
When lock_word <= -X_LOCK_DECR, we also know that lock_word % X_LOCK_DECR == 0:
63
 
other values of lock_word are invalid.
64
 
 
65
 
The lock_word is always read and updated atomically and consistently, so that
66
 
it always represents the state of the lock, and the state of the lock changes
67
 
with a single atomic operation. This lock_word holds all of the information
68
 
that a thread needs in order to determine if it is eligible to gain the lock
69
 
or if it must spin or sleep. The one exception to this is that writer_thread
70
 
must be verified before recursive write locks: to solve this scenario, we make
71
 
writer_thread readable by all threads, but only writeable by the x-lock holder.
72
 
 
73
 
The other members of the lock obey the following rules to remain consistent:
74
 
 
75
 
recursive:      This and the writer_thread field together control the
76
 
                behaviour of recursive x-locking.
77
 
                lock->recursive must be FALSE in following states:
78
 
                        1) The writer_thread contains garbage i.e.: the
79
 
                        lock has just been initialized.
80
 
                        2) The lock is not x-held and there is no
81
 
                        x-waiter waiting on WAIT_EX event.
82
 
                        3) The lock is x-held or there is an x-waiter
83
 
                        waiting on WAIT_EX event but the 'pass' value
84
 
                        is non-zero.
85
 
                lock->recursive is TRUE iff:
86
 
                        1) The lock is x-held or there is an x-waiter
87
 
                        waiting on WAIT_EX event and the 'pass' value
88
 
                        is zero.
89
 
                This flag must be set after the writer_thread field
90
 
                has been updated with a memory ordering barrier.
91
 
                It is unset before the lock_word has been incremented.
92
 
writer_thread:  Is used only in recursive x-locking. Can only be safely
93
 
                read iff lock->recursive flag is TRUE.
94
 
                This field is uninitialized at lock creation time and
95
 
                is updated atomically when x-lock is acquired or when
96
 
                move_ownership is called. A thread is only allowed to
97
 
                set the value of this field to it's thread_id i.e.: a
98
 
                thread cannot set writer_thread to some other thread's
99
 
                id.
100
 
waiters:        May be set to 1 anytime, but to avoid unnecessary wake-up
101
 
                signals, it should only be set to 1 when there are threads
102
 
                waiting on event. Must be 1 when a writer starts waiting to
103
 
                ensure the current x-locking thread sends a wake-up signal
104
 
                during unlock. May only be reset to 0 immediately before a
105
 
                a wake-up signal is sent to event. On most platforms, a
106
 
                memory barrier is required after waiters is set, and before
107
 
                verifying lock_word is still held, to ensure some unlocker
108
 
                really does see the flags new value.
109
 
event:          Threads wait on event for read or writer lock when another
110
 
                thread has an x-lock or an x-lock reservation (wait_ex). A
111
 
                thread may only wait on event after performing the following
112
 
                actions in order:
113
 
                   (1) Record the counter value of event (with os_event_reset).
114
 
                   (2) Set waiters to 1.
115
 
                   (3) Verify lock_word <= 0.
116
 
                (1) must come before (2) to ensure signal is not missed.
117
 
                (2) must come before (3) to ensure a signal is sent.
118
 
                These restrictions force the above ordering.
119
 
                Immediately before sending the wake-up signal, we should:
120
 
                   (1) Verify lock_word == X_LOCK_DECR (unlocked)
121
 
                   (2) Reset waiters to 0.
122
 
wait_ex_event:  A thread may only wait on the wait_ex_event after it has
123
 
                performed the following actions in order:
124
 
                   (1) Decrement lock_word by X_LOCK_DECR.
125
 
                   (2) Record counter value of wait_ex_event (os_event_reset,
126
 
                       called from sync_array_reserve_cell).
127
 
                   (3) Verify that lock_word < 0.
128
 
                (1) must come first to ensures no other threads become reader
129
 
                or next writer, and notifies unlocker that signal must be sent.
130
 
                (2) must come before (3) to ensure the signal is not missed.
131
 
                These restrictions force the above ordering.
132
 
                Immediately before sending the wake-up signal, we should:
133
 
                   Verify lock_word == 0 (waiting thread holds x_lock)
134
 
*/
135
 
 
136
 
 
137
 
/** number of spin waits on rw-latches,
138
 
resulted during shared (read) locks */
139
 
UNIV_INTERN ib_int64_t  rw_s_spin_wait_count    = 0;
140
 
/** number of spin loop rounds on rw-latches,
141
 
resulted during shared (read) locks */
142
 
UNIV_INTERN ib_int64_t  rw_s_spin_round_count   = 0;
143
 
 
144
 
/** number of OS waits on rw-latches,
145
 
resulted during shared (read) locks */
146
 
UNIV_INTERN ib_int64_t  rw_s_os_wait_count      = 0;
147
 
 
148
 
/** number of unlocks (that unlock shared locks),
149
 
set only when UNIV_SYNC_PERF_STAT is defined */
150
 
UNIV_INTERN ib_int64_t  rw_s_exit_count         = 0;
151
 
 
152
 
/** number of spin waits on rw-latches,
153
 
resulted during exclusive (write) locks */
154
 
UNIV_INTERN ib_int64_t  rw_x_spin_wait_count    = 0;
155
 
/** number of spin loop rounds on rw-latches,
156
 
resulted during exclusive (write) locks */
157
 
UNIV_INTERN ib_int64_t  rw_x_spin_round_count   = 0;
158
 
 
159
 
/** number of OS waits on rw-latches,
160
 
resulted during exclusive (write) locks */
161
 
UNIV_INTERN ib_int64_t  rw_x_os_wait_count      = 0;
162
 
 
163
 
/** number of unlocks (that unlock exclusive locks),
164
 
set only when UNIV_SYNC_PERF_STAT is defined */
165
 
UNIV_INTERN ib_int64_t  rw_x_exit_count         = 0;
 
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;
166
47
 
167
48
/* The global list of rw-locks */
168
49
UNIV_INTERN rw_lock_list_t      rw_lock_list;
169
50
UNIV_INTERN mutex_t             rw_lock_list_mutex;
170
51
 
171
 
#ifdef UNIV_PFS_MUTEX
172
 
UNIV_INTERN mysql_pfs_key_t     rw_lock_list_mutex_key;
173
 
UNIV_INTERN mysql_pfs_key_t     rw_lock_mutex_key;
174
 
#endif /* UNIV_PFS_MUTEX */
175
 
 
176
52
#ifdef UNIV_SYNC_DEBUG
177
53
/* The global mutex which protects debug info lists of all rw-locks.
178
54
To modify the debug info list of an rw-lock, this mutex has to be
179
55
acquired in addition to the mutex protecting the lock. */
180
56
 
181
57
UNIV_INTERN mutex_t             rw_lock_debug_mutex;
182
 
 
183
 
# ifdef UNIV_PFS_MUTEX
184
 
UNIV_INTERN mysql_pfs_key_t     rw_lock_debug_mutex_key;
185
 
# endif
186
 
 
187
58
/* If deadlock detection does not get immediately the mutex,
188
59
it may wait for this event */
189
60
UNIV_INTERN os_event_t          rw_lock_debug_event;
190
61
/* This is set to TRUE, if there may be waiters for the event */
191
62
UNIV_INTERN ibool               rw_lock_debug_waiters;
192
63
 
193
 
/******************************************************************//**
 
64
/**********************************************************************
194
65
Creates a debug info struct. */
195
66
static
196
67
rw_lock_debug_t*
197
68
rw_lock_debug_create(void);
198
69
/*======================*/
199
 
/******************************************************************//**
 
70
/**********************************************************************
200
71
Frees a debug info struct. */
201
72
static
202
73
void
204
75
/*===============*/
205
76
        rw_lock_debug_t* info);
206
77
 
207
 
/******************************************************************//**
208
 
Creates a debug info struct.
209
 
@return own: debug info struct */
 
78
/**********************************************************************
 
79
Creates a debug info struct. */
210
80
static
211
81
rw_lock_debug_t*
212
82
rw_lock_debug_create(void)
215
85
        return((rw_lock_debug_t*) mem_alloc(sizeof(rw_lock_debug_t)));
216
86
}
217
87
 
218
 
/******************************************************************//**
 
88
/**********************************************************************
219
89
Frees a debug info struct. */
220
90
static
221
91
void
227
97
}
228
98
#endif /* UNIV_SYNC_DEBUG */
229
99
 
230
 
/******************************************************************//**
 
100
/**********************************************************************
231
101
Creates, or rather, initializes an rw-lock object in a specified memory
232
102
location (which must be appropriately aligned). The rw-lock is initialized
233
103
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
236
106
void
237
107
rw_lock_create_func(
238
108
/*================*/
239
 
        rw_lock_t*      lock,           /*!< in: pointer to memory */
 
109
        rw_lock_t*      lock,           /* in: pointer to memory */
240
110
#ifdef UNIV_DEBUG
241
111
# ifdef UNIV_SYNC_DEBUG
242
 
        ulint           level,          /*!< in: level */
 
112
        ulint           level,          /* in: level */
243
113
# endif /* UNIV_SYNC_DEBUG */
244
 
        const char*     cmutex_name,    /*!< in: mutex name */
 
114
        const char*     cmutex_name,    /* in: mutex name */
245
115
#endif /* UNIV_DEBUG */
246
 
        const char*     cfile_name,     /*!< in: file name where created */
247
 
        ulint           cline)          /*!< in: file line where created */
 
116
        const char*     cfile_name,     /* in: file name where created */
 
117
        ulint           cline)          /* in: file line where created */
248
118
{
249
119
        /* If this is the very first time a synchronization object is
250
120
        created, then the following call initializes the sync system. */
251
121
 
252
 
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
253
 
        mutex_create(rw_lock_mutex_key, rw_lock_get_mutex(lock),
254
 
                     SYNC_NO_ORDER_CHECK);
 
122
        mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
255
123
 
256
124
        lock->mutex.cfile_name = cfile_name;
257
125
        lock->mutex.cline = cline;
258
126
 
259
 
        ut_d(lock->mutex.cmutex_name = cmutex_name);
260
 
        ut_d(lock->mutex.mutex_type = 1);
261
 
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
262
 
# ifdef UNIV_DEBUG
263
 
        UT_NOT_USED(cmutex_name);
264
 
# endif
265
 
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
266
 
 
267
 
        lock->lock_word = X_LOCK_DECR;
268
 
        lock->waiters = 0;
269
 
 
270
 
        /* We set this value to signify that lock->writer_thread
271
 
        contains garbage at initialization and cannot be used for
272
 
        recursive x-locking. */
273
 
        lock->recursive = FALSE;
 
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;
274
138
 
275
139
#ifdef UNIV_SYNC_DEBUG
276
140
        UT_LIST_INIT(lock->debug_list);
278
142
        lock->level = level;
279
143
#endif /* UNIV_SYNC_DEBUG */
280
144
 
281
 
        ut_d(lock->magic_n = RW_LOCK_MAGIC_N);
 
145
        lock->magic_n = RW_LOCK_MAGIC_N;
282
146
 
283
147
        lock->cfile_name = cfile_name;
284
148
        lock->cline = (unsigned int) cline;
285
149
 
286
 
        lock->count_os_wait = 0;
287
150
        lock->last_s_file_name = "not yet reserved";
288
151
        lock->last_x_file_name = "not yet reserved";
289
152
        lock->last_s_line = 0;
290
153
        lock->last_x_line = 0;
291
154
        lock->event = os_event_create(NULL);
 
155
 
 
156
#ifdef __WIN__
292
157
        lock->wait_ex_event = os_event_create(NULL);
 
158
#endif
293
159
 
294
160
        mutex_enter(&rw_lock_list_mutex);
295
161
 
296
 
        ut_ad(UT_LIST_GET_FIRST(rw_lock_list) == NULL
297
 
              || UT_LIST_GET_FIRST(rw_lock_list)->magic_n == RW_LOCK_MAGIC_N);
 
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
        }
298
166
 
299
167
        UT_LIST_ADD_FIRST(list, rw_lock_list, lock);
300
168
 
301
169
        mutex_exit(&rw_lock_list_mutex);
302
170
}
303
171
 
304
 
/******************************************************************//**
 
172
/**********************************************************************
305
173
Calling this function is obligatory only if the memory buffer containing
306
174
the rw-lock is freed. Removes an rw-lock object from the global list. The
307
175
rw-lock is checked to be in the non-locked state. */
308
176
UNIV_INTERN
309
177
void
310
 
rw_lock_free_func(
311
 
/*==============*/
312
 
        rw_lock_t*      lock)   /*!< in: rw-lock */
 
178
rw_lock_free(
 
179
/*=========*/
 
180
        rw_lock_t*      lock)   /* in: rw-lock */
313
181
{
314
182
        ut_ad(rw_lock_validate(lock));
315
 
        ut_a(lock->lock_word == X_LOCK_DECR);
316
 
 
317
 
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
 
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
 
318
189
        mutex_free(rw_lock_get_mutex(lock));
319
 
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
320
190
 
321
191
        mutex_enter(&rw_lock_list_mutex);
322
192
        os_event_free(lock->event);
323
193
 
 
194
#ifdef __WIN__
324
195
        os_event_free(lock->wait_ex_event);
 
196
#endif
325
197
 
326
 
        ut_ad(UT_LIST_GET_PREV(list, lock) == NULL
327
 
              || UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
328
 
        ut_ad(UT_LIST_GET_NEXT(list, lock) == NULL
329
 
              || UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N);
 
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
        }
330
204
 
331
205
        UT_LIST_REMOVE(list, rw_lock_list, lock);
332
206
 
333
207
        mutex_exit(&rw_lock_list_mutex);
334
 
 
335
 
        ut_d(lock->magic_n = 0);
336
208
}
337
209
 
338
210
#ifdef UNIV_DEBUG
339
 
/******************************************************************//**
 
211
/**********************************************************************
340
212
Checks that the rw-lock has been initialized and that there are no
341
 
simultaneous shared and exclusive locks.
342
 
@return TRUE */
 
213
simultaneous shared and exclusive locks. */
343
214
UNIV_INTERN
344
215
ibool
345
216
rw_lock_validate(
346
217
/*=============*/
347
 
        rw_lock_t*      lock)   /*!< in: rw-lock */
 
218
        rw_lock_t*      lock)
348
219
{
349
 
        ulint   waiters;
350
 
        lint    lock_word;
351
 
 
352
220
        ut_a(lock);
353
221
 
354
 
        waiters = rw_lock_get_waiters(lock);
355
 
        lock_word = lock->lock_word;
356
 
 
357
 
        ut_ad(lock->magic_n == RW_LOCK_MAGIC_N);
358
 
        ut_a(waiters == 0 || waiters == 1);
359
 
        ut_a(lock_word > -X_LOCK_DECR ||(-lock_word) % X_LOCK_DECR == 0);
 
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));
360
235
 
361
236
        return(TRUE);
362
237
}
363
238
#endif /* UNIV_DEBUG */
364
239
 
365
 
/******************************************************************//**
 
240
/**********************************************************************
366
241
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
367
242
locked in exclusive mode, or there is an exclusive lock request waiting,
368
243
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
371
246
void
372
247
rw_lock_s_lock_spin(
373
248
/*================*/
374
 
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
375
 
        ulint           pass,   /*!< in: pass value; != 0, if the lock
 
249
        rw_lock_t*      lock,   /* in: pointer to rw-lock */
 
250
        ulint           pass,   /* in: pass value; != 0, if the lock
376
251
                                will be passed to another thread to unlock */
377
 
        const char*     file_name, /*!< in: file name where lock requested */
378
 
        ulint           line)   /*!< in: line where requested */
 
252
        const char*     file_name, /* in: file name where lock requested */
 
253
        ulint           line)   /* in: line where requested */
379
254
{
380
255
        ulint    index; /* index of the reserved wait cell */
381
 
        ulint    i = 0; /* spin round count */
 
256
        ulint    i;     /* spin round count */
382
257
 
383
258
        ut_ad(rw_lock_validate(lock));
384
259
 
385
 
        rw_s_spin_wait_count++; /*!< Count calls to this function */
386
260
lock_loop:
 
261
        rw_s_spin_wait_count++;
387
262
 
388
263
        /* Spin waiting for the writer field to become free */
389
 
        while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
 
264
        i = 0;
 
265
 
 
266
        while (rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED
 
267
               && i < SYNC_SPIN_ROUNDS) {
390
268
                if (srv_spin_wait_delay) {
391
269
                        ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
392
270
                }
407
285
                        lock->cfile_name, (ulong) lock->cline, (ulong) i);
408
286
        }
409
287
 
 
288
        mutex_enter(rw_lock_get_mutex(lock));
 
289
 
410
290
        /* We try once again to obtain the lock */
 
291
 
411
292
        if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
412
 
                rw_s_spin_round_count += i;
 
293
                mutex_exit(rw_lock_get_mutex(lock));
413
294
 
414
295
                return; /* Success */
415
296
        } else {
416
 
 
417
 
                if (i < SYNC_SPIN_ROUNDS) {
418
 
                        goto lock_loop;
419
 
                }
420
 
 
421
 
                rw_s_spin_round_count += i;
 
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++;
422
301
 
423
302
                sync_array_reserve_cell(sync_primary_wait_array,
424
303
                                        lock, RW_LOCK_SHARED,
425
304
                                        file_name, line,
426
305
                                        &index);
427
306
 
428
 
                /* Set waiters before checking lock_word to ensure wake-up
429
 
                signal is sent. This may lead to some unnecessary signals. */
430
 
                rw_lock_set_waiter_flag(lock);
 
307
                rw_lock_set_waiters(lock, 1);
431
308
 
432
 
                if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
433
 
                        sync_array_free_cell(sync_primary_wait_array, index);
434
 
                        return; /* Success */
435
 
                }
 
309
                mutex_exit(rw_lock_get_mutex(lock));
436
310
 
437
311
                if (srv_print_latch_waits) {
438
312
                        fprintf(stderr,
443
317
                                (ulong) lock->cline);
444
318
                }
445
319
 
446
 
                /* these stats may not be accurate */
447
 
                lock->count_os_wait++;
 
320
                rw_s_system_call_count++;
448
321
                rw_s_os_wait_count++;
449
322
 
450
323
                sync_array_wait_event(sync_primary_wait_array, index);
451
324
 
452
 
                i = 0;
453
325
                goto lock_loop;
454
326
        }
455
327
}
456
328
 
457
 
/******************************************************************//**
 
329
/**********************************************************************
458
330
This function is used in the insert buffer to move the ownership of an
459
331
x-latch on a buffer frame to the current thread. The x-latch was set by
460
332
the buffer read operation and it protected the buffer frame while the
466
338
void
467
339
rw_lock_x_lock_move_ownership(
468
340
/*==========================*/
469
 
        rw_lock_t*      lock)   /*!< in: lock which was x-locked in the
 
341
        rw_lock_t*      lock)   /* in: lock which was x-locked in the
470
342
                                buffer read */
471
343
{
472
344
        ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
473
345
 
474
 
        rw_lock_set_writer_id_and_recursion_flag(lock, TRUE);
 
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));
475
353
}
476
354
 
477
 
/******************************************************************//**
478
 
Function for the next writer to call. Waits for readers to exit.
479
 
The caller must have already decremented lock_word by X_LOCK_DECR. */
 
355
/**********************************************************************
 
356
Low-level function for acquiring an exclusive lock. */
480
357
UNIV_INLINE
481
 
void
482
 
rw_lock_x_lock_wait(
483
 
/*================*/
484
 
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
485
 
#ifdef UNIV_SYNC_DEBUG
486
 
        ulint           pass,   /*!< in: pass value; != 0, if the lock will
 
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
487
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);
488
384
#endif
489
 
        const char*     file_name,/*!< in: file name where lock requested */
490
 
        ulint           line)   /*!< in: line where requested */
491
 
{
492
 
        ulint index;
493
 
        ulint i = 0;
494
 
 
495
 
        ut_ad(lock->lock_word <= 0);
496
 
 
497
 
        while (lock->lock_word < 0) {
498
 
                if (srv_spin_wait_delay) {
499
 
                        ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
500
 
                }
501
 
                if(i < SYNC_SPIN_ROUNDS) {
502
 
                        i++;
503
 
                        continue;
504
 
                }
505
 
 
506
 
                /* If there is still a reader, then go to sleep.*/
507
 
                rw_x_spin_round_count += i;
508
 
                i = 0;
509
 
                sync_array_reserve_cell(sync_primary_wait_array,
510
 
                                        lock,
511
 
                                        RW_LOCK_WAIT_EX,
512
 
                                        file_name, line,
513
 
                                        &index);
514
 
                /* Check lock_word to ensure wake-up isn't missed.*/
515
 
                if(lock->lock_word < 0) {
516
 
 
517
 
                        /* these stats may not be accurate */
518
 
                        lock->count_os_wait++;
519
 
                        rw_x_os_wait_count++;
520
 
 
521
 
                        /* Add debug info as it is needed to detect possible
522
 
                        deadlock. We must add info for WAIT_EX thread for
523
 
                        deadlock detection to work properly. */
 
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
 
524
397
#ifdef UNIV_SYNC_DEBUG
525
398
                        rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
526
399
                                               file_name, line);
527
400
#endif
528
401
 
529
 
                        sync_array_wait_event(sync_primary_wait_array,
530
 
                                              index);
531
 
#ifdef UNIV_SYNC_DEBUG
532
 
                        rw_lock_remove_debug_info(lock, pass,
533
 
                                               RW_LOCK_WAIT_EX);
534
 
#endif
535
 
                        /* It is possible to wake when lock_word < 0.
536
 
                        We must pass the while-loop check to proceed.*/
537
 
                } else {
538
 
                        sync_array_free_cell(sync_primary_wait_array,
539
 
                                             index);
540
 
                }
541
 
        }
542
 
        rw_x_spin_round_count += i;
543
 
}
544
 
 
545
 
/******************************************************************//**
546
 
Low-level function for acquiring an exclusive lock.
547
 
@return RW_LOCK_NOT_LOCKED if did not succeed, RW_LOCK_EX if success. */
548
 
UNIV_INLINE
549
 
ibool
550
 
rw_lock_x_lock_low(
551
 
/*===============*/
552
 
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
553
 
        ulint           pass,   /*!< in: pass value; != 0, if the lock will
554
 
                                be passed to another thread to unlock */
555
 
        const char*     file_name,/*!< in: file name where lock requested */
556
 
        ulint           line)   /*!< in: line where requested */
557
 
{
558
 
        os_thread_id_t  curr_thread     = os_thread_get_curr_id();
559
 
 
560
 
        if (rw_lock_lock_word_decr(lock, X_LOCK_DECR)) {
561
 
 
562
 
                /* lock->recursive also tells us if the writer_thread
563
 
                field is stale or active. As we are going to write
564
 
                our own thread id in that field it must be that the
565
 
                current writer_thread value is not active. */
566
 
                ut_a(!lock->recursive);
567
 
 
568
 
                /* Decrement occurred: we are writer or next-writer. */
569
 
                rw_lock_set_writer_id_and_recursion_flag(lock,
570
 
                                                pass ? FALSE : TRUE);
571
 
 
572
 
                rw_lock_x_lock_wait(lock,
573
 
#ifdef UNIV_SYNC_DEBUG
574
 
                                    pass,
575
 
#endif
576
 
                                    file_name, line);
577
 
 
578
 
        } else {
579
 
                /* Decrement failed: relock or failed lock */
580
 
                if (!pass && lock->recursive
581
 
                    && os_thread_eq(lock->writer_thread, curr_thread)) {
582
 
                        /* Relock */
583
 
                        lock->lock_word -= X_LOCK_DECR;
584
 
                } else {
585
 
                        /* Another thread locked before us */
586
 
                        return(FALSE);
587
 
                }
588
 
        }
589
 
#ifdef UNIV_SYNC_DEBUG
590
 
        rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
591
 
                               file_name, line);
592
 
#endif
593
 
        lock->last_x_file_name = file_name;
594
 
        lock->last_x_line = (unsigned int) line;
595
 
 
596
 
        return(TRUE);
597
 
}
598
 
 
599
 
/******************************************************************//**
 
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
/**********************************************************************
600
456
NOTE! Use the corresponding macro, not directly this function! Lock an
601
457
rw-lock in exclusive mode for the current thread. If the rw-lock is locked
602
458
in shared or exclusive mode, or there is an exclusive lock request waiting,
609
465
void
610
466
rw_lock_x_lock_func(
611
467
/*================*/
612
 
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
613
 
        ulint           pass,   /*!< in: pass value; != 0, if the lock will
 
468
        rw_lock_t*      lock,   /* in: pointer to rw-lock */
 
469
        ulint           pass,   /* in: pass value; != 0, if the lock will
614
470
                                be passed to another thread to unlock */
615
 
        const char*     file_name,/*!< in: file name where lock requested */
616
 
        ulint           line)   /*!< in: line where requested */
 
471
        const char*     file_name,/* in: file name where lock requested */
 
472
        ulint           line)   /* in: line where requested */
617
473
{
618
 
        ulint   index;  /*!< index of the reserved wait cell */
619
 
        ulint   i;      /*!< spin round count */
620
 
        ibool   spinning = FALSE;
 
474
        ulint   index;  /* index of the reserved wait cell */
 
475
        ulint   state;  /* lock state acquired */
 
476
        ulint   i;      /* spin round count */
621
477
 
622
478
        ut_ad(rw_lock_validate(lock));
623
479
 
624
 
        i = 0;
625
 
 
626
480
lock_loop:
627
 
 
628
 
        if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
629
 
                rw_x_spin_round_count += i;
 
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) {
630
489
 
631
490
                return; /* Locking succeeded */
632
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
                }
633
526
        } else {
634
 
 
635
 
                if (!spinning) {
636
 
                        spinning = TRUE;
637
 
                        rw_x_spin_wait_count++;
638
 
                }
639
 
 
640
 
                /* Spin waiting for the lock_word to become free */
641
 
                while (i < SYNC_SPIN_ROUNDS
642
 
                       && lock->lock_word <= 0) {
643
 
                        if (srv_spin_wait_delay) {
644
 
                                ut_delay(ut_rnd_interval(0,
645
 
                                                         srv_spin_wait_delay));
646
 
                        }
647
 
 
648
 
                        i++;
649
 
                }
650
 
                if (i == SYNC_SPIN_ROUNDS) {
651
 
                        os_thread_yield();
652
 
                } else {
653
 
                        goto lock_loop;
654
 
                }
 
527
                i = 0; /* Eliminate a compiler warning */
 
528
                ut_error;
655
529
        }
656
530
 
657
 
        rw_x_spin_round_count += i;
658
 
 
659
531
        if (srv_print_latch_waits) {
660
532
                fprintf(stderr,
661
533
                        "Thread %lu spin wait rw-x-lock at %p"
664
536
                        lock->cfile_name, (ulong) lock->cline, (ulong) i);
665
537
        }
666
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
 
667
556
        sync_array_reserve_cell(sync_primary_wait_array,
668
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
669
565
                                RW_LOCK_EX,
670
566
                                file_name, line,
671
567
                                &index);
672
568
 
673
 
        /* Waiters must be set before checking lock_word, to ensure signal
674
 
        is sent. This could lead to a few unnecessary wake-up signals. */
675
 
        rw_lock_set_waiter_flag(lock);
 
569
        rw_lock_set_waiters(lock, 1);
676
570
 
677
 
        if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
678
 
                sync_array_free_cell(sync_primary_wait_array, index);
679
 
                return; /* Locking succeeded */
680
 
        }
 
571
        mutex_exit(rw_lock_get_mutex(lock));
681
572
 
682
573
        if (srv_print_latch_waits) {
683
574
                fprintf(stderr,
687
578
                        lock->cfile_name, (ulong) lock->cline);
688
579
        }
689
580
 
690
 
        /* these stats may not be accurate */
691
 
        lock->count_os_wait++;
 
581
        rw_x_system_call_count++;
692
582
        rw_x_os_wait_count++;
693
583
 
694
584
        sync_array_wait_event(sync_primary_wait_array, index);
695
585
 
696
 
        i = 0;
697
586
        goto lock_loop;
698
587
}
699
588
 
700
589
#ifdef UNIV_SYNC_DEBUG
701
 
/******************************************************************//**
 
590
/**********************************************************************
702
591
Acquires the debug mutex. We cannot use the mutex defined in sync0sync,
703
592
because the debug mutex is also acquired in sync0arr while holding the OS
704
593
mutex protecting the sync array, and the ordinary mutex_enter might
727
616
        goto loop;
728
617
}
729
618
 
730
 
/******************************************************************//**
 
619
/**********************************************************************
731
620
Releases the debug mutex. */
732
621
UNIV_INTERN
733
622
void
742
631
        }
743
632
}
744
633
 
745
 
/******************************************************************//**
 
634
/**********************************************************************
746
635
Inserts the debug information for an rw-lock. */
747
636
UNIV_INTERN
748
637
void
749
638
rw_lock_add_debug_info(
750
639
/*===================*/
751
 
        rw_lock_t*      lock,           /*!< in: rw-lock */
752
 
        ulint           pass,           /*!< in: pass value */
753
 
        ulint           lock_type,      /*!< in: lock type */
754
 
        const char*     file_name,      /*!< in: file where requested */
755
 
        ulint           line)           /*!< in: line where requested */
 
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 */
756
645
{
757
646
        rw_lock_debug_t*        info;
758
647
 
778
667
        }
779
668
}
780
669
 
781
 
/******************************************************************//**
 
670
/**********************************************************************
782
671
Removes a debug information struct for an rw-lock. */
783
672
UNIV_INTERN
784
673
void
785
674
rw_lock_remove_debug_info(
786
675
/*======================*/
787
 
        rw_lock_t*      lock,           /*!< in: rw-lock */
788
 
        ulint           pass,           /*!< in: pass value */
789
 
        ulint           lock_type)      /*!< in: lock type */
 
676
        rw_lock_t*      lock,           /* in: rw-lock */
 
677
        ulint           pass,           /* in: pass value */
 
678
        ulint           lock_type)      /* in: lock type */
790
679
{
791
680
        rw_lock_debug_t*        info;
792
681
 
824
713
#endif /* UNIV_SYNC_DEBUG */
825
714
 
826
715
#ifdef UNIV_SYNC_DEBUG
827
 
/******************************************************************//**
 
716
/**********************************************************************
828
717
Checks if the thread has locked the rw-lock in the specified mode, with
829
 
the pass value == 0.
830
 
@return TRUE if locked */
 
718
the pass value == 0. */
831
719
UNIV_INTERN
832
720
ibool
833
721
rw_lock_own(
834
722
/*========*/
835
 
        rw_lock_t*      lock,           /*!< in: rw-lock */
836
 
        ulint           lock_type)      /*!< in: lock type: RW_LOCK_SHARED,
 
723
                                        /* out: TRUE if locked */
 
724
        rw_lock_t*      lock,           /* in: rw-lock */
 
725
        ulint           lock_type)      /* in: lock type: RW_LOCK_SHARED,
837
726
                                        RW_LOCK_EX */
838
727
{
839
728
        rw_lock_debug_t*        info;
841
730
        ut_ad(lock);
842
731
        ut_ad(rw_lock_validate(lock));
843
732
 
844
 
        rw_lock_debug_mutex_enter();
 
733
        mutex_enter(&(lock->mutex));
845
734
 
846
735
        info = UT_LIST_GET_FIRST(lock->debug_list);
847
736
 
851
740
                    && (info->pass == 0)
852
741
                    && (info->lock_type == lock_type)) {
853
742
 
854
 
                        rw_lock_debug_mutex_exit();
 
743
                        mutex_exit(&(lock->mutex));
855
744
                        /* Found! */
856
745
 
857
746
                        return(TRUE);
859
748
 
860
749
                info = UT_LIST_GET_NEXT(list, info);
861
750
        }
862
 
        rw_lock_debug_mutex_exit();
 
751
        mutex_exit(&(lock->mutex));
863
752
 
864
753
        return(FALSE);
865
754
}
866
755
#endif /* UNIV_SYNC_DEBUG */
867
756
 
868
 
/******************************************************************//**
869
 
Checks if somebody has locked the rw-lock in the specified mode.
870
 
@return TRUE if locked */
 
757
/**********************************************************************
 
758
Checks if somebody has locked the rw-lock in the specified mode. */
871
759
UNIV_INTERN
872
760
ibool
873
761
rw_lock_is_locked(
874
762
/*==============*/
875
 
        rw_lock_t*      lock,           /*!< in: rw-lock */
876
 
        ulint           lock_type)      /*!< in: lock type: RW_LOCK_SHARED,
 
763
                                        /* out: TRUE if locked */
 
764
        rw_lock_t*      lock,           /* in: rw-lock */
 
765
        ulint           lock_type)      /* in: lock type: RW_LOCK_SHARED,
877
766
                                        RW_LOCK_EX */
878
767
{
879
768
        ibool   ret     = FALSE;
881
770
        ut_ad(lock);
882
771
        ut_ad(rw_lock_validate(lock));
883
772
 
 
773
        mutex_enter(&(lock->mutex));
 
774
 
884
775
        if (lock_type == RW_LOCK_SHARED) {
885
 
                if (rw_lock_get_reader_count(lock) > 0) {
 
776
                if (lock->reader_count > 0) {
886
777
                        ret = TRUE;
887
778
                }
888
779
        } else if (lock_type == RW_LOCK_EX) {
889
 
                if (rw_lock_get_writer(lock) == RW_LOCK_EX) {
 
780
                if (lock->writer == RW_LOCK_EX) {
890
781
                        ret = TRUE;
891
782
                }
892
783
        } else {
893
784
                ut_error;
894
785
        }
895
786
 
 
787
        mutex_exit(&(lock->mutex));
 
788
 
896
789
        return(ret);
897
790
}
898
791
 
899
792
#ifdef UNIV_SYNC_DEBUG
900
 
/***************************************************************//**
 
793
/*******************************************************************
901
794
Prints debug info of currently locked rw-locks. */
902
795
UNIV_INTERN
903
796
void
904
797
rw_lock_list_print_info(
905
798
/*====================*/
906
 
        FILE*   file)           /*!< in: file where to print */
 
799
        FILE*   file)           /* in: file where to print */
907
800
{
908
801
        rw_lock_t*      lock;
909
802
        ulint           count           = 0;
921
814
 
922
815
                count++;
923
816
 
924
 
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
925
817
                mutex_enter(&(lock->mutex));
926
 
#endif
927
 
                if (lock->lock_word != X_LOCK_DECR) {
 
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)) {
928
822
 
929
823
                        fprintf(file, "RW-LOCK: %p ", (void*) lock);
930
824
 
940
834
                                info = UT_LIST_GET_NEXT(list, info);
941
835
                        }
942
836
                }
943
 
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
 
837
 
944
838
                mutex_exit(&(lock->mutex));
945
 
#endif
946
 
 
947
839
                lock = UT_LIST_GET_NEXT(list, lock);
948
840
        }
949
841
 
951
843
        mutex_exit(&rw_lock_list_mutex);
952
844
}
953
845
 
954
 
/***************************************************************//**
 
846
/*******************************************************************
955
847
Prints debug info of an rw-lock. */
956
848
UNIV_INTERN
957
849
void
958
850
rw_lock_print(
959
851
/*==========*/
960
 
        rw_lock_t*      lock)   /*!< in: rw-lock */
 
852
        rw_lock_t*      lock)   /* in: rw-lock */
961
853
{
962
854
        rw_lock_debug_t* info;
963
855
 
966
858
                "RW-LATCH INFO\n"
967
859
                "RW-LATCH: %p ", (void*) lock);
968
860
 
969
 
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
970
 
        /* We used to acquire lock->mutex here, but it would cause a
971
 
        recursive call to sync_thread_add_level() if UNIV_SYNC_DEBUG
972
 
        is defined.  Since this function is only invoked from
973
 
        sync_thread_levels_g(), let us choose the smaller evil:
974
 
        performing dirty reads instead of causing bogus deadlocks or
975
 
        assertion failures. */
976
 
#endif
977
 
        if (lock->lock_word != X_LOCK_DECR) {
 
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)) {
978
864
 
979
865
                if (rw_lock_get_waiters(lock)) {
980
866
                        fputs(" Waiters for the lock exist\n", stderr);
990
876
        }
991
877
}
992
878
 
993
 
/*********************************************************************//**
 
879
/*************************************************************************
994
880
Prints info of a debug struct. */
995
881
UNIV_INTERN
996
882
void
997
883
rw_lock_debug_print(
998
884
/*================*/
999
 
        rw_lock_debug_t*        info)   /*!< in: debug struct */
 
885
        rw_lock_debug_t*        info)   /* in: debug struct */
1000
886
{
1001
887
        ulint   rwt;
1002
888
 
1003
889
        rwt       = info->lock_type;
1004
890
 
1005
 
        fprintf(stderr, "Locked: thread %lu file %s line %lu  ",
 
891
        fprintf(stderr, "Locked: thread %ld file %s line %ld  ",
1006
892
                (ulong) os_thread_pf(info->thread_id), info->file_name,
1007
893
                (ulong) info->line);
1008
894
        if (rwt == RW_LOCK_SHARED) {
1020
906
        putc('\n', stderr);
1021
907
}
1022
908
 
1023
 
/***************************************************************//**
 
909
/*******************************************************************
1024
910
Returns the number of currently locked rw-locks. Works only in the debug
1025
 
version.
1026
 
@return number of locked rw-locks */
 
911
version. */
1027
912
UNIV_INTERN
1028
913
ulint
1029
914
rw_lock_n_locked(void)
1037
922
        lock = UT_LIST_GET_FIRST(rw_lock_list);
1038
923
 
1039
924
        while (lock != NULL) {
 
925
                mutex_enter(rw_lock_get_mutex(lock));
1040
926
 
1041
 
                if (lock->lock_word != X_LOCK_DECR) {
 
927
                if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
 
928
                    || (rw_lock_get_reader_count(lock) != 0)) {
1042
929
                        count++;
1043
930
                }
1044
931
 
 
932
                mutex_exit(rw_lock_get_mutex(lock));
1045
933
                lock = UT_LIST_GET_NEXT(list, lock);
1046
934
        }
1047
935