~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/innobase/include/sync0rw.ic

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

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., 59 Temple
 
22
Place, Suite 330, Boston, MA 02111-1307 USA
 
23
 
 
24
*****************************************************************************/
 
25
 
 
26
/**************************************************//**
 
27
@file include/sync0rw.ic
 
28
The read-write lock (for threads)
 
29
 
 
30
Created 9/11/1995 Heikki Tuuri
 
31
*******************************************************/
 
32
 
 
33
/******************************************************************//**
 
34
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
 
35
locked in exclusive mode, or there is an exclusive lock request waiting,
 
36
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
 
37
waiting for the lock before suspending the thread. */
 
38
UNIV_INTERN
 
39
void
 
40
rw_lock_s_lock_spin(
 
41
/*================*/
 
42
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
 
43
        ulint           pass,   /*!< in: pass value; != 0, if the lock will
 
44
                                be passed to another thread to unlock */
 
45
        const char*     file_name,/*!< in: file name where lock requested */
 
46
        ulint           line);  /*!< in: line where requested */
 
47
#ifdef UNIV_SYNC_DEBUG
 
48
/******************************************************************//**
 
49
Inserts the debug information for an rw-lock. */
 
50
UNIV_INTERN
 
51
void
 
52
rw_lock_add_debug_info(
 
53
/*===================*/
 
54
        rw_lock_t*      lock,           /*!< in: rw-lock */
 
55
        ulint           pass,           /*!< in: pass value */
 
56
        ulint           lock_type,      /*!< in: lock type */
 
57
        const char*     file_name,      /*!< in: file where requested */
 
58
        ulint           line);          /*!< in: line where requested */
 
59
/******************************************************************//**
 
60
Removes a debug information struct for an rw-lock. */
 
61
UNIV_INTERN
 
62
void
 
63
rw_lock_remove_debug_info(
 
64
/*======================*/
 
65
        rw_lock_t*      lock,           /*!< in: rw-lock */
 
66
        ulint           pass,           /*!< in: pass value */
 
67
        ulint           lock_type);     /*!< in: lock type */
 
68
#endif /* UNIV_SYNC_DEBUG */
 
69
 
 
70
/********************************************************************//**
 
71
Check if there are threads waiting for the rw-lock.
 
72
@return 1 if waiters, 0 otherwise */
 
73
UNIV_INLINE
 
74
ulint
 
75
rw_lock_get_waiters(
 
76
/*================*/
 
77
        const rw_lock_t*        lock)   /*!< in: rw-lock */
 
78
{
 
79
        return(lock->waiters);
 
80
}
 
81
 
 
82
/********************************************************************//**
 
83
Sets lock->waiters to 1. It is not an error if lock->waiters is already
 
84
1. On platforms where ATOMIC builtins are used this function enforces a
 
85
memory barrier. */
 
86
UNIV_INLINE
 
87
void
 
88
rw_lock_set_waiter_flag(
 
89
/*====================*/
 
90
        rw_lock_t*      lock)   /*!< in/out: rw-lock */
 
91
{
 
92
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
 
93
        if (! os_compare_and_swap_ulint(&lock->waiters, 0, 1))
 
94
          return; 
 
95
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
 
96
        lock->waiters = 1;
 
97
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
 
98
}
 
99
 
 
100
/********************************************************************//**
 
101
Resets lock->waiters to 0. It is not an error if lock->waiters is already
 
102
0. On platforms where ATOMIC builtins are used this function enforces a
 
103
memory barrier. */
 
104
UNIV_INLINE
 
105
void
 
106
rw_lock_reset_waiter_flag(
 
107
/*======================*/
 
108
        rw_lock_t*      lock)   /*!< in/out: rw-lock */
 
109
{
 
110
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
 
111
        if (! os_compare_and_swap_ulint(&lock->waiters, 1, 0))
 
112
          return;
 
113
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
 
114
        lock->waiters = 0;
 
115
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
 
116
}
 
117
 
 
118
/******************************************************************//**
 
119
Returns the write-status of the lock - this function made more sense
 
120
with the old rw_lock implementation.
 
121
@return RW_LOCK_NOT_LOCKED, RW_LOCK_EX, RW_LOCK_WAIT_EX */
 
122
UNIV_INLINE
 
123
ulint
 
124
rw_lock_get_writer(
 
125
/*===============*/
 
126
        const rw_lock_t*        lock)   /*!< in: rw-lock */
 
127
{
 
128
        lint lock_word = lock->lock_word;
 
129
        if (lock_word > 0) {
 
130
                /* return NOT_LOCKED in s-lock state, like the writer
 
131
                member of the old lock implementation. */
 
132
                return(RW_LOCK_NOT_LOCKED);
 
133
        } else if (((-lock_word) % X_LOCK_DECR) == 0) {
 
134
                return(RW_LOCK_EX);
 
135
        } else {
 
136
                ut_ad(lock_word > -X_LOCK_DECR);
 
137
                return(RW_LOCK_WAIT_EX);
 
138
        }
 
139
}
 
140
 
 
141
/******************************************************************//**
 
142
Returns the number of readers.
 
143
@return number of readers */
 
144
UNIV_INLINE
 
145
ulint
 
146
rw_lock_get_reader_count(
 
147
/*=====================*/
 
148
        const rw_lock_t*        lock)   /*!< in: rw-lock */
 
149
{
 
150
        lint lock_word = lock->lock_word;
 
151
        if (lock_word > 0) {
 
152
                /* s-locked, no x-waiters */
 
153
                return(X_LOCK_DECR - lock_word);
 
154
        } else if (lock_word < 0 && lock_word > -X_LOCK_DECR) {
 
155
                /* s-locked, with x-waiters */
 
156
                return((ulint)(-lock_word));
 
157
        }
 
158
        return(0);
 
159
}
 
160
 
 
161
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
 
162
UNIV_INLINE
 
163
mutex_t*
 
164
rw_lock_get_mutex(
 
165
/*==============*/
 
166
        rw_lock_t*      lock)
 
167
{
 
168
        return(&(lock->mutex));
 
169
}
 
170
#endif
 
171
 
 
172
/******************************************************************//**
 
173
Returns the value of writer_count for the lock. Does not reserve the lock
 
174
mutex, so the caller must be sure it is not changed during the call.
 
175
@return value of writer_count */
 
176
UNIV_INLINE
 
177
ulint
 
178
rw_lock_get_x_lock_count(
 
179
/*=====================*/
 
180
        const rw_lock_t*        lock)   /*!< in: rw-lock */
 
181
{
 
182
        lint lock_copy = lock->lock_word;
 
183
        /* If there is a reader, lock_word is not divisible by X_LOCK_DECR */
 
184
        if (lock_copy > 0 || (-lock_copy) % X_LOCK_DECR != 0) {
 
185
                return(0);
 
186
        }
 
187
        return(((-lock_copy) / X_LOCK_DECR) + 1);
 
188
}
 
189
 
 
190
/******************************************************************//**
 
191
Two different implementations for decrementing the lock_word of a rw_lock:
 
192
one for systems supporting atomic operations, one for others. This does
 
193
does not support recusive x-locks: they should be handled by the caller and
 
194
need not be atomic since they are performed by the current lock holder.
 
195
Returns true if the decrement was made, false if not.
 
196
@return TRUE if decr occurs */
 
197
UNIV_INLINE
 
198
ibool
 
199
rw_lock_lock_word_decr(
 
200
/*===================*/
 
201
        rw_lock_t*      lock,           /*!< in/out: rw-lock */
 
202
        ulint           amount)         /*!< in: amount to decrement */
 
203
{
 
204
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
 
205
        lint local_lock_word = lock->lock_word;
 
206
        while (local_lock_word > 0) {
 
207
                if (os_compare_and_swap_lint(&lock->lock_word,
 
208
                                             local_lock_word,
 
209
                                             local_lock_word - amount)) {
 
210
                        return(TRUE);
 
211
                }
 
212
                local_lock_word = lock->lock_word;
 
213
        }
 
214
        return(FALSE);
 
215
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
 
216
        ibool success = FALSE;
 
217
        mutex_enter(&(lock->mutex));
 
218
        if (lock->lock_word > 0) {
 
219
                lock->lock_word -= amount;
 
220
                success = TRUE;
 
221
        }
 
222
        mutex_exit(&(lock->mutex));
 
223
        return(success);
 
224
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
 
225
}
 
226
 
 
227
/******************************************************************//**
 
228
Increments lock_word the specified amount and returns new value.
 
229
@return lock->lock_word after increment */
 
230
UNIV_INLINE
 
231
lint
 
232
rw_lock_lock_word_incr(
 
233
/*===================*/
 
234
        rw_lock_t*      lock,           /*!< in/out: rw-lock */
 
235
        ulint           amount)         /*!< in: amount of increment */
 
236
{
 
237
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
 
238
        return(os_atomic_increment_lint(&lock->lock_word, amount));
 
239
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
 
240
        lint local_lock_word;
 
241
 
 
242
        mutex_enter(&(lock->mutex));
 
243
 
 
244
        lock->lock_word += amount;
 
245
        local_lock_word = lock->lock_word;
 
246
 
 
247
        mutex_exit(&(lock->mutex));
 
248
 
 
249
        return(local_lock_word);
 
250
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
 
251
}
 
252
 
 
253
/******************************************************************//**
 
254
This function sets the lock->writer_thread and lock->recursive fields.
 
255
For platforms where we are using atomic builtins instead of lock->mutex
 
256
it sets the lock->writer_thread field using atomics to ensure memory
 
257
ordering. Note that it is assumed that the caller of this function
 
258
effectively owns the lock i.e.: nobody else is allowed to modify
 
259
lock->writer_thread at this point in time.
 
260
The protocol is that lock->writer_thread MUST be updated BEFORE the
 
261
lock->recursive flag is set. */
 
262
UNIV_INLINE
 
263
void
 
264
rw_lock_set_writer_id_and_recursion_flag(
 
265
/*=====================================*/
 
266
        rw_lock_t*      lock,           /*!< in/out: lock to work on */
 
267
        ibool           recursive)      /*!< in: TRUE if recursion
 
268
                                        allowed */
 
269
{
 
270
        os_thread_id_t  curr_thread     = os_thread_get_curr_id();
 
271
 
 
272
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
 
273
        os_thread_id_t  local_thread;
 
274
        ibool           success;
 
275
 
 
276
        /* Prevent Valgrind warnings about writer_thread being
 
277
        uninitialized.  It does not matter if writer_thread is
 
278
        uninitialized, because we are comparing writer_thread against
 
279
        itself, and the operation should always succeed. */
 
280
        UNIV_MEM_VALID(&lock->writer_thread, sizeof lock->writer_thread);
 
281
 
 
282
        local_thread = lock->writer_thread;
 
283
        success = os_compare_and_swap_thread_id(
 
284
                &lock->writer_thread, local_thread, curr_thread);
 
285
        ut_a(success);
 
286
        lock->recursive = recursive;
 
287
 
 
288
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
 
289
 
 
290
        mutex_enter(&lock->mutex);
 
291
        lock->writer_thread = curr_thread;
 
292
        lock->recursive = recursive;
 
293
        mutex_exit(&lock->mutex);
 
294
 
 
295
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
 
296
}
 
297
 
 
298
/******************************************************************//**
 
299
Low-level function which tries to lock an rw-lock in s-mode. Performs no
 
300
spinning.
 
301
@return TRUE if success */
 
302
UNIV_INLINE
 
303
ibool
 
304
rw_lock_s_lock_low(
 
305
/*===============*/
 
306
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
 
307
        ulint           pass __attribute__((unused)),
 
308
                                /*!< in: pass value; != 0, if the lock will be
 
309
                                passed to another thread to unlock */
 
310
        const char*     file_name, /*!< in: file name where lock requested */
 
311
        ulint           line)   /*!< in: line where requested */
 
312
{
 
313
        (void)pass;
 
314
        /* TODO: study performance of UNIV_LIKELY branch prediction hints. */
 
315
        if (!rw_lock_lock_word_decr(lock, 1)) {
 
316
                /* Locking did not succeed */
 
317
                return(FALSE);
 
318
        }
 
319
 
 
320
#ifdef UNIV_SYNC_DEBUG
 
321
        rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name, line);
 
322
#endif
 
323
        /* These debugging values are not set safely: they may be incorrect
 
324
        or even refer to a line that is invalid for the file name. */
 
325
        lock->last_s_file_name = file_name;
 
326
        lock->last_s_line = line;
 
327
 
 
328
        return(TRUE);   /* locking succeeded */
 
329
}
 
330
 
 
331
/******************************************************************//**
 
332
Low-level function which locks an rw-lock in s-mode when we know that it
 
333
is possible and none else is currently accessing the rw-lock structure.
 
334
Then we can do the locking without reserving the mutex. */
 
335
UNIV_INLINE
 
336
void
 
337
rw_lock_s_lock_direct(
 
338
/*==================*/
 
339
        rw_lock_t*      lock,           /*!< in/out: rw-lock */
 
340
        const char*     file_name,      /*!< in: file name where requested */
 
341
        ulint           line)           /*!< in: line where lock requested */
 
342
{
 
343
        ut_ad(lock->lock_word == X_LOCK_DECR);
 
344
 
 
345
        /* Indicate there is a new reader by decrementing lock_word */
 
346
        lock->lock_word--;
 
347
 
 
348
        lock->last_s_file_name = file_name;
 
349
        lock->last_s_line = line;
 
350
 
 
351
#ifdef UNIV_SYNC_DEBUG
 
352
        rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);
 
353
#endif
 
354
}
 
355
 
 
356
/******************************************************************//**
 
357
Low-level function which locks an rw-lock in x-mode when we know that it
 
358
is not locked and none else is currently accessing the rw-lock structure.
 
359
Then we can do the locking without reserving the mutex. */
 
360
UNIV_INLINE
 
361
void
 
362
rw_lock_x_lock_direct(
 
363
/*==================*/
 
364
        rw_lock_t*      lock,           /*!< in/out: rw-lock */
 
365
        const char*     file_name,      /*!< in: file name where requested */
 
366
        ulint           line)           /*!< in: line where lock requested */
 
367
{
 
368
        ut_ad(rw_lock_validate(lock));
 
369
        ut_ad(lock->lock_word == X_LOCK_DECR);
 
370
 
 
371
        lock->lock_word -= X_LOCK_DECR;
 
372
        lock->writer_thread = os_thread_get_curr_id();
 
373
        lock->recursive = TRUE;
 
374
 
 
375
        lock->last_x_file_name = file_name;
 
376
        lock->last_x_line = line;
 
377
 
 
378
#ifdef UNIV_SYNC_DEBUG
 
379
        rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
 
380
#endif
 
381
}
 
382
 
 
383
/******************************************************************//**
 
384
NOTE! Use the corresponding macro, not directly this function! Lock an
 
385
rw-lock in shared mode for the current thread. If the rw-lock is locked
 
386
in exclusive mode, or there is an exclusive lock request waiting, the
 
387
function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for
 
388
the lock, before suspending the thread. */
 
389
UNIV_INLINE
 
390
void
 
391
rw_lock_s_lock_func(
 
392
/*================*/
 
393
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
 
394
        ulint           pass,   /*!< in: pass value; != 0, if the lock will
 
395
                                be passed to another thread to unlock */
 
396
        const char*     file_name,/*!< in: file name where lock requested */
 
397
        ulint           line)   /*!< in: line where requested */
 
398
{
 
399
        /* NOTE: As we do not know the thread ids for threads which have
 
400
        s-locked a latch, and s-lockers will be served only after waiting
 
401
        x-lock requests have been fulfilled, then if this thread already
 
402
        owns an s-lock here, it may end up in a deadlock with another thread
 
403
        which requests an x-lock here. Therefore, we will forbid recursive
 
404
        s-locking of a latch: the following assert will warn the programmer
 
405
        of the possibility of this kind of a deadlock. If we want to implement
 
406
        safe recursive s-locking, we should keep in a list the thread ids of
 
407
        the threads which have s-locked a latch. This would use some CPU
 
408
        time. */
 
409
 
 
410
#ifdef UNIV_SYNC_DEBUG
 
411
        ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
 
412
#endif /* UNIV_SYNC_DEBUG */
 
413
 
 
414
        /* TODO: study performance of UNIV_LIKELY branch prediction hints. */
 
415
        if (rw_lock_s_lock_low(lock, pass, file_name, line)) {
 
416
 
 
417
                return; /* Success */
 
418
        } else {
 
419
                /* Did not succeed, try spin wait */
 
420
 
 
421
                rw_lock_s_lock_spin(lock, pass, file_name, line);
 
422
 
 
423
                return;
 
424
        }
 
425
}
 
426
 
 
427
/******************************************************************//**
 
428
NOTE! Use the corresponding macro, not directly this function! Lock an
 
429
rw-lock in exclusive mode for the current thread if the lock can be
 
430
obtained immediately.
 
431
@return TRUE if success */
 
432
UNIV_INLINE
 
433
ibool
 
434
rw_lock_x_lock_func_nowait(
 
435
/*=======================*/
 
436
        rw_lock_t*      lock,   /*!< in: pointer to rw-lock */
 
437
        const char*     file_name,/*!< in: file name where lock requested */
 
438
        ulint           line)   /*!< in: line where requested */
 
439
{
 
440
        os_thread_id_t  curr_thread     = os_thread_get_curr_id();
 
441
 
 
442
        ibool success;
 
443
 
 
444
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
 
445
        success = os_compare_and_swap_lint(&lock->lock_word, X_LOCK_DECR, 0);
 
446
#else
 
447
 
 
448
        success = FALSE;
 
449
        mutex_enter(&(lock->mutex));
 
450
        if (lock->lock_word == X_LOCK_DECR) {
 
451
                lock->lock_word = 0;
 
452
                success = TRUE;
 
453
        }
 
454
        mutex_exit(&(lock->mutex));
 
455
 
 
456
#endif
 
457
        if (success) {
 
458
                rw_lock_set_writer_id_and_recursion_flag(lock, TRUE);
 
459
 
 
460
        } else if (lock->recursive
 
461
                   && os_thread_eq(lock->writer_thread, curr_thread)) {
 
462
                /* Relock: this lock_word modification is safe since no other
 
463
                threads can modify (lock, unlock, or reserve) lock_word while
 
464
                there is an exclusive writer and this is the writer thread. */
 
465
                lock->lock_word -= X_LOCK_DECR;
 
466
 
 
467
                ut_ad(((-lock->lock_word) % X_LOCK_DECR) == 0);
 
468
 
 
469
        } else {
 
470
                /* Failure */
 
471
                return(FALSE);
 
472
        }
 
473
#ifdef UNIV_SYNC_DEBUG
 
474
        rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
 
475
#endif
 
476
 
 
477
        lock->last_x_file_name = file_name;
 
478
        lock->last_x_line = line;
 
479
 
 
480
        ut_ad(rw_lock_validate(lock));
 
481
 
 
482
        return(TRUE);
 
483
}
 
484
 
 
485
/******************************************************************//**
 
486
Releases a shared mode lock. */
 
487
UNIV_INLINE
 
488
void
 
489
rw_lock_s_unlock_func(
 
490
/*==================*/
 
491
#ifdef UNIV_SYNC_DEBUG
 
492
        ulint           pass,   /*!< in: pass value; != 0, if the lock may have
 
493
                                been passed to another thread to unlock */
 
494
#endif
 
495
        rw_lock_t*      lock)   /*!< in/out: rw-lock */
 
496
{
 
497
        ut_ad((lock->lock_word % X_LOCK_DECR) != 0);
 
498
 
 
499
#ifdef UNIV_SYNC_DEBUG
 
500
        rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
 
501
#endif
 
502
 
 
503
        /* Increment lock_word to indicate 1 less reader */
 
504
        if (rw_lock_lock_word_incr(lock, 1) == 0) {
 
505
 
 
506
                /* wait_ex waiter exists. It may not be asleep, but we signal
 
507
                anyway. We do not wake other waiters, because they can't
 
508
                exist without wait_ex waiter and wait_ex waiter goes first.*/
 
509
                os_event_set(lock->wait_ex_event);
 
510
                sync_array_object_signalled(sync_primary_wait_array);
 
511
 
 
512
        }
 
513
 
 
514
        ut_ad(rw_lock_validate(lock));
 
515
 
 
516
#ifdef UNIV_SYNC_PERF_STAT
 
517
        rw_s_exit_count++;
 
518
#endif
 
519
}
 
520
 
 
521
/******************************************************************//**
 
522
Releases a shared mode lock when we know there are no waiters and none
 
523
else will access the lock during the time this function is executed. */
 
524
UNIV_INLINE
 
525
void
 
526
rw_lock_s_unlock_direct(
 
527
/*====================*/
 
528
        rw_lock_t*      lock)   /*!< in/out: rw-lock */
 
529
{
 
530
        ut_ad(lock->lock_word < X_LOCK_DECR);
 
531
 
 
532
#ifdef UNIV_SYNC_DEBUG
 
533
        rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
 
534
#endif
 
535
 
 
536
        /* Decrease reader count by incrementing lock_word */
 
537
        lock->lock_word++;
 
538
 
 
539
        ut_ad(!lock->waiters);
 
540
        ut_ad(rw_lock_validate(lock));
 
541
#ifdef UNIV_SYNC_PERF_STAT
 
542
        rw_s_exit_count++;
 
543
#endif
 
544
}
 
545
 
 
546
/******************************************************************//**
 
547
Releases an exclusive mode lock. */
 
548
UNIV_INLINE
 
549
void
 
550
rw_lock_x_unlock_func(
 
551
/*==================*/
 
552
#ifdef UNIV_SYNC_DEBUG
 
553
        ulint           pass,   /*!< in: pass value; != 0, if the lock may have
 
554
                                been passed to another thread to unlock */
 
555
#endif
 
556
        rw_lock_t*      lock)   /*!< in/out: rw-lock */
 
557
{
 
558
        ut_ad((lock->lock_word % X_LOCK_DECR) == 0);
 
559
 
 
560
        /* lock->recursive flag also indicates if lock->writer_thread is
 
561
        valid or stale. If we are the last of the recursive callers
 
562
        then we must unset lock->recursive flag to indicate that the
 
563
        lock->writer_thread is now stale.
 
564
        Note that since we still hold the x-lock we can safely read the
 
565
        lock_word. */
 
566
        if (lock->lock_word == 0) {
 
567
                /* Last caller in a possible recursive chain. */
 
568
                lock->recursive = FALSE;
 
569
                UNIV_MEM_INVALID(&lock->writer_thread,
 
570
                                 sizeof lock->writer_thread);
 
571
        }
 
572
 
 
573
#ifdef UNIV_SYNC_DEBUG
 
574
        rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
 
575
#endif
 
576
 
 
577
        if (rw_lock_lock_word_incr(lock, X_LOCK_DECR) == X_LOCK_DECR) {
 
578
                /* Lock is now free. May have to signal read/write waiters.
 
579
                We do not need to signal wait_ex waiters, since they cannot
 
580
                exist when there is a writer. */
 
581
                if (lock->waiters) {
 
582
                        rw_lock_reset_waiter_flag(lock);
 
583
                        os_event_set(lock->event);
 
584
                        sync_array_object_signalled(sync_primary_wait_array);
 
585
                }
 
586
        }
 
587
 
 
588
        ut_ad(rw_lock_validate(lock));
 
589
 
 
590
#ifdef UNIV_SYNC_PERF_STAT
 
591
        rw_x_exit_count++;
 
592
#endif
 
593
}
 
594
 
 
595
/******************************************************************//**
 
596
Releases an exclusive mode lock when we know there are no waiters, and
 
597
none else will access the lock during the time this function is executed. */
 
598
UNIV_INLINE
 
599
void
 
600
rw_lock_x_unlock_direct(
 
601
/*====================*/
 
602
        rw_lock_t*      lock)   /*!< in/out: rw-lock */
 
603
{
 
604
        /* Reset the exclusive lock if this thread no longer has an x-mode
 
605
        lock */
 
606
 
 
607
        ut_ad((lock->lock_word % X_LOCK_DECR) == 0);
 
608
 
 
609
#ifdef UNIV_SYNC_DEBUG
 
610
        rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
 
611
#endif
 
612
 
 
613
        if (lock->lock_word == 0) {
 
614
                lock->recursive = FALSE;
 
615
                UNIV_MEM_INVALID(&lock->writer_thread,
 
616
                                 sizeof lock->writer_thread);
 
617
        }
 
618
 
 
619
        lock->lock_word += X_LOCK_DECR;
 
620
 
 
621
        ut_ad(!lock->waiters);
 
622
        ut_ad(rw_lock_validate(lock));
 
623
 
 
624
#ifdef UNIV_SYNC_PERF_STAT
 
625
        rw_x_exit_count++;
 
626
#endif
 
627
}