18
18
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
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
21
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22
Place, Suite 330, Boston, MA 02111-1307 USA
24
24
*****************************************************************************/
26
/**************************************************//**
26
/******************************************************
28
27
The read-write lock (for thread synchronization)
30
29
Created 9/11/1995 Heikki Tuuri
137
/** number of spin waits on rw-latches,
135
/* number of spin waits on rw-latches,
138
136
resulted during shared (read) locks */
139
137
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
138
UNIV_INTERN ib_int64_t rw_s_spin_round_count = 0;
144
/** number of OS waits on rw-latches,
140
/* number of OS waits on rw-latches,
145
141
resulted during shared (read) locks */
146
142
UNIV_INTERN ib_int64_t rw_s_os_wait_count = 0;
148
/** number of unlocks (that unlock shared locks),
144
/* number of unlocks (that unlock shared locks),
149
145
set only when UNIV_SYNC_PERF_STAT is defined */
150
146
UNIV_INTERN ib_int64_t rw_s_exit_count = 0;
152
/** number of spin waits on rw-latches,
148
/* number of spin waits on rw-latches,
153
149
resulted during exclusive (write) locks */
154
150
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
151
UNIV_INTERN ib_int64_t rw_x_spin_round_count = 0;
159
/** number of OS waits on rw-latches,
153
/* number of OS waits on rw-latches,
160
154
resulted during exclusive (write) locks */
161
155
UNIV_INTERN ib_int64_t rw_x_os_wait_count = 0;
163
/** number of unlocks (that unlock exclusive locks),
157
/* number of unlocks (that unlock exclusive locks),
164
158
set only when UNIV_SYNC_PERF_STAT is defined */
165
159
UNIV_INTERN ib_int64_t rw_x_exit_count = 0;
168
162
UNIV_INTERN rw_lock_list_t rw_lock_list;
169
163
UNIV_INTERN mutex_t rw_lock_list_mutex;
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 */
176
165
#ifdef UNIV_SYNC_DEBUG
177
166
/* The global mutex which protects debug info lists of all rw-locks.
178
167
To modify the debug info list of an rw-lock, this mutex has to be
179
168
acquired in addition to the mutex protecting the lock. */
181
170
UNIV_INTERN mutex_t rw_lock_debug_mutex;
183
# ifdef UNIV_PFS_MUTEX
184
UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key;
187
171
/* If deadlock detection does not get immediately the mutex,
188
172
it may wait for this event */
189
173
UNIV_INTERN os_event_t rw_lock_debug_event;
190
174
/* This is set to TRUE, if there may be waiters for the event */
191
175
UNIV_INTERN ibool rw_lock_debug_waiters;
193
/******************************************************************//**
177
/**********************************************************************
194
178
Creates a debug info struct. */
197
181
rw_lock_debug_create(void);
198
182
/*======================*/
199
/******************************************************************//**
183
/**********************************************************************
200
184
Frees a debug info struct. */
204
188
/*===============*/
205
189
rw_lock_debug_t* info);
207
/******************************************************************//**
208
Creates a debug info struct.
209
@return own: debug info struct */
191
/**********************************************************************
192
Creates a debug info struct. */
212
195
rw_lock_debug_create(void)
215
198
return((rw_lock_debug_t*) mem_alloc(sizeof(rw_lock_debug_t)));
218
/******************************************************************//**
201
/**********************************************************************
219
202
Frees a debug info struct. */
228
211
#endif /* UNIV_SYNC_DEBUG */
230
/******************************************************************//**
213
/**********************************************************************
231
214
Creates, or rather, initializes an rw-lock object in a specified memory
232
215
location (which must be appropriately aligned). The rw-lock is initialized
233
216
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
237
220
rw_lock_create_func(
238
221
/*================*/
239
rw_lock_t* lock, /*!< in: pointer to memory */
222
rw_lock_t* lock, /* in: pointer to memory */
240
223
#ifdef UNIV_DEBUG
241
224
# ifdef UNIV_SYNC_DEBUG
242
ulint level, /*!< in: level */
225
ulint level, /* in: level */
243
226
# endif /* UNIV_SYNC_DEBUG */
244
const char* cmutex_name, /*!< in: mutex name */
227
const char* cmutex_name, /* in: mutex name */
245
228
#endif /* UNIV_DEBUG */
246
const char* cfile_name, /*!< in: file name where created */
247
ulint cline) /*!< in: file line where created */
229
const char* cfile_name, /* in: file name where created */
230
ulint cline) /* in: file line where created */
249
232
/* If this is the very first time a synchronization object is
250
233
created, then the following call initializes the sync system. */
252
235
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
253
mutex_create(rw_lock_mutex_key, rw_lock_get_mutex(lock),
254
SYNC_NO_ORDER_CHECK);
236
mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
256
238
lock->mutex.cfile_name = cfile_name;
257
239
lock->mutex.cline = cline;
259
ut_d(lock->mutex.cmutex_name = cmutex_name);
260
ut_d(lock->mutex.mutex_type = 1);
241
# if defined UNIV_DEBUG && !defined UNIV_HOTBACKUP
242
lock->mutex.cmutex_name = cmutex_name;
243
lock->mutex.mutex_type = 1;
244
# endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
261
246
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
262
247
# ifdef UNIV_DEBUG
263
248
UT_NOT_USED(cmutex_name);
278
263
lock->level = level;
279
264
#endif /* UNIV_SYNC_DEBUG */
281
ut_d(lock->magic_n = RW_LOCK_MAGIC_N);
266
lock->magic_n = RW_LOCK_MAGIC_N;
283
268
lock->cfile_name = cfile_name;
284
269
lock->cline = (unsigned int) cline;
294
279
mutex_enter(&rw_lock_list_mutex);
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);
281
if (UT_LIST_GET_LEN(rw_lock_list) > 0) {
282
ut_a(UT_LIST_GET_FIRST(rw_lock_list)->magic_n
299
286
UT_LIST_ADD_FIRST(list, rw_lock_list, lock);
301
288
mutex_exit(&rw_lock_list_mutex);
304
/******************************************************************//**
291
/**********************************************************************
305
292
Calling this function is obligatory only if the memory buffer containing
306
293
the rw-lock is freed. Removes an rw-lock object from the global list. The
307
294
rw-lock is checked to be in the non-locked state. */
312
rw_lock_t* lock) /*!< in: rw-lock */
299
rw_lock_t* lock) /* in: rw-lock */
314
301
ut_ad(rw_lock_validate(lock));
315
302
ut_a(lock->lock_word == X_LOCK_DECR);
317
306
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
318
307
mutex_free(rw_lock_get_mutex(lock));
319
308
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
324
313
os_event_free(lock->wait_ex_event);
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);
315
if (UT_LIST_GET_PREV(list, lock)) {
316
ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
318
if (UT_LIST_GET_NEXT(list, lock)) {
319
ut_a(UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N);
331
322
UT_LIST_REMOVE(list, rw_lock_list, lock);
333
324
mutex_exit(&rw_lock_list_mutex);
335
ut_d(lock->magic_n = 0);
338
327
#ifdef UNIV_DEBUG
339
/******************************************************************//**
328
/**********************************************************************
340
329
Checks that the rw-lock has been initialized and that there are no
341
simultaneous shared and exclusive locks.
330
simultaneous shared and exclusive locks. */
345
333
rw_lock_validate(
346
334
/*=============*/
347
rw_lock_t* lock) /*!< in: rw-lock */
354
waiters = rw_lock_get_waiters(lock);
355
lock_word = lock->lock_word;
339
ulint waiters = rw_lock_get_waiters(lock);
340
lint lock_word = lock->lock_word;
357
ut_ad(lock->magic_n == RW_LOCK_MAGIC_N);
342
ut_a(lock->magic_n == RW_LOCK_MAGIC_N);
358
343
ut_a(waiters == 0 || waiters == 1);
359
344
ut_a(lock_word > -X_LOCK_DECR ||(-lock_word) % X_LOCK_DECR == 0);
363
348
#endif /* UNIV_DEBUG */
365
/******************************************************************//**
350
/**********************************************************************
366
351
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
367
352
locked in exclusive mode, or there is an exclusive lock request waiting,
368
353
the function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting
372
357
rw_lock_s_lock_spin(
373
358
/*================*/
374
rw_lock_t* lock, /*!< in: pointer to rw-lock */
375
ulint pass, /*!< in: pass value; != 0, if the lock
359
rw_lock_t* lock, /* in: pointer to rw-lock */
360
ulint pass, /* in: pass value; != 0, if the lock
376
361
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 */
362
const char* file_name, /* in: file name where lock requested */
363
ulint line) /* in: line where requested */
380
365
ulint index; /* index of the reserved wait cell */
381
366
ulint i = 0; /* spin round count */
383
368
ut_ad(rw_lock_validate(lock));
385
rw_s_spin_wait_count++; /*!< Count calls to this function */
370
rw_s_spin_wait_count++; /* Count calls to this function */
388
373
/* Spin waiting for the writer field to become free */
457
/******************************************************************//**
442
/**********************************************************************
458
443
This function is used in the insert buffer to move the ownership of an
459
444
x-latch on a buffer frame to the current thread. The x-latch was set by
460
445
the buffer read operation and it protected the buffer frame while the
467
452
rw_lock_x_lock_move_ownership(
468
453
/*==========================*/
469
rw_lock_t* lock) /*!< in: lock which was x-locked in the
454
rw_lock_t* lock) /* in: lock which was x-locked in the
472
457
ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
474
459
rw_lock_set_writer_id_and_recursion_flag(lock, TRUE);
477
/******************************************************************//**
462
/**********************************************************************
478
463
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. */
464
The caller must have already decremented lock_word by X_LOCK_DECR.*/
482
467
rw_lock_x_lock_wait(
483
468
/*================*/
484
rw_lock_t* lock, /*!< in: pointer to rw-lock */
469
rw_lock_t* lock, /* in: pointer to rw-lock */
485
470
#ifdef UNIV_SYNC_DEBUG
486
ulint pass, /*!< in: pass value; != 0, if the lock will
471
ulint pass, /* in: pass value; != 0, if the lock will
487
472
be passed to another thread to unlock */
489
const char* file_name,/*!< in: file name where lock requested */
490
ulint line) /*!< in: line where requested */
474
const char* file_name,/* in: file name where lock requested */
475
ulint line) /* in: line where requested */
542
527
rw_x_spin_round_count += i;
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. */
530
/**********************************************************************
531
Low-level function for acquiring an exclusive lock. */
550
534
rw_lock_x_lock_low(
551
535
/*===============*/
552
rw_lock_t* lock, /*!< in: pointer to rw-lock */
553
ulint pass, /*!< in: pass value; != 0, if the lock will
536
/* out: RW_LOCK_NOT_LOCKED if did
537
not succeed, RW_LOCK_EX if success. */
538
rw_lock_t* lock, /* in: pointer to rw-lock */
539
ulint pass, /* in: pass value; != 0, if the lock will
554
540
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 */
541
const char* file_name,/* in: file name where lock requested */
542
ulint line) /* in: line where requested */
558
544
os_thread_id_t curr_thread = os_thread_get_curr_id();
599
/******************************************************************//**
585
/**********************************************************************
600
586
NOTE! Use the corresponding macro, not directly this function! Lock an
601
587
rw-lock in exclusive mode for the current thread. If the rw-lock is locked
602
588
in shared or exclusive mode, or there is an exclusive lock request waiting,
610
596
rw_lock_x_lock_func(
611
597
/*================*/
612
rw_lock_t* lock, /*!< in: pointer to rw-lock */
613
ulint pass, /*!< in: pass value; != 0, if the lock will
598
rw_lock_t* lock, /* in: pointer to rw-lock */
599
ulint pass, /* in: pass value; != 0, if the lock will
614
600
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 */
601
const char* file_name,/* in: file name where lock requested */
602
ulint line) /* in: line where requested */
618
ulint index; /*!< index of the reserved wait cell */
619
ulint i; /*!< spin round count */
620
ibool spinning = FALSE;
604
ulint index; /* index of the reserved wait cell */
605
ulint i; /* spin round count */
606
ibool spinning = FALSE;
622
608
ut_ad(rw_lock_validate(lock));
700
686
#ifdef UNIV_SYNC_DEBUG
701
/******************************************************************//**
687
/**********************************************************************
702
688
Acquires the debug mutex. We cannot use the mutex defined in sync0sync,
703
689
because the debug mutex is also acquired in sync0arr while holding the OS
704
690
mutex protecting the sync array, and the ordinary mutex_enter might
745
/******************************************************************//**
731
/**********************************************************************
746
732
Inserts the debug information for an rw-lock. */
749
735
rw_lock_add_debug_info(
750
736
/*===================*/
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 */
737
rw_lock_t* lock, /* in: rw-lock */
738
ulint pass, /* in: pass value */
739
ulint lock_type, /* in: lock type */
740
const char* file_name, /* in: file where requested */
741
ulint line) /* in: line where requested */
757
743
rw_lock_debug_t* info;
781
/******************************************************************//**
767
/**********************************************************************
782
768
Removes a debug information struct for an rw-lock. */
785
771
rw_lock_remove_debug_info(
786
772
/*======================*/
787
rw_lock_t* lock, /*!< in: rw-lock */
788
ulint pass, /*!< in: pass value */
789
ulint lock_type) /*!< in: lock type */
773
rw_lock_t* lock, /* in: rw-lock */
774
ulint pass, /* in: pass value */
775
ulint lock_type) /* in: lock type */
791
777
rw_lock_debug_t* info;
824
810
#endif /* UNIV_SYNC_DEBUG */
826
812
#ifdef UNIV_SYNC_DEBUG
827
/******************************************************************//**
813
/**********************************************************************
828
814
Checks if the thread has locked the rw-lock in the specified mode, with
830
@return TRUE if locked */
815
the pass value == 0. */
835
rw_lock_t* lock, /*!< in: rw-lock */
836
ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED,
820
/* out: TRUE if locked */
821
rw_lock_t* lock, /* in: rw-lock */
822
ulint lock_type) /* in: lock type: RW_LOCK_SHARED,
839
825
rw_lock_debug_t* info;
866
852
#endif /* UNIV_SYNC_DEBUG */
868
/******************************************************************//**
869
Checks if somebody has locked the rw-lock in the specified mode.
870
@return TRUE if locked */
854
/**********************************************************************
855
Checks if somebody has locked the rw-lock in the specified mode. */
873
858
rw_lock_is_locked(
874
859
/*==============*/
875
rw_lock_t* lock, /*!< in: rw-lock */
876
ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED,
860
/* out: TRUE if locked */
861
rw_lock_t* lock, /* in: rw-lock */
862
ulint lock_type) /* in: lock type: RW_LOCK_SHARED,
879
865
ibool ret = FALSE;
899
885
#ifdef UNIV_SYNC_DEBUG
900
/***************************************************************//**
886
/*******************************************************************
901
887
Prints debug info of currently locked rw-locks. */
904
890
rw_lock_list_print_info(
905
891
/*====================*/
906
FILE* file) /*!< in: file where to print */
892
FILE* file) /* in: file where to print */
951
937
mutex_exit(&rw_lock_list_mutex);
954
/***************************************************************//**
940
/*******************************************************************
955
941
Prints debug info of an rw-lock. */
960
rw_lock_t* lock) /*!< in: rw-lock */
946
rw_lock_t* lock) /* in: rw-lock */
962
948
rw_lock_debug_t* info;
967
953
"RW-LATCH: %p ", (void*) lock);
969
955
#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. */
956
mutex_enter(&(lock->mutex));
977
958
if (lock->lock_word != X_LOCK_DECR) {
988
969
info = UT_LIST_GET_NEXT(list, info);
972
#ifndef INNODB_RW_LOCKS_USE_ATOMICS
973
mutex_exit(&(lock->mutex));
993
/*********************************************************************//**
977
/*************************************************************************
994
978
Prints info of a debug struct. */
997
981
rw_lock_debug_print(
998
982
/*================*/
999
rw_lock_debug_t* info) /*!< in: debug struct */
983
rw_lock_debug_t* info) /* in: debug struct */
1020
1004
putc('\n', stderr);
1023
/***************************************************************//**
1007
/*******************************************************************
1024
1008
Returns the number of currently locked rw-locks. Works only in the debug
1026
@return number of locked rw-locks */
1029
1012
rw_lock_n_locked(void)