Drizzled Public API Documentation

sync0rw.cc
1 /*****************************************************************************
2 
3 Copyright (c) 1995, 2011, Oracle and/or its affiliates. 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 /**************************************************/
33 #include "sync0rw.h"
34 #ifdef UNIV_NONINL
35 #include "sync0rw.ic"
36 #endif
37 
38 #include "os0thread.h"
39 #include "mem0mem.h"
40 #include "srv0srv.h"
41 #include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */
42 #include "ha_prototypes.h"
43 
44 /*
45  IMPLEMENTATION OF THE RW_LOCK
46  =============================
47 The status of a rw_lock is held in lock_word. The initial value of lock_word is
48 X_LOCK_DECR. lock_word is decremented by 1 for each s-lock and by X_LOCK_DECR
49 for each x-lock. This describes the lock state for each value of lock_word:
50 
51 lock_word == X_LOCK_DECR: Unlocked.
52 0 < lock_word < X_LOCK_DECR: Read locked, no waiting writers.
53  (X_LOCK_DECR - lock_word) is the
54  number of readers that hold the lock.
55 lock_word == 0: Write locked
56 -X_LOCK_DECR < lock_word < 0: Read locked, with a waiting writer.
57  (-lock_word) is the number of readers
58  that hold the lock.
59 lock_word <= -X_LOCK_DECR: Recursively write locked. lock_word has been
60  decremented by X_LOCK_DECR once for each lock,
61  so the number of locks is:
62  ((-lock_word) / X_LOCK_DECR) + 1
63 When lock_word <= -X_LOCK_DECR, we also know that lock_word % X_LOCK_DECR == 0:
64 other values of lock_word are invalid.
65 
66 The lock_word is always read and updated atomically and consistently, so that
67 it always represents the state of the lock, and the state of the lock changes
68 with a single atomic operation. This lock_word holds all of the information
69 that a thread needs in order to determine if it is eligible to gain the lock
70 or if it must spin or sleep. The one exception to this is that writer_thread
71 must be verified before recursive write locks: to solve this scenario, we make
72 writer_thread readable by all threads, but only writeable by the x-lock holder.
73 
74 The other members of the lock obey the following rules to remain consistent:
75 
76 recursive: This and the writer_thread field together control the
77  behaviour of recursive x-locking.
78  lock->recursive must be FALSE in following states:
79  1) The writer_thread contains garbage i.e.: the
80  lock has just been initialized.
81  2) The lock is not x-held and there is no
82  x-waiter waiting on WAIT_EX event.
83  3) The lock is x-held or there is an x-waiter
84  waiting on WAIT_EX event but the 'pass' value
85  is non-zero.
86  lock->recursive is TRUE iff:
87  1) The lock is x-held or there is an x-waiter
88  waiting on WAIT_EX event and the 'pass' value
89  is zero.
90  This flag must be set after the writer_thread field
91  has been updated with a memory ordering barrier.
92  It is unset before the lock_word has been incremented.
93 writer_thread: Is used only in recursive x-locking. Can only be safely
94  read iff lock->recursive flag is TRUE.
95  This field is uninitialized at lock creation time and
96  is updated atomically when x-lock is acquired or when
97  move_ownership is called. A thread is only allowed to
98  set the value of this field to it's thread_id i.e.: a
99  thread cannot set writer_thread to some other thread's
100  id.
101 waiters: May be set to 1 anytime, but to avoid unnecessary wake-up
102  signals, it should only be set to 1 when there are threads
103  waiting on event. Must be 1 when a writer starts waiting to
104  ensure the current x-locking thread sends a wake-up signal
105  during unlock. May only be reset to 0 immediately before a
106  a wake-up signal is sent to event. On most platforms, a
107  memory barrier is required after waiters is set, and before
108  verifying lock_word is still held, to ensure some unlocker
109  really does see the flags new value.
110 event: Threads wait on event for read or writer lock when another
111  thread has an x-lock or an x-lock reservation (wait_ex). A
112  thread may only wait on event after performing the following
113  actions in order:
114  (1) Record the counter value of event (with os_event_reset).
115  (2) Set waiters to 1.
116  (3) Verify lock_word <= 0.
117  (1) must come before (2) to ensure signal is not missed.
118  (2) must come before (3) to ensure a signal is sent.
119  These restrictions force the above ordering.
120  Immediately before sending the wake-up signal, we should:
121  (1) Verify lock_word == X_LOCK_DECR (unlocked)
122  (2) Reset waiters to 0.
123 wait_ex_event: A thread may only wait on the wait_ex_event after it has
124  performed the following actions in order:
125  (1) Decrement lock_word by X_LOCK_DECR.
126  (2) Record counter value of wait_ex_event (os_event_reset,
127  called from sync_array_reserve_cell).
128  (3) Verify that lock_word < 0.
129  (1) must come first to ensures no other threads become reader
130  or next writer, and notifies unlocker that signal must be sent.
131  (2) must come before (3) to ensure the signal is not missed.
132  These restrictions force the above ordering.
133  Immediately before sending the wake-up signal, we should:
134  Verify lock_word == 0 (waiting thread holds x_lock)
135 */
136 
137 
140 UNIV_INTERN ib_int64_t rw_s_spin_wait_count = 0;
143 UNIV_INTERN ib_int64_t rw_s_spin_round_count = 0;
144 
147 UNIV_INTERN ib_int64_t rw_s_os_wait_count = 0;
148 
151 UNIV_INTERN ib_int64_t rw_s_exit_count = 0;
152 
155 UNIV_INTERN ib_int64_t rw_x_spin_wait_count = 0;
158 UNIV_INTERN ib_int64_t rw_x_spin_round_count = 0;
159 
162 UNIV_INTERN ib_int64_t rw_x_os_wait_count = 0;
163 
166 UNIV_INTERN ib_int64_t rw_x_exit_count = 0;
167 
168 /* The global list of rw-locks */
169 UNIV_INTERN rw_lock_list_t rw_lock_list;
170 UNIV_INTERN mutex_t rw_lock_list_mutex;
171 
172 #ifdef UNIV_PFS_MUTEX
173 UNIV_INTERN mysql_pfs_key_t rw_lock_list_mutex_key;
174 UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key;
175 #endif /* UNIV_PFS_MUTEX */
176 
177 #ifdef UNIV_SYNC_DEBUG
178 /* The global mutex which protects debug info lists of all rw-locks.
179 To modify the debug info list of an rw-lock, this mutex has to be
180 acquired in addition to the mutex protecting the lock. */
181 
182 UNIV_INTERN mutex_t rw_lock_debug_mutex;
183 
184 # ifdef UNIV_PFS_MUTEX
185 UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key;
186 # endif
187 
188 /* If deadlock detection does not get immediately the mutex,
189 it may wait for this event */
190 UNIV_INTERN os_event_t rw_lock_debug_event;
191 /* This is set to TRUE, if there may be waiters for the event */
192 UNIV_INTERN ibool rw_lock_debug_waiters;
193 
194 /******************************************************************/
196 static
197 rw_lock_debug_t*
198 rw_lock_debug_create(void);
199 /*======================*/
200 /******************************************************************/
202 static
203 void
204 rw_lock_debug_free(
205 /*===============*/
206  rw_lock_debug_t* info);
207 
208 /******************************************************************/
211 static
212 rw_lock_debug_t*
213 rw_lock_debug_create(void)
214 /*======================*/
215 {
216  return((rw_lock_debug_t*) mem_alloc(sizeof(rw_lock_debug_t)));
217 }
218 
219 /******************************************************************/
221 static
222 void
223 rw_lock_debug_free(
224 /*===============*/
225  rw_lock_debug_t* info)
226 {
227  mem_free(info);
228 }
229 #endif /* UNIV_SYNC_DEBUG */
230 
231 /******************************************************************/
236 UNIV_INTERN
237 void
239 /*================*/
240  rw_lock_t* lock,
241 #ifdef UNIV_DEBUG
242 # ifdef UNIV_SYNC_DEBUG
243  ulint level,
244 # endif /* UNIV_SYNC_DEBUG */
245  const char* cmutex_name,
246 #endif /* UNIV_DEBUG */
247  const char* cfile_name,
248  ulint cline)
249 {
250  /* If this is the very first time a synchronization object is
251  created, then the following call initializes the sync system. */
252 
253 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
254  mutex_create(rw_lock_mutex_key, rw_lock_get_mutex(lock),
255  SYNC_NO_ORDER_CHECK);
256 
257  lock->mutex.cfile_name = cfile_name;
258  lock->mutex.cline = cline;
259 
260  ut_d(lock->mutex.cmutex_name = cmutex_name);
261  ut_d(lock->mutex.mutex_type = 1);
262 #else /* INNODB_RW_LOCKS_USE_ATOMICS */
263 # ifdef UNIV_DEBUG
264  UT_NOT_USED(cmutex_name);
265 # endif
266 #endif /* INNODB_RW_LOCKS_USE_ATOMICS */
267 
268  lock->lock_word = X_LOCK_DECR;
269  lock->waiters = 0;
270 
271  /* We set this value to signify that lock->writer_thread
272  contains garbage at initialization and cannot be used for
273  recursive x-locking. */
274  lock->recursive = FALSE;
275  /* Silence Valgrind when UNIV_DEBUG_VALGRIND is not enabled. */
276  memset((void*) &lock->writer_thread, 0, sizeof lock->writer_thread);
277  UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread);
278 
279 #ifdef UNIV_SYNC_DEBUG
280  UT_LIST_INIT(lock->debug_list);
281 
282  lock->level = level;
283 #endif /* UNIV_SYNC_DEBUG */
284 
285  ut_d(lock->magic_n = RW_LOCK_MAGIC_N);
286 
287  lock->cfile_name = cfile_name;
288  lock->cline = (unsigned int) cline;
289 
290  lock->count_os_wait = 0;
291  lock->last_s_file_name = "not yet reserved";
292  lock->last_x_file_name = "not yet reserved";
293  lock->last_s_line = 0;
294  lock->last_x_line = 0;
295  lock->event = os_event_create(NULL);
296  lock->wait_ex_event = os_event_create(NULL);
297 
298  mutex_enter(&rw_lock_list_mutex);
299 
300  ut_ad(UT_LIST_GET_FIRST(rw_lock_list) == NULL
301  || UT_LIST_GET_FIRST(rw_lock_list)->magic_n == RW_LOCK_MAGIC_N);
302 
303  UT_LIST_ADD_FIRST(list, rw_lock_list, lock);
304 
305  mutex_exit(&rw_lock_list_mutex);
306 }
307 
308 /******************************************************************/
312 UNIV_INTERN
313 void
315 /*==============*/
316  rw_lock_t* lock)
317 {
318  ut_ad(rw_lock_validate(lock));
319  ut_a(lock->lock_word == X_LOCK_DECR);
320 
321 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
322  mutex_free(rw_lock_get_mutex(lock));
323 #endif /* INNODB_RW_LOCKS_USE_ATOMICS */
324 
325  mutex_enter(&rw_lock_list_mutex);
326  os_event_free(lock->event);
327 
329 
330  ut_ad(UT_LIST_GET_PREV(list, lock) == NULL
331  || UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
332  ut_ad(UT_LIST_GET_NEXT(list, lock) == NULL
333  || UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N);
334 
335  UT_LIST_REMOVE(list, rw_lock_list, lock);
336 
337  mutex_exit(&rw_lock_list_mutex);
338 
339  ut_d(lock->magic_n = 0);
340 }
341 
342 #ifdef UNIV_DEBUG
343 /******************************************************************/
347 UNIV_INTERN
348 ibool
349 rw_lock_validate(
350 /*=============*/
351  rw_lock_t* lock)
352 {
353  ulint waiters;
354  lint lock_word;
355 
356  ut_a(lock);
357 
358  waiters = rw_lock_get_waiters(lock);
359  lock_word = lock->lock_word;
360 
361  ut_ad(lock->magic_n == RW_LOCK_MAGIC_N);
362  ut_a(waiters == 0 || waiters == 1);
363  ut_a(lock_word > -X_LOCK_DECR ||(-lock_word) % X_LOCK_DECR == 0);
364 
365  return(TRUE);
366 }
367 #endif /* UNIV_DEBUG */
368 
369 /******************************************************************/
374 UNIV_INTERN
375 void
376 rw_lock_s_lock_spin(
377 /*================*/
378  rw_lock_t* lock,
379  ulint pass,
381  const char* file_name,
382  ulint line)
383 {
384  ulint index; /* index of the reserved wait cell */
385  ulint i = 0; /* spin round count */
386 
387  ut_ad(rw_lock_validate(lock));
388 
390 lock_loop:
391 
392  /* Spin waiting for the writer field to become free */
393  while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
394  if (srv_spin_wait_delay) {
395  ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
396  }
397 
398  i++;
399  }
400 
401  if (i == SYNC_SPIN_ROUNDS) {
402  os_thread_yield();
403  }
404 
405  if (srv_print_latch_waits) {
406  fprintf(stderr,
407  "Thread %lu spin wait rw-s-lock at %p"
408  " cfile %s cline %lu rnds %lu\n",
410  (void*) lock,
412  (ulong) lock->cline, (ulong) i);
413  }
414 
415  /* We try once again to obtain the lock */
416  if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
418 
419  return; /* Success */
420  } else {
421 
422  if (i < SYNC_SPIN_ROUNDS) {
423  goto lock_loop;
424  }
425 
427 
428  sync_array_reserve_cell(sync_primary_wait_array,
429  lock, RW_LOCK_SHARED,
430  file_name, line,
431  &index);
432 
433  /* Set waiters before checking lock_word to ensure wake-up
434  signal is sent. This may lead to some unnecessary signals. */
435  rw_lock_set_waiter_flag(lock);
436 
437  if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
438  sync_array_free_cell(sync_primary_wait_array, index);
439  return; /* Success */
440  }
441 
442  if (srv_print_latch_waits) {
443  fprintf(stderr,
444  "Thread %lu OS wait rw-s-lock at %p"
445  " cfile %s cline %lu\n",
447  (void*) lock,
449  (ulong) lock->cline);
450  }
451 
452  /* these stats may not be accurate */
453  lock->count_os_wait++;
455 
456  sync_array_wait_event(sync_primary_wait_array, index);
457 
458  i = 0;
459  goto lock_loop;
460  }
461 }
462 
463 /******************************************************************/
471 UNIV_INTERN
472 void
474 /*==========================*/
475  rw_lock_t* lock)
477 {
478  ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
479 
481 }
482 
483 /******************************************************************/
486 UNIV_INLINE
487 void
488 rw_lock_x_lock_wait(
489 /*================*/
490  rw_lock_t* lock,
491 #ifdef UNIV_SYNC_DEBUG
492  ulint pass,
494 #endif
495  const char* file_name,
496  ulint line)
497 {
498  ulint index;
499  ulint i = 0;
500 
501  ut_ad(lock->lock_word <= 0);
502 
503  while (lock->lock_word < 0) {
504  if (srv_spin_wait_delay) {
505  ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
506  }
507  if(i < SYNC_SPIN_ROUNDS) {
508  i++;
509  continue;
510  }
511 
512  /* If there is still a reader, then go to sleep.*/
514  i = 0;
515  sync_array_reserve_cell(sync_primary_wait_array,
516  lock,
517  RW_LOCK_WAIT_EX,
518  file_name, line,
519  &index);
520  /* Check lock_word to ensure wake-up isn't missed.*/
521  if(lock->lock_word < 0) {
522 
523  /* these stats may not be accurate */
524  lock->count_os_wait++;
526 
527  /* Add debug info as it is needed to detect possible
528  deadlock. We must add info for WAIT_EX thread for
529  deadlock detection to work properly. */
530 #ifdef UNIV_SYNC_DEBUG
531  rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
532  file_name, line);
533 #endif
534 
535  sync_array_wait_event(sync_primary_wait_array,
536  index);
537 #ifdef UNIV_SYNC_DEBUG
538  rw_lock_remove_debug_info(lock, pass,
539  RW_LOCK_WAIT_EX);
540 #endif
541  /* It is possible to wake when lock_word < 0.
542  We must pass the while-loop check to proceed.*/
543  } else {
544  sync_array_free_cell(sync_primary_wait_array,
545  index);
546  }
547  }
549 }
550 
551 /******************************************************************/
554 UNIV_INLINE
555 ibool
556 rw_lock_x_lock_low(
557 /*===============*/
558  rw_lock_t* lock,
559  ulint pass,
561  const char* file_name,
562  ulint line)
563 {
564  os_thread_id_t curr_thread = os_thread_get_curr_id();
565 
566  if (rw_lock_lock_word_decr(lock, X_LOCK_DECR)) {
567 
568  /* lock->recursive also tells us if the writer_thread
569  field is stale or active. As we are going to write
570  our own thread id in that field it must be that the
571  current writer_thread value is not active. */
572  ut_a(!lock->recursive);
573 
574  /* Decrement occurred: we are writer or next-writer. */
576  pass ? FALSE : TRUE);
577 
578  rw_lock_x_lock_wait(lock,
579 #ifdef UNIV_SYNC_DEBUG
580  pass,
581 #endif
582  file_name, line);
583 
584  } else {
585  /* Decrement failed: relock or failed lock */
586  if (!pass && lock->recursive
587  && os_thread_eq(lock->writer_thread, curr_thread)) {
588  /* Relock */
589  lock->lock_word -= X_LOCK_DECR;
590  } else {
591  /* Another thread locked before us */
592  return(FALSE);
593  }
594  }
595 #ifdef UNIV_SYNC_DEBUG
596  rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
597  file_name, line);
598 #endif
599  lock->last_x_file_name = file_name;
600  lock->last_x_line = (unsigned int) line;
601 
602  return(TRUE);
603 }
604 
605 /******************************************************************/
614 UNIV_INTERN
615 void
617 /*================*/
618  rw_lock_t* lock,
619  ulint pass,
621  const char* file_name,
622  ulint line)
623 {
624  ulint index;
625  ulint i;
626  ibool spinning = FALSE;
627 
628  ut_ad(rw_lock_validate(lock));
629 
630  i = 0;
631 
632 lock_loop:
633 
634  if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
636 
637  return; /* Locking succeeded */
638 
639  } else {
640 
641  if (!spinning) {
642  spinning = TRUE;
644  }
645 
646  /* Spin waiting for the lock_word to become free */
647  while (i < SYNC_SPIN_ROUNDS
648  && lock->lock_word <= 0) {
649  if (srv_spin_wait_delay) {
651  srv_spin_wait_delay));
652  }
653 
654  i++;
655  }
656  if (i == SYNC_SPIN_ROUNDS) {
657  os_thread_yield();
658  } else {
659  goto lock_loop;
660  }
661  }
662 
664 
665  if (srv_print_latch_waits) {
666  fprintf(stderr,
667  "Thread %lu spin wait rw-x-lock at %p"
668  " cfile %s cline %lu rnds %lu\n",
669  os_thread_pf(os_thread_get_curr_id()), (void*) lock,
671  (ulong) lock->cline, (ulong) i);
672  }
673 
675  lock,
676  RW_LOCK_EX,
677  file_name, line,
678  &index);
679 
680  /* Waiters must be set before checking lock_word, to ensure signal
681  is sent. This could lead to a few unnecessary wake-up signals. */
682  rw_lock_set_waiter_flag(lock);
683 
684  if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
686  return; /* Locking succeeded */
687  }
688 
689  if (srv_print_latch_waits) {
690  fprintf(stderr,
691  "Thread %lu OS wait for rw-x-lock at %p"
692  " cfile %s cline %lu\n",
693  os_thread_pf(os_thread_get_curr_id()), (void*) lock,
695  (ulong) lock->cline);
696  }
697 
698  /* these stats may not be accurate */
699  lock->count_os_wait++;
701 
703 
704  i = 0;
705  goto lock_loop;
706 }
707 
708 #ifdef UNIV_SYNC_DEBUG
709 /******************************************************************/
715 UNIV_INTERN
716 void
717 rw_lock_debug_mutex_enter(void)
718 /*==========================*/
719 {
720 loop:
721  if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
722  return;
723  }
724 
725  os_event_reset(rw_lock_debug_event);
726 
727  rw_lock_debug_waiters = TRUE;
728 
729  if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
730  return;
731  }
732 
733  os_event_wait(rw_lock_debug_event);
734 
735  goto loop;
736 }
737 
738 /******************************************************************/
740 UNIV_INTERN
741 void
742 rw_lock_debug_mutex_exit(void)
743 /*==========================*/
744 {
745  mutex_exit(&rw_lock_debug_mutex);
746 
747  if (rw_lock_debug_waiters) {
748  rw_lock_debug_waiters = FALSE;
749  os_event_set(rw_lock_debug_event);
750  }
751 }
752 
753 /******************************************************************/
755 UNIV_INTERN
756 void
757 rw_lock_add_debug_info(
758 /*===================*/
759  rw_lock_t* lock,
760  ulint pass,
761  ulint lock_type,
762  const char* file_name,
763  ulint line)
764 {
765  rw_lock_debug_t* info;
766 
767  ut_ad(lock);
768  ut_ad(file_name);
769 
770  info = rw_lock_debug_create();
771 
772  rw_lock_debug_mutex_enter();
773 
774  info->file_name = file_name;
775  info->line = line;
776  info->lock_type = lock_type;
777  info->thread_id = os_thread_get_curr_id();
778  info->pass = pass;
779 
780  UT_LIST_ADD_FIRST(list, lock->debug_list, info);
781 
782  rw_lock_debug_mutex_exit();
783 
784  if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
785  sync_thread_add_level(lock, lock->level);
786  }
787 }
788 
789 /******************************************************************/
791 UNIV_INTERN
792 void
793 rw_lock_remove_debug_info(
794 /*======================*/
795  rw_lock_t* lock,
796  ulint pass,
797  ulint lock_type)
798 {
799  rw_lock_debug_t* info;
800 
801  ut_ad(lock);
802 
803  if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
804  sync_thread_reset_level(lock);
805  }
806 
807  rw_lock_debug_mutex_enter();
808 
809  info = UT_LIST_GET_FIRST(lock->debug_list);
810 
811  while (info != NULL) {
812  if ((pass == info->pass)
813  && ((pass != 0)
814  || os_thread_eq(info->thread_id,
816  && (info->lock_type == lock_type)) {
817 
818  /* Found! */
819  UT_LIST_REMOVE(list, lock->debug_list, info);
820  rw_lock_debug_mutex_exit();
821 
822  rw_lock_debug_free(info);
823 
824  return;
825  }
826 
827  info = UT_LIST_GET_NEXT(list, info);
828  }
829 
830  ut_error;
831 }
832 #endif /* UNIV_SYNC_DEBUG */
833 
834 #ifdef UNIV_SYNC_DEBUG
835 /******************************************************************/
839 UNIV_INTERN
840 ibool
841 rw_lock_own(
842 /*========*/
843  rw_lock_t* lock,
844  ulint lock_type)
846 {
847  rw_lock_debug_t* info;
848 
849  ut_ad(lock);
850  ut_ad(rw_lock_validate(lock));
851 
852  rw_lock_debug_mutex_enter();
853 
854  info = UT_LIST_GET_FIRST(lock->debug_list);
855 
856  while (info != NULL) {
857 
858  if (os_thread_eq(info->thread_id, os_thread_get_curr_id())
859  && (info->pass == 0)
860  && (info->lock_type == lock_type)) {
861 
862  rw_lock_debug_mutex_exit();
863  /* Found! */
864 
865  return(TRUE);
866  }
867 
868  info = UT_LIST_GET_NEXT(list, info);
869  }
870  rw_lock_debug_mutex_exit();
871 
872  return(FALSE);
873 }
874 #endif /* UNIV_SYNC_DEBUG */
875 
876 /******************************************************************/
879 UNIV_INTERN
880 ibool
882 /*==============*/
883  rw_lock_t* lock,
884  ulint lock_type)
886 {
887  ibool ret = FALSE;
888 
889  ut_ad(lock);
890  ut_ad(rw_lock_validate(lock));
891 
892  if (lock_type == RW_LOCK_SHARED) {
893  if (rw_lock_get_reader_count(lock) > 0) {
894  ret = TRUE;
895  }
896  } else if (lock_type == RW_LOCK_EX) {
897  if (rw_lock_get_writer(lock) == RW_LOCK_EX) {
898  ret = TRUE;
899  }
900  } else {
901  ut_error;
902  }
903 
904  return(ret);
905 }
906 
907 #ifdef UNIV_SYNC_DEBUG
908 /***************************************************************/
910 UNIV_INTERN
911 void
912 rw_lock_list_print_info(
913 /*====================*/
914  FILE* file)
915 {
916  rw_lock_t* lock;
917  ulint count = 0;
918  rw_lock_debug_t* info;
919 
920  mutex_enter(&rw_lock_list_mutex);
921 
922  fputs("-------------\n"
923  "RW-LATCH INFO\n"
924  "-------------\n", file);
925 
926  lock = UT_LIST_GET_FIRST(rw_lock_list);
927 
928  while (lock != NULL) {
929 
930  count++;
931 
932 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
933  mutex_enter(&(lock->mutex));
934 #endif
935  if (lock->lock_word != X_LOCK_DECR) {
936 
937  fprintf(file, "RW-LOCK: %p ", (void*) lock);
938 
939  if (rw_lock_get_waiters(lock)) {
940  fputs(" Waiters for the lock exist\n", file);
941  } else {
942  putc('\n', file);
943  }
944 
945  info = UT_LIST_GET_FIRST(lock->debug_list);
946  while (info != NULL) {
947  rw_lock_debug_print(file, info);
948  info = UT_LIST_GET_NEXT(list, info);
949  }
950  }
951 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
952  mutex_exit(&(lock->mutex));
953 #endif
954 
955  lock = UT_LIST_GET_NEXT(list, lock);
956  }
957 
958  fprintf(file, "Total number of rw-locks %ld\n", count);
959  mutex_exit(&rw_lock_list_mutex);
960 }
961 
962 /***************************************************************/
964 UNIV_INTERN
965 void
966 rw_lock_print(
967 /*==========*/
968  rw_lock_t* lock)
969 {
970  rw_lock_debug_t* info;
971 
972  fprintf(stderr,
973  "-------------\n"
974  "RW-LATCH INFO\n"
975  "RW-LATCH: %p ", (void*) lock);
976 
977 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
978  /* We used to acquire lock->mutex here, but it would cause a
979  recursive call to sync_thread_add_level() if UNIV_SYNC_DEBUG
980  is defined. Since this function is only invoked from
981  sync_thread_levels_g(), let us choose the smaller evil:
982  performing dirty reads instead of causing bogus deadlocks or
983  assertion failures. */
984 #endif
985  if (lock->lock_word != X_LOCK_DECR) {
986 
987  if (rw_lock_get_waiters(lock)) {
988  fputs(" Waiters for the lock exist\n", stderr);
989  } else {
990  putc('\n', stderr);
991  }
992 
993  info = UT_LIST_GET_FIRST(lock->debug_list);
994  while (info != NULL) {
995  rw_lock_debug_print(stderr, info);
996  info = UT_LIST_GET_NEXT(list, info);
997  }
998  }
999 }
1000 
1001 /*********************************************************************/
1003 UNIV_INTERN
1004 void
1005 rw_lock_debug_print(
1006 /*================*/
1007  FILE* f,
1008  rw_lock_debug_t* info)
1009 {
1010  ulint rwt;
1011 
1012  rwt = info->lock_type;
1013 
1014  fprintf(f, "Locked: thread %lu file %s line %lu ",
1015  (ulong) os_thread_pf(info->thread_id), info->file_name,
1016  (ulong) info->line);
1017  if (rwt == RW_LOCK_SHARED) {
1018  fputs("S-LOCK", f);
1019  } else if (rwt == RW_LOCK_EX) {
1020  fputs("X-LOCK", f);
1021  } else if (rwt == RW_LOCK_WAIT_EX) {
1022  fputs("WAIT X-LOCK", f);
1023  } else {
1024  ut_error;
1025  }
1026  if (info->pass != 0) {
1027  fprintf(f, " pass value %lu", (ulong) info->pass);
1028  }
1029  putc('\n', f);
1030 }
1031 
1032 /***************************************************************/
1036 UNIV_INTERN
1037 ulint
1038 rw_lock_n_locked(void)
1039 /*==================*/
1040 {
1041  rw_lock_t* lock;
1042  ulint count = 0;
1043 
1044  mutex_enter(&rw_lock_list_mutex);
1045 
1046  lock = UT_LIST_GET_FIRST(rw_lock_list);
1047 
1048  while (lock != NULL) {
1049 
1050  if (lock->lock_word != X_LOCK_DECR) {
1051  count++;
1052  }
1053 
1054  lock = UT_LIST_GET_NEXT(list, lock);
1055  }
1056 
1057  mutex_exit(&rw_lock_list_mutex);
1058 
1059  return(count);
1060 }
1061 #endif /* UNIV_SYNC_DEBUG */