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