Drizzled Public API Documentation

sync0rw.cc
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 /**************************************************/
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 
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 
139 UNIV_INTERN ib_int64_t rw_s_spin_wait_count = 0;
142 UNIV_INTERN ib_int64_t rw_s_spin_round_count = 0;
143 
146 UNIV_INTERN ib_int64_t rw_s_os_wait_count = 0;
147 
150 UNIV_INTERN ib_int64_t rw_s_exit_count = 0;
151 
154 UNIV_INTERN ib_int64_t rw_x_spin_wait_count = 0;
157 UNIV_INTERN ib_int64_t rw_x_spin_round_count = 0;
158 
161 UNIV_INTERN ib_int64_t rw_x_os_wait_count = 0;
162 
165 UNIV_INTERN ib_int64_t rw_x_exit_count = 0;
166 
167 /* The global list of rw-locks */
168 UNIV_INTERN rw_lock_list_t rw_lock_list;
169 UNIV_INTERN mutex_t rw_lock_list_mutex;
170 
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 #ifdef UNIV_SYNC_DEBUG
177 /* The global mutex which protects debug info lists of all rw-locks.
178 To modify the debug info list of an rw-lock, this mutex has to be
179 acquired in addition to the mutex protecting the lock. */
180 
181 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 /* If deadlock detection does not get immediately the mutex,
188 it may wait for this event */
189 UNIV_INTERN os_event_t rw_lock_debug_event;
190 /* This is set to TRUE, if there may be waiters for the event */
191 UNIV_INTERN ibool rw_lock_debug_waiters;
192 
193 /******************************************************************/
195 static
196 rw_lock_debug_t*
197 rw_lock_debug_create(void);
198 /*======================*/
199 /******************************************************************/
201 static
202 void
203 rw_lock_debug_free(
204 /*===============*/
205  rw_lock_debug_t* info);
206 
207 /******************************************************************/
210 static
211 rw_lock_debug_t*
212 rw_lock_debug_create(void)
213 /*======================*/
214 {
215  return((rw_lock_debug_t*) mem_alloc(sizeof(rw_lock_debug_t)));
216 }
217 
218 /******************************************************************/
220 static
221 void
222 rw_lock_debug_free(
223 /*===============*/
224  rw_lock_debug_t* info)
225 {
226  mem_free(info);
227 }
228 #endif /* UNIV_SYNC_DEBUG */
229 
230 /******************************************************************/
235 UNIV_INTERN
236 void
238 /*================*/
239  rw_lock_t* lock,
240 #ifdef UNIV_DEBUG
241 # ifdef UNIV_SYNC_DEBUG
242  ulint level,
243 # endif /* UNIV_SYNC_DEBUG */
244  const char* cmutex_name,
245 #endif /* UNIV_DEBUG */
246  const char* cfile_name,
247  ulint cline)
248 {
249  /* If this is the very first time a synchronization object is
250  created, then the following call initializes the sync system. */
251 
252 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
253  mutex_create(rw_lock_mutex_key, rw_lock_get_mutex(lock),
254  SYNC_NO_ORDER_CHECK);
255 
256  lock->mutex.cfile_name = cfile_name;
257  lock->mutex.cline = cline;
258 
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;
274 
275 #ifdef UNIV_SYNC_DEBUG
276  UT_LIST_INIT(lock->debug_list);
277 
278  lock->level = level;
279 #endif /* UNIV_SYNC_DEBUG */
280 
281  ut_d(lock->magic_n = RW_LOCK_MAGIC_N);
282 
283  lock->cfile_name = cfile_name;
284  lock->cline = (unsigned int) cline;
285 
286  lock->count_os_wait = 0;
287  lock->last_s_file_name = "not yet reserved";
288  lock->last_x_file_name = "not yet reserved";
289  lock->last_s_line = 0;
290  lock->last_x_line = 0;
291  lock->event = os_event_create(NULL);
292  lock->wait_ex_event = os_event_create(NULL);
293 
294  mutex_enter(&rw_lock_list_mutex);
295 
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);
298 
299  UT_LIST_ADD_FIRST(list, rw_lock_list, lock);
300 
301  mutex_exit(&rw_lock_list_mutex);
302 }
303 
304 /******************************************************************/
308 UNIV_INTERN
309 void
311 /*==============*/
312  rw_lock_t* lock)
313 {
314  ut_ad(rw_lock_validate(lock));
315  ut_a(lock->lock_word == X_LOCK_DECR);
316 
317 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
318  mutex_free(rw_lock_get_mutex(lock));
319 #endif /* INNODB_RW_LOCKS_USE_ATOMICS */
320 
321  mutex_enter(&rw_lock_list_mutex);
322  os_event_free(lock->event);
323 
325 
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);
330 
331  UT_LIST_REMOVE(list, rw_lock_list, lock);
332 
333  mutex_exit(&rw_lock_list_mutex);
334 
335  ut_d(lock->magic_n = 0);
336 }
337 
338 #ifdef UNIV_DEBUG
339 /******************************************************************/
343 UNIV_INTERN
344 ibool
345 rw_lock_validate(
346 /*=============*/
347  rw_lock_t* lock)
348 {
349  ulint waiters;
350  lint lock_word;
351 
352  ut_a(lock);
353 
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);
360 
361  return(TRUE);
362 }
363 #endif /* UNIV_DEBUG */
364 
365 /******************************************************************/
370 UNIV_INTERN
371 void
372 rw_lock_s_lock_spin(
373 /*================*/
374  rw_lock_t* lock,
375  ulint pass,
377  const char* file_name,
378  ulint line)
379 {
380  ulint index; /* index of the reserved wait cell */
381  ulint i = 0; /* spin round count */
382 
383  ut_ad(rw_lock_validate(lock));
384 
386 lock_loop:
387 
388  /* Spin waiting for the writer field to become free */
389  while (i < SYNC_SPIN_ROUNDS && lock->lock_word <= 0) {
390  if (srv_spin_wait_delay) {
391  ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
392  }
393 
394  i++;
395  }
396 
397  if (i == SYNC_SPIN_ROUNDS) {
398  os_thread_yield();
399  }
400 
401  if (srv_print_latch_waits) {
402  fprintf(stderr,
403  "Thread %lu spin wait rw-s-lock at %p"
404  " cfile %s cline %lu rnds %lu\n",
406  (void*) lock,
407  lock->cfile_name, (ulong) lock->cline, (ulong) i);
408  }
409 
410  /* We try once again to obtain the lock */
411  if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
413 
414  return; /* Success */
415  } else {
416 
417  if (i < SYNC_SPIN_ROUNDS) {
418  goto lock_loop;
419  }
420 
422 
423  sync_array_reserve_cell(sync_primary_wait_array,
424  lock, RW_LOCK_SHARED,
425  file_name, line,
426  &index);
427 
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);
431 
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  }
436 
437  if (srv_print_latch_waits) {
438  fprintf(stderr,
439  "Thread %lu OS wait rw-s-lock at %p"
440  " cfile %s cline %lu\n",
442  (void*) lock, lock->cfile_name,
443  (ulong) lock->cline);
444  }
445 
446  /* these stats may not be accurate */
447  lock->count_os_wait++;
449 
450  sync_array_wait_event(sync_primary_wait_array, index);
451 
452  i = 0;
453  goto lock_loop;
454  }
455 }
456 
457 /******************************************************************/
465 UNIV_INTERN
466 void
468 /*==========================*/
469  rw_lock_t* lock)
471 {
472  ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
473 
475 }
476 
477 /******************************************************************/
480 UNIV_INLINE
481 void
482 rw_lock_x_lock_wait(
483 /*================*/
484  rw_lock_t* lock,
485 #ifdef UNIV_SYNC_DEBUG
486  ulint pass,
488 #endif
489  const char* file_name,
490  ulint line)
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.*/
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++;
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. */
524 #ifdef UNIV_SYNC_DEBUG
525  rw_lock_add_debug_info(lock, pass, RW_LOCK_WAIT_EX,
526  file_name, line);
527 #endif
528 
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  }
543 }
544 
545 /******************************************************************/
548 UNIV_INLINE
549 ibool
550 rw_lock_x_lock_low(
551 /*===============*/
552  rw_lock_t* lock,
553  ulint pass,
555  const char* file_name,
556  ulint line)
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. */
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 /******************************************************************/
608 UNIV_INTERN
609 void
611 /*================*/
612  rw_lock_t* lock,
613  ulint pass,
615  const char* file_name,
616  ulint line)
617 {
618  ulint index;
619  ulint i;
620  ibool spinning = FALSE;
621 
622  ut_ad(rw_lock_validate(lock));
623 
624  i = 0;
625 
626 lock_loop:
627 
628  if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
630 
631  return; /* Locking succeeded */
632 
633  } else {
634 
635  if (!spinning) {
636  spinning = TRUE;
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) {
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  }
655  }
656 
658 
659  if (srv_print_latch_waits) {
660  fprintf(stderr,
661  "Thread %lu spin wait rw-x-lock at %p"
662  " cfile %s cline %lu rnds %lu\n",
663  os_thread_pf(os_thread_get_curr_id()), (void*) lock,
664  lock->cfile_name, (ulong) lock->cline, (ulong) i);
665  }
666 
668  lock,
669  RW_LOCK_EX,
670  file_name, line,
671  &index);
672 
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);
676 
677  if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
679  return; /* Locking succeeded */
680  }
681 
682  if (srv_print_latch_waits) {
683  fprintf(stderr,
684  "Thread %lu OS wait for rw-x-lock at %p"
685  " cfile %s cline %lu\n",
686  os_thread_pf(os_thread_get_curr_id()), (void*) lock,
687  lock->cfile_name, (ulong) lock->cline);
688  }
689 
690  /* these stats may not be accurate */
691  lock->count_os_wait++;
693 
695 
696  i = 0;
697  goto lock_loop;
698 }
699 
700 #ifdef UNIV_SYNC_DEBUG
701 /******************************************************************/
707 UNIV_INTERN
708 void
709 rw_lock_debug_mutex_enter(void)
710 /*==========================*/
711 {
712 loop:
713  if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
714  return;
715  }
716 
717  os_event_reset(rw_lock_debug_event);
718 
719  rw_lock_debug_waiters = TRUE;
720 
721  if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
722  return;
723  }
724 
725  os_event_wait(rw_lock_debug_event);
726 
727  goto loop;
728 }
729 
730 /******************************************************************/
732 UNIV_INTERN
733 void
734 rw_lock_debug_mutex_exit(void)
735 /*==========================*/
736 {
737  mutex_exit(&rw_lock_debug_mutex);
738 
739  if (rw_lock_debug_waiters) {
740  rw_lock_debug_waiters = FALSE;
741  os_event_set(rw_lock_debug_event);
742  }
743 }
744 
745 /******************************************************************/
747 UNIV_INTERN
748 void
749 rw_lock_add_debug_info(
750 /*===================*/
751  rw_lock_t* lock,
752  ulint pass,
753  ulint lock_type,
754  const char* file_name,
755  ulint line)
756 {
757  rw_lock_debug_t* info;
758 
759  ut_ad(lock);
760  ut_ad(file_name);
761 
762  info = rw_lock_debug_create();
763 
764  rw_lock_debug_mutex_enter();
765 
766  info->file_name = file_name;
767  info->line = line;
768  info->lock_type = lock_type;
769  info->thread_id = os_thread_get_curr_id();
770  info->pass = pass;
771 
772  UT_LIST_ADD_FIRST(list, lock->debug_list, info);
773 
774  rw_lock_debug_mutex_exit();
775 
776  if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
777  sync_thread_add_level(lock, lock->level);
778  }
779 }
780 
781 /******************************************************************/
783 UNIV_INTERN
784 void
785 rw_lock_remove_debug_info(
786 /*======================*/
787  rw_lock_t* lock,
788  ulint pass,
789  ulint lock_type)
790 {
791  rw_lock_debug_t* info;
792 
793  ut_ad(lock);
794 
795  if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
796  sync_thread_reset_level(lock);
797  }
798 
799  rw_lock_debug_mutex_enter();
800 
801  info = UT_LIST_GET_FIRST(lock->debug_list);
802 
803  while (info != NULL) {
804  if ((pass == info->pass)
805  && ((pass != 0)
806  || os_thread_eq(info->thread_id,
808  && (info->lock_type == lock_type)) {
809 
810  /* Found! */
811  UT_LIST_REMOVE(list, lock->debug_list, info);
812  rw_lock_debug_mutex_exit();
813 
814  rw_lock_debug_free(info);
815 
816  return;
817  }
818 
819  info = UT_LIST_GET_NEXT(list, info);
820  }
821 
822  ut_error;
823 }
824 #endif /* UNIV_SYNC_DEBUG */
825 
826 #ifdef UNIV_SYNC_DEBUG
827 /******************************************************************/
831 UNIV_INTERN
832 ibool
833 rw_lock_own(
834 /*========*/
835  rw_lock_t* lock,
836  ulint lock_type)
838 {
839  rw_lock_debug_t* info;
840 
841  ut_ad(lock);
842  ut_ad(rw_lock_validate(lock));
843 
844  rw_lock_debug_mutex_enter();
845 
846  info = UT_LIST_GET_FIRST(lock->debug_list);
847 
848  while (info != NULL) {
849 
850  if (os_thread_eq(info->thread_id, os_thread_get_curr_id())
851  && (info->pass == 0)
852  && (info->lock_type == lock_type)) {
853 
854  rw_lock_debug_mutex_exit();
855  /* Found! */
856 
857  return(TRUE);
858  }
859 
860  info = UT_LIST_GET_NEXT(list, info);
861  }
862  rw_lock_debug_mutex_exit();
863 
864  return(FALSE);
865 }
866 #endif /* UNIV_SYNC_DEBUG */
867 
868 /******************************************************************/
871 UNIV_INTERN
872 ibool
874 /*==============*/
875  rw_lock_t* lock,
876  ulint lock_type)
878 {
879  ibool ret = FALSE;
880 
881  ut_ad(lock);
882  ut_ad(rw_lock_validate(lock));
883 
884  if (lock_type == RW_LOCK_SHARED) {
885  if (rw_lock_get_reader_count(lock) > 0) {
886  ret = TRUE;
887  }
888  } else if (lock_type == RW_LOCK_EX) {
889  if (rw_lock_get_writer(lock) == RW_LOCK_EX) {
890  ret = TRUE;
891  }
892  } else {
893  ut_error;
894  }
895 
896  return(ret);
897 }
898 
899 #ifdef UNIV_SYNC_DEBUG
900 /***************************************************************/
902 UNIV_INTERN
903 void
904 rw_lock_list_print_info(
905 /*====================*/
906  FILE* file)
907 {
908  rw_lock_t* lock;
909  ulint count = 0;
910  rw_lock_debug_t* info;
911 
912  mutex_enter(&rw_lock_list_mutex);
913 
914  fputs("-------------\n"
915  "RW-LATCH INFO\n"
916  "-------------\n", file);
917 
918  lock = UT_LIST_GET_FIRST(rw_lock_list);
919 
920  while (lock != NULL) {
921 
922  count++;
923 
924 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
925  mutex_enter(&(lock->mutex));
926 #endif
927  if (lock->lock_word != X_LOCK_DECR) {
928 
929  fprintf(file, "RW-LOCK: %p ", (void*) lock);
930 
931  if (rw_lock_get_waiters(lock)) {
932  fputs(" Waiters for the lock exist\n", file);
933  } else {
934  putc('\n', file);
935  }
936 
937  info = UT_LIST_GET_FIRST(lock->debug_list);
938  while (info != NULL) {
939  rw_lock_debug_print(info);
940  info = UT_LIST_GET_NEXT(list, info);
941  }
942  }
943 #ifndef INNODB_RW_LOCKS_USE_ATOMICS
944  mutex_exit(&(lock->mutex));
945 #endif
946 
947  lock = UT_LIST_GET_NEXT(list, lock);
948  }
949 
950  fprintf(file, "Total number of rw-locks %ld\n", count);
951  mutex_exit(&rw_lock_list_mutex);
952 }
953 
954 /***************************************************************/
956 UNIV_INTERN
957 void
958 rw_lock_print(
959 /*==========*/
960  rw_lock_t* lock)
961 {
962  rw_lock_debug_t* info;
963 
964  fprintf(stderr,
965  "-------------\n"
966  "RW-LATCH INFO\n"
967  "RW-LATCH: %p ", (void*) lock);
968 
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) {
978 
979  if (rw_lock_get_waiters(lock)) {
980  fputs(" Waiters for the lock exist\n", stderr);
981  } else {
982  putc('\n', stderr);
983  }
984 
985  info = UT_LIST_GET_FIRST(lock->debug_list);
986  while (info != NULL) {
987  rw_lock_debug_print(info);
988  info = UT_LIST_GET_NEXT(list, info);
989  }
990  }
991 }
992 
993 /*********************************************************************/
995 UNIV_INTERN
996 void
997 rw_lock_debug_print(
998 /*================*/
999  rw_lock_debug_t* info)
1000 {
1001  ulint rwt;
1002 
1003  rwt = info->lock_type;
1004 
1005  fprintf(stderr, "Locked: thread %lu file %s line %lu ",
1006  (ulong) os_thread_pf(info->thread_id), info->file_name,
1007  (ulong) info->line);
1008  if (rwt == RW_LOCK_SHARED) {
1009  fputs("S-LOCK", stderr);
1010  } else if (rwt == RW_LOCK_EX) {
1011  fputs("X-LOCK", stderr);
1012  } else if (rwt == RW_LOCK_WAIT_EX) {
1013  fputs("WAIT X-LOCK", stderr);
1014  } else {
1015  ut_error;
1016  }
1017  if (info->pass != 0) {
1018  fprintf(stderr, " pass value %lu", (ulong) info->pass);
1019  }
1020  putc('\n', stderr);
1021 }
1022 
1023 /***************************************************************/
1027 UNIV_INTERN
1028 ulint
1029 rw_lock_n_locked(void)
1030 /*==================*/
1031 {
1032  rw_lock_t* lock;
1033  ulint count = 0;
1034 
1035  mutex_enter(&rw_lock_list_mutex);
1036 
1037  lock = UT_LIST_GET_FIRST(rw_lock_list);
1038 
1039  while (lock != NULL) {
1040 
1041  if (lock->lock_word != X_LOCK_DECR) {
1042  count++;
1043  }
1044 
1045  lock = UT_LIST_GET_NEXT(list, lock);
1046  }
1047 
1048  mutex_exit(&rw_lock_list_mutex);
1049 
1050  return(count);
1051 }
1052 #endif /* UNIV_SYNC_DEBUG */