1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /******************************************************************//** |
21 | @file include/ib0mutex.h |
22 | Policy based mutexes. |
23 | |
24 | Created 2013-03-26 Sunny Bains. |
25 | ***********************************************************************/ |
26 | |
27 | #ifndef UNIV_INNOCHECKSUM |
28 | |
29 | #ifndef ib0mutex_h |
30 | #define ib0mutex_h |
31 | |
32 | #include "ut0ut.h" |
33 | #include "ut0rnd.h" |
34 | #include "os0event.h" |
35 | #include "sync0arr.h" |
36 | |
37 | /** OS mutex for tracking lock/unlock for debugging */ |
38 | template <template <typename> class Policy = NoPolicy> |
39 | struct OSTrackMutex { |
40 | |
41 | typedef Policy<OSTrackMutex> MutexPolicy; |
42 | |
43 | explicit OSTrackMutex(bool destroy_mutex_at_exit = true) |
44 | UNIV_NOTHROW |
45 | { |
46 | ut_d(m_freed = true); |
47 | ut_d(m_locked = false); |
48 | ut_d(m_destroy_at_exit = destroy_mutex_at_exit); |
49 | } |
50 | |
51 | ~OSTrackMutex() UNIV_NOTHROW |
52 | { |
53 | ut_ad(!m_destroy_at_exit || !m_locked); |
54 | } |
55 | |
56 | /** Initialise the mutex. */ |
57 | void init(latch_id_t, const char*, uint32_t) UNIV_NOTHROW |
58 | { |
59 | ut_ad(m_freed); |
60 | ut_ad(!m_locked); |
61 | |
62 | m_mutex.init(); |
63 | |
64 | ut_d(m_freed = false); |
65 | } |
66 | |
67 | /** Destroy the mutex */ |
68 | void destroy() UNIV_NOTHROW |
69 | { |
70 | ut_ad(!m_locked); |
71 | ut_ad(!m_freed); |
72 | |
73 | m_mutex.destroy(); |
74 | |
75 | ut_d(m_freed = true); |
76 | } |
77 | |
78 | /** Release the mutex. */ |
79 | void exit() UNIV_NOTHROW |
80 | { |
81 | ut_ad(m_locked); |
82 | ut_d(m_locked = false); |
83 | ut_ad(!m_freed); |
84 | |
85 | m_mutex.exit(); |
86 | } |
87 | |
88 | /** Acquire the mutex. */ |
89 | void enter(uint32_t, uint32_t, const char*, uint32_t) |
90 | UNIV_NOTHROW |
91 | { |
92 | ut_ad(!m_freed); |
93 | |
94 | m_mutex.enter(); |
95 | |
96 | ut_ad(!m_locked); |
97 | ut_d(m_locked = true); |
98 | } |
99 | |
100 | /** @return true if locking succeeded */ |
101 | bool try_lock() UNIV_NOTHROW |
102 | { |
103 | ut_ad(!m_freed); |
104 | |
105 | bool locked = m_mutex.try_lock(); |
106 | |
107 | if (locked) { |
108 | ut_ad(!m_locked); |
109 | ut_d(m_locked = locked); |
110 | } |
111 | |
112 | return(locked); |
113 | } |
114 | |
115 | /** @return non-const version of the policy */ |
116 | MutexPolicy& policy() |
117 | UNIV_NOTHROW |
118 | { |
119 | return(m_policy); |
120 | } |
121 | |
122 | /** @return the const version of the policy */ |
123 | const MutexPolicy& policy() const |
124 | UNIV_NOTHROW |
125 | { |
126 | return(m_policy); |
127 | } |
128 | |
129 | private: |
130 | #ifdef UNIV_DEBUG |
131 | /** true if the mutex has not be initialized */ |
132 | bool m_freed; |
133 | |
134 | /** true if the mutex has been locked. */ |
135 | bool m_locked; |
136 | |
137 | /** Do/Dont destroy mutex at exit */ |
138 | bool m_destroy_at_exit; |
139 | #endif /* UNIV_DEBUG */ |
140 | |
141 | /** OS Mutex instance */ |
142 | OSMutex m_mutex; |
143 | |
144 | /** Policy data */ |
145 | MutexPolicy m_policy; |
146 | }; |
147 | |
148 | |
149 | #ifdef HAVE_IB_LINUX_FUTEX |
150 | |
151 | #include <linux/futex.h> |
152 | #include <sys/syscall.h> |
153 | |
154 | /** Mutex implementation that used the Linux futex. */ |
155 | template <template <typename> class Policy = NoPolicy> |
156 | struct TTASFutexMutex { |
157 | |
158 | typedef Policy<TTASFutexMutex> MutexPolicy; |
159 | |
160 | TTASFutexMutex() UNIV_NOTHROW |
161 | : |
162 | m_lock_word(MUTEX_STATE_UNLOCKED) |
163 | { |
164 | /* Check that lock_word is aligned. */ |
165 | ut_ad(!((ulint) &m_lock_word % sizeof(ulint))); |
166 | } |
167 | |
168 | ~TTASFutexMutex() |
169 | { |
170 | ut_a(m_lock_word == MUTEX_STATE_UNLOCKED); |
171 | } |
172 | |
173 | /** Called when the mutex is "created". Note: Not from the constructor |
174 | but when the mutex is initialised. */ |
175 | void init(latch_id_t, const char*, uint32_t) UNIV_NOTHROW |
176 | { |
177 | ut_a(m_lock_word == MUTEX_STATE_UNLOCKED); |
178 | } |
179 | |
180 | /** Destroy the mutex. */ |
181 | void destroy() UNIV_NOTHROW |
182 | { |
183 | /* The destructor can be called at shutdown. */ |
184 | ut_a(m_lock_word == MUTEX_STATE_UNLOCKED); |
185 | } |
186 | |
187 | /** Acquire the mutex. |
188 | @param[in] max_spins max number of spins |
189 | @param[in] max_delay max delay per spin */ |
190 | void enter(uint32_t max_spins, uint32_t max_delay, |
191 | const char*, uint32_t) UNIV_NOTHROW |
192 | { |
193 | uint32_t n_spins, n_waits; |
194 | |
195 | for (n_spins= 0; n_spins < max_spins; n_spins++) { |
196 | if (try_lock()) { |
197 | m_policy.add(n_spins, 0); |
198 | return; |
199 | } |
200 | |
201 | ut_delay(max_delay); |
202 | } |
203 | |
204 | for (n_waits= 0;; n_waits++) { |
205 | if (my_atomic_fas32_explicit(&m_lock_word, |
206 | MUTEX_STATE_WAITERS, |
207 | MY_MEMORY_ORDER_ACQUIRE) |
208 | == MUTEX_STATE_UNLOCKED) { |
209 | break; |
210 | } |
211 | |
212 | syscall(SYS_futex, &m_lock_word, |
213 | FUTEX_WAIT_PRIVATE, MUTEX_STATE_WAITERS, |
214 | 0, 0, 0); |
215 | } |
216 | |
217 | m_policy.add(n_spins, n_waits); |
218 | } |
219 | |
220 | /** Release the mutex. */ |
221 | void exit() UNIV_NOTHROW |
222 | { |
223 | if (my_atomic_fas32_explicit(&m_lock_word, |
224 | MUTEX_STATE_UNLOCKED, |
225 | MY_MEMORY_ORDER_RELEASE) |
226 | == MUTEX_STATE_WAITERS) { |
227 | syscall(SYS_futex, &m_lock_word, FUTEX_WAKE_PRIVATE, |
228 | 1, 0, 0, 0); |
229 | } |
230 | } |
231 | |
232 | /** Try and lock the mutex. |
233 | @return true if successful */ |
234 | bool try_lock() UNIV_NOTHROW |
235 | { |
236 | int32 oldval = MUTEX_STATE_UNLOCKED; |
237 | return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval, |
238 | MUTEX_STATE_LOCKED, |
239 | MY_MEMORY_ORDER_ACQUIRE, |
240 | MY_MEMORY_ORDER_RELAXED)); |
241 | } |
242 | |
243 | /** @return non-const version of the policy */ |
244 | MutexPolicy& policy() UNIV_NOTHROW |
245 | { |
246 | return(m_policy); |
247 | } |
248 | |
249 | /** @return const version of the policy */ |
250 | const MutexPolicy& policy() const UNIV_NOTHROW |
251 | { |
252 | return(m_policy); |
253 | } |
254 | private: |
255 | /** Policy data */ |
256 | MutexPolicy m_policy; |
257 | |
258 | /** lock_word is the target of the atomic test-and-set instruction |
259 | when atomic operations are enabled. */ |
260 | int32 m_lock_word; |
261 | }; |
262 | |
263 | #endif /* HAVE_IB_LINUX_FUTEX */ |
264 | |
265 | template <template <typename> class Policy = NoPolicy> |
266 | struct TTASMutex { |
267 | |
268 | typedef Policy<TTASMutex> MutexPolicy; |
269 | |
270 | TTASMutex() UNIV_NOTHROW |
271 | : |
272 | m_lock_word(MUTEX_STATE_UNLOCKED) |
273 | { |
274 | /* Check that lock_word is aligned. */ |
275 | ut_ad(!((ulint) &m_lock_word % sizeof(ulint))); |
276 | } |
277 | |
278 | ~TTASMutex() |
279 | { |
280 | ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED); |
281 | } |
282 | |
283 | /** Called when the mutex is "created". Note: Not from the constructor |
284 | but when the mutex is initialised. */ |
285 | void init(latch_id_t) UNIV_NOTHROW |
286 | { |
287 | ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED); |
288 | } |
289 | |
290 | /** Destroy the mutex. */ |
291 | void destroy() UNIV_NOTHROW |
292 | { |
293 | /* The destructor can be called at shutdown. */ |
294 | ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED); |
295 | } |
296 | |
297 | /** Try and lock the mutex. |
298 | @return true on success */ |
299 | bool try_lock() UNIV_NOTHROW |
300 | { |
301 | int32 oldval = MUTEX_STATE_UNLOCKED; |
302 | return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval, |
303 | MUTEX_STATE_LOCKED, |
304 | MY_MEMORY_ORDER_ACQUIRE, |
305 | MY_MEMORY_ORDER_RELAXED)); |
306 | } |
307 | |
308 | /** Release the mutex. */ |
309 | void exit() UNIV_NOTHROW |
310 | { |
311 | ut_ad(m_lock_word == MUTEX_STATE_LOCKED); |
312 | my_atomic_store32_explicit(&m_lock_word, MUTEX_STATE_UNLOCKED, |
313 | MY_MEMORY_ORDER_RELEASE); |
314 | } |
315 | |
316 | /** Acquire the mutex. |
317 | @param max_spins max number of spins |
318 | @param max_delay max delay per spin */ |
319 | void enter(uint32_t max_spins, uint32_t max_delay, |
320 | const char*, uint32_t) UNIV_NOTHROW |
321 | { |
322 | const uint32_t step = max_spins; |
323 | uint32_t n_spins = 0; |
324 | |
325 | while (!try_lock()) { |
326 | ut_delay(max_delay); |
327 | if (++n_spins == max_spins) { |
328 | os_thread_yield(); |
329 | max_spins+= step; |
330 | } |
331 | } |
332 | |
333 | m_policy.add(n_spins, 0); |
334 | } |
335 | |
336 | /** @return non-const version of the policy */ |
337 | MutexPolicy& policy() UNIV_NOTHROW |
338 | { |
339 | return(m_policy); |
340 | } |
341 | |
342 | /** @return const version of the policy */ |
343 | const MutexPolicy& policy() const UNIV_NOTHROW |
344 | { |
345 | return(m_policy); |
346 | } |
347 | |
348 | private: |
349 | // Disable copying |
350 | TTASMutex(const TTASMutex&); |
351 | TTASMutex& operator=(const TTASMutex&); |
352 | |
353 | /** Policy data */ |
354 | MutexPolicy m_policy; |
355 | |
356 | /** lock_word is the target of the atomic test-and-set instruction |
357 | when atomic operations are enabled. */ |
358 | int32 m_lock_word; |
359 | }; |
360 | |
361 | template <template <typename> class Policy = NoPolicy> |
362 | struct TTASEventMutex { |
363 | |
364 | typedef Policy<TTASEventMutex> MutexPolicy; |
365 | |
366 | TTASEventMutex() |
367 | UNIV_NOTHROW |
368 | : |
369 | m_lock_word(MUTEX_STATE_UNLOCKED), |
370 | m_event() |
371 | { |
372 | /* Check that lock_word is aligned. */ |
373 | ut_ad(!((ulint) &m_lock_word % sizeof(ulint))); |
374 | } |
375 | |
376 | ~TTASEventMutex() |
377 | UNIV_NOTHROW |
378 | { |
379 | ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED); |
380 | } |
381 | |
382 | /** Called when the mutex is "created". Note: Not from the constructor |
383 | but when the mutex is initialised. |
384 | @param[in] id Mutex ID */ |
385 | void init(latch_id_t id, const char*, uint32_t) UNIV_NOTHROW |
386 | { |
387 | ut_a(m_event == 0); |
388 | ut_a(m_lock_word == MUTEX_STATE_UNLOCKED); |
389 | |
390 | m_event = os_event_create(sync_latch_get_name(id)); |
391 | } |
392 | |
393 | /** This is the real desctructor. This mutex can be created in BSS and |
394 | its desctructor will be called on exit(). We can't call |
395 | os_event_destroy() at that stage. */ |
396 | void destroy() |
397 | UNIV_NOTHROW |
398 | { |
399 | ut_ad(m_lock_word == MUTEX_STATE_UNLOCKED); |
400 | |
401 | /* We have to free the event before InnoDB shuts down. */ |
402 | os_event_destroy(m_event); |
403 | m_event = 0; |
404 | } |
405 | |
406 | /** Try and lock the mutex. Note: POSIX returns 0 on success. |
407 | @return true on success */ |
408 | bool try_lock() |
409 | UNIV_NOTHROW |
410 | { |
411 | int32 oldval = MUTEX_STATE_UNLOCKED; |
412 | return(my_atomic_cas32_strong_explicit(&m_lock_word, &oldval, |
413 | MUTEX_STATE_LOCKED, |
414 | MY_MEMORY_ORDER_ACQUIRE, |
415 | MY_MEMORY_ORDER_RELAXED)); |
416 | } |
417 | |
418 | /** Release the mutex. */ |
419 | void exit() |
420 | UNIV_NOTHROW |
421 | { |
422 | if (my_atomic_fas32_explicit(&m_lock_word, |
423 | MUTEX_STATE_UNLOCKED, |
424 | MY_MEMORY_ORDER_RELEASE) |
425 | == MUTEX_STATE_WAITERS) { |
426 | os_event_set(m_event); |
427 | sync_array_object_signalled(); |
428 | } |
429 | } |
430 | |
431 | /** Acquire the mutex. |
432 | @param[in] max_spins max number of spins |
433 | @param[in] max_delay max delay per spin |
434 | @param[in] filename from where called |
435 | @param[in] line within filename */ |
436 | void enter( |
437 | uint32_t max_spins, |
438 | uint32_t max_delay, |
439 | const char* filename, |
440 | uint32_t line) |
441 | UNIV_NOTHROW |
442 | { |
443 | uint32_t n_spins = 0; |
444 | uint32_t n_waits = 0; |
445 | const uint32_t step = max_spins; |
446 | |
447 | while (!try_lock()) { |
448 | if (n_spins++ == max_spins) { |
449 | max_spins += step; |
450 | n_waits++; |
451 | os_thread_yield(); |
452 | |
453 | sync_cell_t* cell; |
454 | sync_array_t *sync_arr = sync_array_get_and_reserve_cell( |
455 | this, |
456 | (m_policy.get_id() == LATCH_ID_BUF_BLOCK_MUTEX |
457 | || m_policy.get_id() == LATCH_ID_BUF_POOL_ZIP) |
458 | ? SYNC_BUF_BLOCK |
459 | : SYNC_MUTEX, |
460 | filename, line, &cell); |
461 | |
462 | int32 oldval = MUTEX_STATE_LOCKED; |
463 | my_atomic_cas32_strong_explicit(&m_lock_word, &oldval, |
464 | MUTEX_STATE_WAITERS, |
465 | MY_MEMORY_ORDER_RELAXED, |
466 | MY_MEMORY_ORDER_RELAXED); |
467 | |
468 | if (oldval == MUTEX_STATE_UNLOCKED) { |
469 | sync_array_free_cell(sync_arr, cell); |
470 | } else { |
471 | sync_array_wait_event(sync_arr, cell); |
472 | } |
473 | } else { |
474 | ut_delay(max_delay); |
475 | } |
476 | } |
477 | |
478 | m_policy.add(n_spins, n_waits); |
479 | } |
480 | |
481 | /** @return the lock state. */ |
482 | int32 state() const |
483 | UNIV_NOTHROW |
484 | { |
485 | return(my_atomic_load32_explicit(const_cast<int32*> |
486 | (&m_lock_word), |
487 | MY_MEMORY_ORDER_RELAXED)); |
488 | } |
489 | |
490 | /** The event that the mutex will wait in sync0arr.cc |
491 | @return even instance */ |
492 | os_event_t event() |
493 | UNIV_NOTHROW |
494 | { |
495 | return(m_event); |
496 | } |
497 | |
498 | /** @return non-const version of the policy */ |
499 | MutexPolicy& policy() |
500 | UNIV_NOTHROW |
501 | { |
502 | return(m_policy); |
503 | } |
504 | |
505 | /** @return const version of the policy */ |
506 | const MutexPolicy& policy() const |
507 | UNIV_NOTHROW |
508 | { |
509 | return(m_policy); |
510 | } |
511 | |
512 | private: |
513 | /** Disable copying */ |
514 | TTASEventMutex(const TTASEventMutex&); |
515 | TTASEventMutex& operator=(const TTASEventMutex&); |
516 | |
517 | /** lock_word is the target of the atomic test-and-set instruction |
518 | when atomic operations are enabled. */ |
519 | int32 m_lock_word; |
520 | |
521 | /** Used by sync0arr.cc for the wait queue */ |
522 | os_event_t m_event; |
523 | |
524 | /** Policy data */ |
525 | MutexPolicy m_policy; |
526 | }; |
527 | |
528 | /** Mutex interface for all policy mutexes. This class handles the interfacing |
529 | with the Performance Schema instrumentation. */ |
530 | template <typename MutexImpl> |
531 | struct PolicyMutex |
532 | { |
533 | typedef MutexImpl MutexType; |
534 | typedef typename MutexImpl::MutexPolicy Policy; |
535 | |
536 | PolicyMutex() UNIV_NOTHROW : m_impl() |
537 | { |
538 | #ifdef UNIV_PFS_MUTEX |
539 | m_ptr = 0; |
540 | #endif /* UNIV_PFS_MUTEX */ |
541 | } |
542 | |
543 | ~PolicyMutex() { } |
544 | |
545 | /** @return non-const version of the policy */ |
546 | Policy& policy() UNIV_NOTHROW |
547 | { |
548 | return(m_impl.policy()); |
549 | } |
550 | |
551 | /** @return const version of the policy */ |
552 | const Policy& policy() const UNIV_NOTHROW |
553 | { |
554 | return(m_impl.policy()); |
555 | } |
556 | |
557 | /** Release the mutex. */ |
558 | void exit() UNIV_NOTHROW |
559 | { |
560 | #ifdef UNIV_PFS_MUTEX |
561 | pfs_exit(); |
562 | #endif /* UNIV_PFS_MUTEX */ |
563 | |
564 | policy().release(m_impl); |
565 | |
566 | m_impl.exit(); |
567 | } |
568 | |
569 | /** Acquire the mutex. |
570 | @param n_spins max number of spins |
571 | @param n_delay max delay per spin |
572 | @param name filename where locked |
573 | @param line line number where locked */ |
574 | void enter( |
575 | uint32_t n_spins, |
576 | uint32_t n_delay, |
577 | const char* name, |
578 | uint32_t line) UNIV_NOTHROW |
579 | { |
580 | #ifdef UNIV_PFS_MUTEX |
581 | /* Note: locker is really an alias for state. That's why |
582 | it has to be in the same scope during pfs_end(). */ |
583 | |
584 | PSI_mutex_locker_state state; |
585 | PSI_mutex_locker* locker; |
586 | |
587 | locker = pfs_begin_lock(&state, name, line); |
588 | #endif /* UNIV_PFS_MUTEX */ |
589 | |
590 | policy().enter(m_impl, name, line); |
591 | |
592 | m_impl.enter(n_spins, n_delay, name, line); |
593 | |
594 | policy().locked(m_impl, name, line); |
595 | #ifdef UNIV_PFS_MUTEX |
596 | pfs_end(locker, 0); |
597 | #endif /* UNIV_PFS_MUTEX */ |
598 | } |
599 | |
600 | /** Try and lock the mutex, return 0 on SUCCESS and 1 otherwise. |
601 | @param name filename where locked |
602 | @param line line number where locked */ |
603 | int trylock(const char* name, uint32_t line) UNIV_NOTHROW |
604 | { |
605 | #ifdef UNIV_PFS_MUTEX |
606 | /* Note: locker is really an alias for state. That's why |
607 | it has to be in the same scope during pfs_end(). */ |
608 | |
609 | PSI_mutex_locker_state state; |
610 | PSI_mutex_locker* locker; |
611 | |
612 | locker = pfs_begin_trylock(&state, name, line); |
613 | #endif /* UNIV_PFS_MUTEX */ |
614 | |
615 | /* There is a subtlety here, we check the mutex ordering |
616 | after locking here. This is only done to avoid add and |
617 | then remove if the trylock was unsuccesful. */ |
618 | |
619 | int ret = m_impl.try_lock() ? 0 : 1; |
620 | |
621 | if (ret == 0) { |
622 | |
623 | policy().enter(m_impl, name, line); |
624 | |
625 | policy().locked(m_impl, name, line); |
626 | } |
627 | |
628 | #ifdef UNIV_PFS_MUTEX |
629 | pfs_end(locker, 0); |
630 | #endif /* UNIV_PFS_MUTEX */ |
631 | |
632 | return(ret); |
633 | } |
634 | |
635 | #ifdef UNIV_DEBUG |
636 | /** @return true if the thread owns the mutex. */ |
637 | bool is_owned() const UNIV_NOTHROW |
638 | { |
639 | return(policy().is_owned()); |
640 | } |
641 | #endif /* UNIV_DEBUG */ |
642 | |
643 | /** |
644 | Initialise the mutex. |
645 | |
646 | @param[in] id Mutex ID |
647 | @param[in] filename file where created |
648 | @param[in] line line number in file where created */ |
649 | void init( |
650 | latch_id_t id, |
651 | const char* filename, |
652 | uint32_t line) |
653 | UNIV_NOTHROW |
654 | { |
655 | #ifdef UNIV_PFS_MUTEX |
656 | pfs_add(sync_latch_get_pfs_key(id)); |
657 | #endif /* UNIV_PFS_MUTEX */ |
658 | |
659 | m_impl.init(id, filename, line); |
660 | policy().init(m_impl, id, filename, line); |
661 | } |
662 | |
663 | /** Free resources (if any) */ |
664 | void destroy() UNIV_NOTHROW |
665 | { |
666 | #ifdef UNIV_PFS_MUTEX |
667 | pfs_del(); |
668 | #endif /* UNIV_PFS_MUTEX */ |
669 | m_impl.destroy(); |
670 | policy().destroy(); |
671 | } |
672 | |
673 | /** Required for os_event_t */ |
674 | operator sys_mutex_t*() UNIV_NOTHROW |
675 | { |
676 | return(m_impl.operator sys_mutex_t*()); |
677 | } |
678 | |
679 | #ifdef UNIV_PFS_MUTEX |
680 | /** Performance schema monitoring - register mutex with PFS. |
681 | |
682 | Note: This is public only because we want to get around an issue |
683 | with registering a subset of buffer pool pages with PFS when |
684 | PFS_GROUP_BUFFER_SYNC is defined. Therefore this has to then |
685 | be called by external code (see buf0buf.cc). |
686 | |
687 | @param key - Performance Schema key. */ |
688 | void pfs_add(mysql_pfs_key_t key) UNIV_NOTHROW |
689 | { |
690 | ut_ad(m_ptr == 0); |
691 | m_ptr = PSI_MUTEX_CALL(init_mutex)(key, this); |
692 | } |
693 | |
694 | private: |
695 | |
696 | /** Performance schema monitoring. |
697 | @param state - PFS locker state |
698 | @param name - file name where locked |
699 | @param line - line number in file where locked */ |
700 | PSI_mutex_locker* pfs_begin_lock( |
701 | PSI_mutex_locker_state* state, |
702 | const char* name, |
703 | uint32_t line) UNIV_NOTHROW |
704 | { |
705 | if (m_ptr != 0) { |
706 | return(PSI_MUTEX_CALL(start_mutex_wait)( |
707 | state, m_ptr, |
708 | PSI_MUTEX_LOCK, name, (uint) line)); |
709 | } |
710 | |
711 | return(0); |
712 | } |
713 | |
714 | /** Performance schema monitoring. |
715 | @param state - PFS locker state |
716 | @param name - file name where locked |
717 | @param line - line number in file where locked */ |
718 | PSI_mutex_locker* pfs_begin_trylock( |
719 | PSI_mutex_locker_state* state, |
720 | const char* name, |
721 | uint32_t line) UNIV_NOTHROW |
722 | { |
723 | if (m_ptr != 0) { |
724 | return(PSI_MUTEX_CALL(start_mutex_wait)( |
725 | state, m_ptr, |
726 | PSI_MUTEX_TRYLOCK, name, (uint) line)); |
727 | } |
728 | |
729 | return(0); |
730 | } |
731 | |
732 | /** Performance schema monitoring |
733 | @param locker - PFS identifier |
734 | @param ret - 0 for success and 1 for failure */ |
735 | void pfs_end(PSI_mutex_locker* locker, int ret) UNIV_NOTHROW |
736 | { |
737 | if (locker != 0) { |
738 | PSI_MUTEX_CALL(end_mutex_wait)(locker, ret); |
739 | } |
740 | } |
741 | |
742 | /** Performance schema monitoring - register mutex release */ |
743 | void pfs_exit() |
744 | { |
745 | if (m_ptr != 0) { |
746 | PSI_MUTEX_CALL(unlock_mutex)(m_ptr); |
747 | } |
748 | } |
749 | |
750 | /** Performance schema monitoring - deregister */ |
751 | void pfs_del() |
752 | { |
753 | if (m_ptr != 0) { |
754 | PSI_MUTEX_CALL(destroy_mutex)(m_ptr); |
755 | m_ptr = 0; |
756 | } |
757 | } |
758 | #endif /* UNIV_PFS_MUTEX */ |
759 | |
760 | private: |
761 | /** The mutex implementation */ |
762 | MutexImpl m_impl; |
763 | |
764 | #ifdef UNIV_PFS_MUTEX |
765 | /** The performance schema instrumentation hook. */ |
766 | PSI_mutex* m_ptr; |
767 | #endif /* UNIV_PFS_MUTEX */ |
768 | |
769 | }; |
770 | |
771 | #endif /* ib0mutex_h */ |
772 | |
773 | #endif /* !UNIV_INNOCHECKSUM */ |
774 | |