// mutex standard header
#ifndef _MUTEX_
#define _MUTEX_

#if defined(__ghs)
 #include <yvals.h>
 #if !_HAS_CPP11
  #error This file requires ISO C++11 support in the compiler
 #endif /* _HAS_CPP11 */
#endif /* __ghs */

#include <thread>
#include <chrono>
#include <functional>
#include <system_error>

 #if defined(__ghs)
  #pragma ghs start_cxx_lib_header
  #pragma ghs startdata
  #if defined(__ghs_max_pack_value)
   #pragma pack (push, __ghs_max_pack_value)
  #endif /* defined(__ghs_max_pack_value) */
 #endif /* defined(__ghs) */

 #if _CLANG
  #define _CONST_FUNY

 #else /* _CLANG */
  #define _CONST_FUNY	_CONST_FUN
 #endif /* _CLANG */

 #if defined(__ghs) && _HAS_CPP17
  #define __cpp_lib_scoped_lock 201703L
 #endif /* defined(__ghs) && _HAS_CPP17 */

_STD_BEGIN
	// MUTUAL EXCLUSION
class _Mutex_base
	{	// base class for all mutex types
public:
#if !defined(__ghs)
	// Can't be constexpr - mutex init is non-trivial
	_CONST_FUNY
#endif /* !defined(__ghs) */
		    _Mutex_base(int _Flags = 0) _NOEXCEPT
		{	// construct with _Flags
		_Mtx_initX(&_Mymtx(), _Flags | _Mtx_try);
		}

	~_Mutex_base() _NOEXCEPT
		{	// clean up
		_Mtx_destroy(_THR_ADDR _Mymtx());
		}

	_Mutex_base(const _Mutex_base&) = delete;
	_Mutex_base& operator=(const _Mutex_base&) = delete;

	void lock()
		{	// lock the mutex
		_Mtx_lockX(_THR_ADDR _Mymtx());
		}

	bool try_lock()
		{	// try to lock the mutex
		return (_Mtx_trylockX(_THR_ADDR _Mymtx()) == _Thrd_success);
		}

	void unlock()
		{	// unlock the mutex
		_Mtx_unlockX(_THR_ADDR _Mymtx());
		}

	typedef _Mtx_t native_handle_type;

	native_handle_type native_handle()
		{	// return mutex handle
		return (_Mtx);
		}

private:
	friend class condition_variable;
	friend class condition_variable_any;
#if defined(__ghs)
	friend class _Timed_mutex_base;
	template<class _Ty> friend class _Associated_state;
#endif

	_Mtx_t& _Mymtx() _NOEXCEPT
		{	// get pointer to _Mtx_internal_imp_t
		return (_Mtx);
		}

	_Mtx_t _Mtx = 0;
	};

class mutex
	: public _Mutex_base
	{	// class for mutual exclusion
public:
#if !defined(__ghs)
	// Can't be constexpr - mutex init is non-trivial
	_CONST_FUNY
#endif /* defined(__ghs) */
	            mutex(int _Flags = 0) _NOEXCEPT
		: _Mutex_base(_Flags)
		{	// construct
		}

	mutex(const mutex&) = delete;
	mutex& operator=(const mutex&) = delete;
	};

class recursive_mutex
	: public _Mutex_base
	{	// class for recursive mutual exclusion
public:
#if !defined(__ghs)
	// Can't be constexpr - mutex init is non-trivial
	_CONST_FUN
#endif /* defined(__ghs) */
		   recursive_mutex()
		: _Mutex_base(_Mtx_recursive)
		{	// default construct
		}

	bool try_lock() _NOEXCEPT
		{	// try to lock the mutex
		return (_Mutex_base::try_lock());
		}

	recursive_mutex(const recursive_mutex&) = delete;
	recursive_mutex& operator=(const recursive_mutex&) = delete;
	};

	// LOCK PROPERTIES
struct adopt_lock_t
	{	// indicates adopt lock
	explicit adopt_lock_t() = default;
	};

struct defer_lock_t
	{	// indicates defer lock
	explicit defer_lock_t() = default;
	};

struct try_to_lock_t
	{	// indicates try to lock
	explicit try_to_lock_t() = default;
	};
_INLINE_VAR _CONST_DATA adopt_lock_t adopt_lock{};
_INLINE_VAR _CONST_DATA defer_lock_t defer_lock{};
_INLINE_VAR _CONST_DATA try_to_lock_t try_to_lock{};
	// LOCKS
		// TEMPLATE CLASS lock_guard
template<size_t _Tuple_no,
	class... _Mutexes>
	class _Unlock_tuple
	{	// unlock first element of a tuple of mutexes
public:
	void operator()(tuple<_Mutexes...>& _Mymutexes)
		{	// unlock first element
		get<_Tuple_no - 1>(_Mymutexes).unlock();
		_Unlock_tuple<_Tuple_no - 1, _Mutexes...>()(_Mymutexes);
		}
	};

template<class... _Mutexes>
	class _Unlock_tuple<0, _Mutexes...>
	{	// stop at element zero
public:
	void operator()(tuple<_Mutexes...>& _Mymutexes)
		{	// do nothing
		}
	};

template<class... _Mutexes>
	class lock_guard
	{	// class with destructor that unlocks zero or more mutexes
public:
//	typedef _Mutex mutex_type;	// one mutex only

	explicit lock_guard(_Mutexes&... _Mtx)
		: _Mymutexes(tie(_Mtx...))
		{	// construct and lock
		if (0 < sizeof...(_Mutexes))
			lock(_Mtx...);
		}

	lock_guard(_Mutexes&... _Mtx, adopt_lock_t)
		: _Mymutexes(tie(_Mtx...))
		{	// construct but don't lock
		}

	~lock_guard() _NOEXCEPT
		{	// unlock
		if (0 < sizeof...(_Mutexes))
			_Unlock_tuple<sizeof...(_Mutexes), _Mutexes&...>()(_Mymutexes);
		}

	lock_guard(const lock_guard&) = delete;
	lock_guard& operator=(const lock_guard&) = delete;
private:
	tuple<_Mutexes&...> _Mymutexes;
	};

template<class _Mutex>
	class lock_guard<_Mutex>
	{	// class with destructor that unlocks a single mutex
public:
	typedef _Mutex mutex_type;

	explicit lock_guard(_Mutex& _Mtx)
		: _MyMtx(_Mtx)
		{	// construct and lock
		_Mtx.lock();
		}

	lock_guard(_Mutex& _Mtx, adopt_lock_t)
		: _MyMtx(_Mtx)
		{	// construct but don't lock
		}

	~lock_guard() _NOEXCEPT
		{	// unlock
		_MyMtx.unlock();
		}

	lock_guard(const lock_guard&) = delete;
	lock_guard& operator=(const lock_guard&) = delete;
private:
	_Mutex& _MyMtx;
	};

template<class _Mutex>
	class unique_lock
	{	// whizzy class with destructor that unlocks mutex
public:
	typedef unique_lock<_Mutex> _Myt;
	typedef _Mutex mutex_type;

	// CONSTRUCT, ASSIGN, AND DESTROY
	unique_lock() _NOEXCEPT
		: _Pmtx(0), _Owns(false)
		{	// default construct
		}

	explicit unique_lock(_Mutex& _Mtx)
		: _Pmtx(&_Mtx), _Owns(false)
		{	// construct and lock
		_Pmtx->lock();
		_Owns = true;
		}

	unique_lock(_Mutex& _Mtx, adopt_lock_t)
		: _Pmtx(&_Mtx), _Owns(true)
		{	// construct and assume already locked
		}

	unique_lock(_Mutex& _Mtx, defer_lock_t) _NOEXCEPT
		: _Pmtx(&_Mtx), _Owns(false)
		{	// construct but don't lock
		}

	unique_lock(_Mutex& _Mtx, try_to_lock_t)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock())
		{	// construct and try to lock
		}

	template<class _Rep,
		class _Period>
		unique_lock(_Mutex& _Mtx,
			const chrono::duration<_Rep, _Period>& _Rel_time)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_for(_Rel_time))
		{	// construct and lock with timeout
		}

	template<class _Clock,
		class _Duration>
		unique_lock(_Mutex& _Mtx,
			const chrono::time_point<_Clock, _Duration>& _Abs_time)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_until(_Abs_time))
		{	// construct and lock with timeout
		}

#if !defined(__ghs)
	unique_lock(_Mutex& _Mtx, const xtime *_Abs_time)
		: _Pmtx(&_Mtx), _Owns(false)
		{	// try to lock until _Abs_time
		_Owns = _Pmtx->try_lock_until(_Abs_time);
		}
#endif /* !defined(__ghs) */

	unique_lock(unique_lock&& _Other) _NOEXCEPT
		: _Pmtx(_Other._Pmtx), _Owns(_Other._Owns)
		{	// destructive copy
		_Other._Pmtx = 0;
		_Other._Owns = false;
		}

	unique_lock& operator=(unique_lock&& _Other)
		{	// destructive copy
		if (this != &_Other)
			{	// different, move contents
			if (_Owns)
				_Pmtx->unlock();
			_Pmtx = _Other._Pmtx;
			_Owns = _Other._Owns;
			_Other._Pmtx = 0;
			_Other._Owns = false;
			}
		return (*this);
		}

	~unique_lock() _NOEXCEPT
		{	// clean up
		if (_Owns)
			_Pmtx->unlock();
		}

	unique_lock(const unique_lock&) = delete;
	unique_lock& operator=(const unique_lock&) = delete;

	// LOCK AND UNLOCK
	void lock()
		{	// lock the mutex
		_Validate();
		_Pmtx->lock();
		_Owns = true;
		}

	bool try_lock()
		{	// try to lock the mutex
		_Validate();
		_Owns = _Pmtx->try_lock();
		return (_Owns);
		}

	template<class _Rep,
		class _Period>
		bool try_lock_for(const chrono::duration<_Rep, _Period>& _Rel_time)
		{	// try to lock mutex for _Rel_time
		_Validate();
		_Owns = _Pmtx->try_lock_for(_Rel_time);
		return (_Owns);
		}

	template<class _Clock,
		class _Duration>
		bool try_lock_until(
			const chrono::time_point<_Clock, _Duration>& _Abs_time)
		{	// try to lock mutex until _Abs_time
		_Validate();
		_Owns = _Pmtx->try_lock_until(_Abs_time);
		return (_Owns);
		}

#if !defined(__ghs)
	bool try_lock_until(const xtime *_Abs_time)
		{	// try to lock the mutex until _Abs_time
		_Validate();
		_Owns = _Pmtx->try_lock_until(_Abs_time);
		return (_Owns);
		}
#endif /* !defined(__ghs) */

	void unlock()
		{	// try to unlock the mutex
#if defined(__ghs)
		_Validate(/*_Should_already_own=*/true);
#else
		_Validate();
#endif /* defined(__ghs) */
		_Pmtx->unlock();
		_Owns = false;
		}

	// MUTATE
	void swap(unique_lock& _Other) _NOEXCEPT
		{	// swap with _Other
		_STD swap(_Pmtx, _Other._Pmtx);
		_STD swap(_Owns, _Other._Owns);
		}

	_Mutex *release() _NOEXCEPT
		{	// disconnect
		_Mutex *_Res = _Pmtx;
		_Pmtx = 0;
		_Owns = false;
		return (_Res);
		}

	// OBSERVE
	bool owns_lock() const _NOEXCEPT
		{	// return true if this object owns the lock
		return (_Owns);
		}

	_EXP_OP operator bool() const _NOEXCEPT
		{	// return true if this object owns the lock
		return (_Owns);
		}

	_Mutex *mutex() const _NOEXCEPT
		{	// return pointer to managed mutex
		return (_Pmtx);
		}

private:
	_Mutex *_Pmtx;
	bool _Owns;

#if defined(__ghs)
	void _Validate(bool _Should_already_own = false) const
#else
	void _Validate() const
#endif /* defined(__ghs) */
		{	// check if the mutex can be locked
#if defined(__ghs)
		if (!_Pmtx || (!_Owns && _Should_already_own))
#else
		if (!_Pmtx)
#endif /* defined(__ghs) */
			_THROW_NCEE(system_error,
				_STD make_error_code(errc::operation_not_permitted));
#if defined(__ghs)
		else if (_Owns != _Should_already_own)
			_THROW_NCEE(system_error,
				_STD make_error_code(errc::resource_deadlock_would_occur));
#endif /* defined(__ghs) */
		}
	};

	// SWAP
template<class _Mutex>
	void swap(unique_lock<_Mutex>& _Left,
		unique_lock<_Mutex>& _Right) _NOEXCEPT
	{	// swap _Left and _Right
	_Left.swap(_Right);
	}

	// MULTIPLE LOCKS
template<class _Lock0> inline
	int _Try_lock(_Lock0& _Lk0)
	{	// try to lock one mutex
	if (!_Lk0.try_lock())
		return (0);
	else
		return (-1);
	}

template<class _Lock0,
	class... _LockN>
	int try_lock(_Lock0&, _LockN&...);

template<class _Lock0,
	class _Lock1,
	class... _LockN> inline
	int _Try_lock(_Lock0& _Lk0, _Lock1& _Lk1, _LockN&... _LkN)
	{	// try to lock n-1 mutexes
	int _Res;
	if (!_Lk0.try_lock())
		return (0);
	_TRY_BEGIN
		// handle exceptions from tail lock
		if ((_Res = try_lock(_Lk1, _LkN...)) != -1)
			{	// tail lock failed
			_Lk0.unlock();
			++_Res;
			}
	_CATCH_ALL
		// tail lock threw exception
		_Lk0.unlock();
 #if defined(__ghs)
		_RERAISE;
 #else
	        throw;
 #endif
	_CATCH_END
	return (_Res);
	}

template<class _Lock0,
	class... _LockN> inline
	int try_lock(_Lock0& _Lk0, _LockN&... _LkN)
	{	// try to lock n-1 mutexes
	return (_Try_lock(_Lk0, _LkN...));
	}

#if defined(__ghs)
// If std::lock is ever changed so that it can acquire mutexes in a different order, 
// then std::scoped_lock may need to be updated so that it releases them in the reverse order.
#endif
template<class _Lock0,
	class _Lock1,
	class... _LockN> inline
	void lock(_Lock0& _Lk0, _Lock1& _Lk1, _LockN&... _LkN)
	{	// lock N mutexes
	int _Res = 0;
	while (_Res != -1)
		_Res = _Try_lock(_Lk0, _Lk1, _LkN...);
	}

	// CALL ONCE
class _Once_pad
	{	// base class for call once
public:
	virtual void _Call() const = 0;
	};

template<class _Target>
	class _Once_target
		: public _Once_pad
	{	// template class for call once
public:
	_Once_target(_Target& _Tgt)
		: _MyTgt(&_Tgt)
		{	// construct from target
		}

	void _Call() const
		{	// do it
		(*_MyTgt)();
		}

private:
	_Target *_MyTgt;
	};

_EXTERN_C
void _Do_call(void *_Tgt);
_END_EXTERN_C

	// STRUCT once_flag
struct once_flag
	{	// opaque data structure for call_once()
	_CONST_FUNY once_flag() _NOEXCEPT
 #if !defined(__ghs)
		: _Opaque(0)
 #endif /* defined(__ghs) */		
		{	// default construct
		}

	once_flag(const once_flag&) = delete;
	once_flag& operator=(const once_flag&) = delete;
#if defined(__ghs)
	_Once_flag_cpp _Flag;
#else
	void *_Opaque;
#endif /* defined(__ghs) */
	};

	// TEMPLATE FUNCTION call_once
typedef int (*_Lambda_fp_t)(void *, void *, void **);
#if defined(__ghs)
int _Execute_once_ghs(
        _Once_flag_cpp *cntrl, _Lambda_fp_t _Lambda_fp, void *_Pv) _NOEXCEPT;
#else
int _Execute_once(
	once_flag& _Flag, _Lambda_fp_t _Lambda_fp, void *_Pv) _NOEXCEPT;
#endif /* defined(__ghs) */

template<class _Tuple,
	size_t... _Ix> inline
	void _Invoke_once(_Tuple& _Tup, integer_sequence<size_t, _Ix...>)
	{	// unpack a tuple for call_once()
	_STD invoke(_STD get<_Ix>(_STD move(_Tup))...);
	}

template<class _Tuple,
	class _Seq
 #if !defined(__ghs) || _HAS_EXCEPTIONS
	,size_t _Idx
 #endif /* !defined(__ghs) || _HAS_EXCEPTIONS */
	> inline
	int _Callback_once(void *, void *_Pv, void **)
	{	// adapt call_once() to callback API
	_Tuple *_Ptup = static_cast<_Tuple *>(_Pv);

	_TRY_BEGIN
		_Invoke_once(*_Ptup, _Seq());
	_CATCH_ALL
 #if defined(__ghs) && !_HAS_EXCEPTIONS
		// Disable this code when exceptions are disabled.  Even though
		// this is within an if (0) block due to the _CATCH_ALL, we
		// still cannot reference std::current_exception, which won't
		// exist without _HAS_EXCEPTIONS
 #else
		auto& _Ref = _STD get<_Idx>(*_Ptup);
		_Ref = _XSTD current_exception();
		return (0);
 #endif /* defined(__ghs) && !_HAS_EXCEPTIONS */
	_CATCH_END

	return (1);
	}

template<class _Fn,
	class... _Types> inline
	void (call_once)(once_flag& _Flag, _Fn&& _Fx, _Types&&... _Args)
	{	// call _Fx(_Args...) once
 #if defined(__ghs) && !_HAS_EXCEPTIONS
	typedef tuple<_Fn&&, _Types&&...> _Tuple;
 #else
	typedef tuple<_Fn&&, _Types&&..., _XSTD exception_ptr&> _Tuple;
 #endif /* defined(__ghs) && !_HAS_EXCEPTIONS */
	typedef make_integer_sequence<size_t, 1 + sizeof...(_Types)> _Seq;

 #if !defined(__ghs) || _HAS_EXCEPTIONS
	_XSTD exception_ptr _Exc;
 #endif /* !defined(__ghs) || _HAS_EXCEPTIONS */
	_Tuple _Tup(_STD forward<_Fn>(_Fx),
		_STD forward<_Types>(_Args)...
 #if !defined(__ghs) || _HAS_EXCEPTIONS
						,_Exc
 #endif /* !defined(__ghs) || _HAS_EXCEPTIONS */
						     );

	_Lambda_fp_t _Fp = &_Callback_once<_Tuple, _Seq
 #if !defined(__ghs) || _HAS_EXCEPTIONS
							, 1 + sizeof...(_Types)
 #endif /* !defined(__ghs) || _HAS_EXCEPTIONS */
									       >;
 #if defined(__ghs)
	if (_Execute_once_ghs(&_Flag._Flag, _Fp, _STD addressof(_Tup)) != 0)
 #else
	if (_Execute_once(_Flag, _Fp, _STD addressof(_Tup)) != 0)
 #endif /* defined(__ghs) */
		return;

 #if !defined(__ghs) || _HAS_EXCEPTIONS
	if (_Exc)
		_XSTD rethrow_exception(_Exc);
 #endif /* !defined(__ghs) || _HAS_EXCEPTIONS */
	}

enum class cv_status {	// names for wait returns
	no_timeout,
	timeout
	};

typedef cv_status _Cv_status;

 #if 0 < __GNUC__	/* compiler test */
inline bool operator==(cv_status _Left, _Cv_status _Right)
	{	// compare cv_status with _Cv_status for equality
	return ((int)_Left == (int)_Right);
	}

inline bool operator!=(cv_status _Left, _Cv_status _Right)
	{	// compare cv_status with _Cv_status for inequality
	return (!((int)_Left == (int)_Right));
	}
 #endif /* 0 < __GNUC__ */

class condition_variable
	{	// class for waiting for conditions
public:
	typedef _Cnd_t native_handle_type;

	condition_variable()
		{	// construct
		_Cnd_initX(&_Mycnd());
		}

	~condition_variable() _NOEXCEPT
		{	// destroy
		_Cnd_destroy(_THR_ADDR _Mycnd());
		}

	condition_variable(const condition_variable&) = delete;
	condition_variable& operator=(const condition_variable&) = delete;

	void notify_one() _NOEXCEPT
		{	// wake up one waiter
		_Cnd_signalX(_THR_ADDR _Mycnd());
		}

	void notify_all() _NOEXCEPT
		{	// wake up all waiters
		_Cnd_broadcastX(_THR_ADDR _Mycnd());
		}

	void wait(unique_lock<mutex>& _Lck)
		{	// wait for signal
		_Cnd_waitX(_THR_ADDR _Mycnd(), _THR_ADDR _Lck.mutex()->_Mymtx());
		}

	template<class _Predicate>
		void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
		{	// wait for signal and test predicate
		while (!_Pred())
			wait(_Lck);
		}

	template<class _Rep,
		class _Period>
		_Cv_status wait_for(
			unique_lock<mutex>& _Lck,
			const chrono::duration<_Rep, _Period>& _Rel_time)
		{	// wait for duration
		Dinkum::threads::xtime _Tgt = _To_xtime(_Rel_time);
		return (wait_until(_Lck, &_Tgt));
		}

	template<class _Rep,
		class _Period,
		class _Predicate>
		bool wait_for(
			unique_lock<mutex>& _Lck,
			const chrono::duration<_Rep, _Period>& _Rel_time,
			_Predicate _Pred)
		{	// wait for signal with timeout and check predicate
		Dinkum::threads::xtime _Tgt = _To_xtime(_Rel_time);
		return (wait_until(_Lck, &_Tgt, _Pred));
		}

	template<class _Clock,
		class _Duration>
		_Cv_status wait_until(
			unique_lock<mutex>& _Lck,
			const chrono::time_point<_Clock, _Duration>& _Abs_time)
		{	// wait until time point
		typename chrono::time_point<_Clock,
			typename _STD common_type<_Duration,
				typename _Clock::duration>::type>::duration
			_Rel_time = _Abs_time - _Clock::now();
		return (wait_for(_Lck, _Rel_time));
		}

	template<class _Clock,
		class _Duration,
		class _Predicate>
		bool wait_until(
			unique_lock<mutex>& _Lck,
			const chrono::time_point<_Clock, _Duration>& _Abs_time,
			_Predicate _Pred)
		{	// wait for signal with timeout and check predicate
#if defined(__ghs)
		typename chrono::time_point<_Clock,
			typename std::common_type<_Duration,
				typename _Clock::duration>::type>::duration
#else       
		typename chrono::time_point<_Clock, _Duration>::duration
#endif /* __ghs */
			_Rel_time = _Abs_time - _Clock::now();
		return (wait_for(_Lck, _Rel_time, _Pred));
		}

	_Cv_status wait_until(
		unique_lock<mutex>& _Lck,
		const xtime *_Abs_time)
		{	// wait for signal with timeout
		if (!_Mtx_current_owns(_THR_ADDR _Lck.mutex()->_Mymtx()))
			_Throw_Cpp_error(_OPERATION_NOT_PERMITTED);
		int _Res = _Cnd_timedwaitX(_THR_ADDR _Mycnd(),
			_THR_ADDR _Lck.mutex()->_Mymtx(), _Abs_time);
		return (_Res == _Thrd_timedout
			? cv_status::timeout : cv_status::no_timeout);
		}

	template<class _Predicate>
		bool wait_until(
			unique_lock<mutex>& _Lck,
			const xtime *_Abs_time,
			_Predicate _Pred)
		{	// wait for signal with timeout and check predicate
		while (!_Pred())
			if (wait_until(_Lck, _Abs_time) == cv_status::timeout)
				return (_Pred());
		return (true);
		}

	native_handle_type native_handle()
		{	// return condition variable handle
		return (_Mycnd());
		}

	void _Register(unique_lock<mutex>& _Lck, int *_Ready)
		{	// register this object for release at thread exit
		_Cnd_register_at_thread_exit(_THR_ADDR _Mycnd(),
			_THR_ADDR _Lck.release()->_Mymtx(), _Ready);
		}

#if !defined(__ghs)
	void _Unregister(mutex& _Mtx)
		{	// unregister this object for release at thread exit
		_Cnd_unregister_at_thread_exit(_THR_ADDR _Mtx._Mymtx());
		}
#endif /* !defined(__ghs) */

private:
	_Cnd_t& _Mycnd() _NOEXCEPT
		{	// get pointer to _Cnd_internal_imp_t
		return (_Cnd);
		}

	_Cnd_t _Cnd;
	};

#if defined(__ghs) && _HAS_CPP17
template<class... _Mutex_Tys>
	class scoped_lock
	{
public:
	explicit scoped_lock(_Mutex_Tys&... _M_Args): _M_Objects(_STD tie(_M_Args...))
		{
		_STD lock(_M_Args...);
		}
	
	scoped_lock(adopt_lock_t, _Mutex_Tys&... _M_Args) : _M_Objects(_STD tie(_M_Args...))
		{
		}
	
	~scoped_lock()
		{
		_STD apply([](_Mutex_Tys&... _M_Args)
			{
			[[maybe_unused]] int _Tmp[] = {(_M_Args.unlock(),0)...};
			}, _M_Objects);
		}
	
	scoped_lock(const scoped_lock&) = delete;
	scoped_lock& operator=(const scoped_lock&) = delete;
	
private:
	tuple<_Mutex_Tys&...> _M_Objects;
	};

template<>
	class scoped_lock<>
	{
public:
	explicit scoped_lock() { };
	scoped_lock(adopt_lock_t) { }
	~scoped_lock() = default;

	scoped_lock(const scoped_lock&) = delete;
	scoped_lock& operator=(const scoped_lock&) = delete;
	};

template<class _Mutex_Ty>
	class scoped_lock<_Mutex_Ty>
	{
public:
	using mutex_type = _Mutex_Ty;

	explicit scoped_lock(_Mutex_Ty& _M_Arg) : _M_Object(_M_Arg)
		{ 
		_M_Object.lock(); 
		}

	scoped_lock(adopt_lock_t, _Mutex_Ty& _M_Arg) : _M_Object(_M_Arg)
		{ 
		}

	~scoped_lock()
		{ 
		_M_Object.unlock();
		}

	scoped_lock(const scoped_lock&) = delete;
	scoped_lock& operator=(const scoped_lock&) = delete;

private:
	_Mutex_Ty&  _M_Object;
	};
#endif /* defined(__ghs) && _HAS_CPP17 */

#if defined(__ghs)
// Use the v6.44 implementations of timed_{recursive_}mutex, which don't require
// condition variable.

class _Timed_mutex_base
	: public _Mutex_base
	{	// base class for mutexes with timeouts
public:
	_Timed_mutex_base(int _Flags = 0)
		: _Mutex_base(_Flags | _Mtx_timed)
		{	// construct from _Flags
		}

 #if _HAS_FUNCTION_DELETE
	_Timed_mutex_base(const _Timed_mutex_base&) = delete;
	_Timed_mutex_base& operator=(const _Timed_mutex_base&) = delete;

 #else /* _HAS_FUNCTION_DELETE */
private:
	_Timed_mutex_base(const _Timed_mutex_base&);	// not defined
	_Timed_mutex_base& operator=(const _Timed_mutex_base&);	// not defined
public:
 #endif /* _HAS_FUNCTION_DELETE */

	template<class _Rep,
		class _Period>
		bool try_lock_for(
			const chrono::duration<_Rep, _Period>& _Rel_time)
		{	// try to lock for duration
#if defined(__ghs)
	        // do a relative wait without converting to absolute time
		Dinkum::threads::xtime _Tgt = _To_like_xtime(_Rel_time);
		return (_Mtx_rel_timedlockX(_THR_ADDR _Mymtx(), &_Tgt)
				== _Thrd_success);
#else
		Dinkum::threads::xtime _Tgt = _To_xtime(_Rel_time);
		return (try_lock_until(&_Tgt));
#endif
		}

	template<class _Clock, class _Duration>
		bool try_lock_until(
			const chrono::time_point<_Clock, _Duration>& _Abs_time)
		{	// try to lock until time point
#if defined(__ghs)
	        // do a wait until without converting to relative time
		Dinkum::threads::xtime _Tgt = _To_like_xtime(_Abs_time);
		return (try_lock_until(&_Tgt));
#else
		typename chrono::time_point<_Clock, _Duration>::duration _Rel_time =
			_Abs_time - _Clock::now();
		return (try_lock_for(_Rel_time));
#endif
		}

	bool try_lock_until(const xtime *_Abs_time)
		{	// try to lock the mutex with timeout
		return (_Mtx_timedlockX(_THR_ADDR _Mymtx(), _Abs_time)
			== _Thrd_success);
		}
	};

class timed_mutex
	: public _Timed_mutex_base
	{	// class for mutual exclusion with timeouts
public:
	timed_mutex()
		: _Timed_mutex_base()
		{	// default construct
		}

 #if _HAS_FUNCTION_DELETE
	timed_mutex(const timed_mutex&) = delete;
	timed_mutex& operator=(const timed_mutex&) = delete;

 #else /* _HAS_FUNCTION_DELETE */
private:
	timed_mutex(const timed_mutex&);	// not defined
	timed_mutex& operator=(const timed_mutex&); // not defined
 #endif /* _HAS_FUNCTION_DELETE */
	};

class recursive_timed_mutex
	: public _Timed_mutex_base
	{	// class for recursive mutual exclusion with timeouts
public:
	recursive_timed_mutex()
		: _Timed_mutex_base(_Mtx_recursive)
		{	// default construct
		}

 #if _HAS_FUNCTION_DELETE
	recursive_timed_mutex(const recursive_timed_mutex&) = delete;
	recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;

 #else /* _HAS_FUNCTION_DELETE */
private:
	recursive_timed_mutex(const recursive_timed_mutex&);	// not defined
	recursive_timed_mutex& operator=(
		const recursive_timed_mutex&); // not defined
 #endif /* _HAS_FUNCTION_DELETE */
	};

#else

class timed_mutex
	{	// class for timed mutual exclusion
public:
	timed_mutex() _NOEXCEPT
		: _My_locked(0)
		{	// default construct
		}

	timed_mutex(const timed_mutex&) = delete;
	timed_mutex& operator=(const timed_mutex&) = delete;

	void lock()
		{	// lock the mutex
		unique_lock<mutex> _Lock(_My_mutex);
		while (_My_locked != 0)
			_My_cond.wait(_Lock);
		_My_locked = UINT_MAX;
		}

	bool try_lock() _NOEXCEPT
		{	// try to lock the mutex
		lock_guard<mutex> _Lock(_My_mutex);
		if (_My_locked != 0)
			return (false);
		else
			{
			_My_locked = UINT_MAX;
			return (true);
			}
		}

	void unlock()
		{	// unlock the mutex
			{
			// The lock here is necessary
			lock_guard<mutex> _Lock(_My_mutex);
			_My_locked = 0;
			}
		_My_cond.notify_one();
		}

	template<class _Rep,
		class _Period>
		bool try_lock_for(const chrono::duration<_Rep, _Period>& _Rel_time)
		{	// try to lock for duration
		return (try_lock_until(chrono::steady_clock::now() + _Rel_time));
		}

	template<class _Time>
		bool _Try_lock_until(_Time _Abs_time)
		{	// try to lock the mutex with timeout
		unique_lock<mutex> _Lock(_My_mutex);
		if (!_My_cond.wait_until(_Lock, _Abs_time,
			[this] { return (_My_locked == 0); }))
				return (false);
		_My_locked = UINT_MAX;
		return (true);
		}

	template<class _Clock,
		class _Duration>
		bool try_lock_until(
		const chrono::time_point<_Clock, _Duration>& _Abs_time)
		{	// try to lock the mutex with timeout
		return (_Try_lock_until(_Abs_time));
		}

	bool try_lock_until(const xtime *_Abs_time)
		{	// try to lock the mutex with timeout
		return (_Try_lock_until(_Abs_time));
		}

private:
	mutex _My_mutex;
	condition_variable _My_cond;
	unsigned int _My_locked;
	};

class recursive_timed_mutex
	{	// class for recursive timed mutual exclusion
public:
	recursive_timed_mutex() _NOEXCEPT
		: _My_locked(0)
		{	// default construct
		}

	recursive_timed_mutex(const recursive_timed_mutex&) = delete;
	recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;

	void lock()
		{	// lock the mutex
		thread::id _Tid = this_thread::get_id();

		unique_lock<mutex> _Lock(_My_mutex);

		if (_Tid == _My_owner)
			{
			if (_My_locked < UINT_MAX)
				++_My_locked;
			else
				_THROW_NCEE(system_error,
					_STD make_error_code(errc::device_or_resource_busy));
			}
		else
			{
			while (_My_locked != 0)
				_My_cond.wait(_Lock);
			_My_locked = 1;
			_My_owner = _Tid;
			}
		}

	bool try_lock() _NOEXCEPT
		{	// try to lock the mutex
		thread::id _Tid = this_thread::get_id();

		lock_guard<mutex> _Lock(_My_mutex);

		if (_Tid == _My_owner)
			{
			if (_My_locked < UINT_MAX)
				++_My_locked;
			else
				return (false);
			}
		else
			{
			if (_My_locked != 0)
				return (false);
			else
				{
				_My_locked = 1;
				_My_owner = _Tid;
				}
			}
		return (true);
	}

	void unlock()
		{	// unlock the mutex
		bool _Do_notify = false;

			{
			lock_guard<mutex> _Lock(_My_mutex);
			--_My_locked;
			if (_My_locked == 0)
				{
				_Do_notify = true;
				_My_owner = thread::id();
				}
			}

		if (_Do_notify)
			_My_cond.notify_one();
		}

	template<class _Rep,
		class _Period>
		bool try_lock_for(const chrono::duration<_Rep, _Period>& _Rel_time)
		{	// try to lock for duration
		return (try_lock_until(chrono::steady_clock::now() + _Rel_time));
		}

	template<class _Time>
		bool _Try_lock_until(_Time _Abs_time)
		{	// try to lock the mutex with timeout
		thread::id _Tid = this_thread::get_id();

		unique_lock<mutex> _Lock(_My_mutex);

		if (_Tid == _My_owner)
			{
			if (_My_locked < UINT_MAX)
				++_My_locked;
			else
				return (false);
			}
		else
			{
			if (!_My_cond.wait_until(_Lock, _Abs_time,
				[this] { return (_My_locked == 0); }))
					return (false);
			_My_locked = 1;
			_My_owner = _Tid;
			}
		return (true);
		}

	template<class _Clock,
		class _Duration>
		bool try_lock_until(
		const chrono::time_point<_Clock, _Duration>& _Abs_time)
		{	// try to lock the mutex with timeout
		return (_Try_lock_until(_Abs_time));
		}

	bool try_lock_until(const xtime *_Abs_time)
		{	// try to lock the mutex with timeout
		return (_Try_lock_until(_Abs_time));
		}

private:
	mutex _My_mutex;
	condition_variable _My_cond;
	unsigned int _My_locked;
	thread::id _My_owner;
	};
#endif /* defined(__ghs) */
_STD_END

 #if defined(__ghs) && defined(__ghs_max_pack_value)
  #pragma pack(pop)
 #endif
 #if defined(__GHS_PRAGMAS)
  #pragma ghs enddata
 #endif

#endif /* _MUTEX_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V8.03b/17:0063 */
