/*---------------------------------------------------------------------------* Project: Horizon File: os_Mutex.h Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 29304 $ *---------------------------------------------------------------------------*/ /*! @file @brief Mutex に関する API の宣言 :include nn/os.h */ #ifndef NN_OS_OS_MUTEX_H_ #define NN_OS_OS_MUTEX_H_ #include #include #include #include #include #include #include #include #ifdef __cplusplus namespace nn { namespace os { /*! @brief ミューテックスを扱う為のクラスです。ミューテックスは排他制御を行うための同期オブジェクトです。 通常は @ref nn::os::Mutex ではなく、@ref nn::os::CriticalSection を使用すべきです。 スレッド間でロックが衝突しない場合のパフォーマンスでは @ref nn::os::CriticalSection の方が @ref nn::os::Mutex より 圧倒的に高速です。 プログラムの特定の箇所について複数のスレッドからの同時実行を抑制し、 データやレジスタなどのリソースが複数のスレッドから同時にアクセスされることを防ぎます。 ミューテックスは @ref Lock によってロックすることができます。 あるスレッドがロックしているミューテックスを、他のスレッドがロックすることはできず、 他のスレッドがロックしようとした場合は、ミューテックスがアンロックされるまでブロックします。 アンロックは @ref Unlock によって行いますが、 ミューテックスのロックはスレッドに紐付けられているため、ロックしているスレッドからしか呼ぶことはできません。 Mutex は再帰ロックミューテックスであり、ロックしているスレッドがさらに @ref Lock を呼ぶことができます。 このとき、@ref Lock を読んだ回数と同じ回数だけ @ref Unlock が呼ばれるまで、ミューテックスがアンロックされません。 Mutex は優先度継承を実装しています。 低い優先度を持つスレッド L がロックしているミューテックスのロックを、 高い優先度を持つスレッド H が取得しようとしたとき、 スレッド L の優先度は一時的にスレッド H と同じ値まで引き上げられます。 Mutex オブジェクトの Wait 動作は、ロックの取得です。 ロックが取得できると、Wait 動作は解放されます。 @ref nn::os::Mutex::ScopedLock を使うとオブジェクトの生成からスコープの有効範囲の終わりまでの間でMutexによるロックをかけることができます。 */ class Mutex : public WaitObject { public: /*! @brief ミューテックスを構築し、初期化します。 @param[in] initialLocked true を指定した場合、初期化と同時にロック状態にします。所有者は作成したスレッドになります。 */ explicit Mutex(bool initialLocked); /*! @brief ミューテックスオブジェクトを構築します。 ミューテックスオブジェクトを構築しますが、初期化はしません。 別途、@ref Initialize を呼ぶ必要があります。 */ Mutex() {} /*! @brief オブジェクトを構築し、初期化を行います。 */ Mutex(const nn::WithInitialize&); /*! @brief ミューテックスを初期化します。 @param[in] initialLocked true を指定した場合、初期化と同時にロック状態にします。所有者は作成したスレッドになります。 */ void Initialize(bool initialLocked = false); /*! @brief ミューテックスの初期化を試みます。 @param[in] initialLocked true を指定した場合、初期化と同時にロック状態にします。所有者は作成したスレッドになります。 @return 関数の実行結果を返します。 */ nn::Result TryInitialize(bool initialLocked = false); /*! @brief ミューテックスを破棄します。 デストラクタからも自動で呼ばれます。 @return 無し。 */ void Finalize() { WaitObject::Finalize(); } /*! @brief デストラクタです。 */ ~Mutex() {} /*! @brief ミューテックスをロックします。 他スレッドでロックされている場合はブロックします。 自スレッドで既にロックされている場合は、ネスト回数が増加します。 @return 無し。 */ void Lock() { this->WaitOne(); } /*! @brief ミューテックスのロックを試みます。 ミューテックスのロックを試み、成功すれば true が返ります。 ロックできなかった場合、最大で timeout で指定した時間だけ待ち、 その間にロックを取得できれば true を返します。 timeout で指定した時間だけ待ってもロックを取得できなかった場合は、false を返します。 @param[in] timeout タイムアウト時間を指定します。0 を指定すると即座に処理を返します。 @return ロックに成功したかを返します。 */ bool TryLock(nn::fnd::TimeSpan timeout = 0) { return this->WaitOne(timeout); } /*! @brief ミューテックスをアンロックします。 自スレッドでロックされているミューテックスのネスト回数を 1 減らします。 ミューテックスをロックしていないスレッドでこの関数を呼ぶことはできません。 @return 無し。 */ void Unlock(); /*! @class nn::os::Mutex::ScopedLock @brief オブジェクトの生成時からオブジェクトの存在するスコープを抜けるまで間、Mutexをロックします。 */ class ScopedLock; private: Result TryInitializeImpl(bool initialLocked); }; // インライン実装 inline Result Mutex::TryInitializeImpl(bool initialLocked) { Handle handle; NN_UTIL_RETURN_IF_FAILED(nn::svc::CreateMutex(&handle, initialLocked)); this->SetHandle(handle); return ResultSuccess(); } inline void Mutex::Initialize(bool initialLocked) { NN_ERR_THROW_FATAL(TryInitializeImpl(initialLocked)); } inline nn::Result Mutex::TryInitialize(bool initialLocked) { Result result = TryInitializeImpl(initialLocked); if (result.GetSummary() == Result::SUMMARY_OUT_OF_RESOURCE) { return result; } NN_ERR_THROW_FATAL(result); return result; } inline Mutex::Mutex(bool initialLocked) { Initialize(initialLocked); } inline Mutex::Mutex(const nn::WithInitialize&) { Initialize(false); } inline void Mutex::Unlock() { NN_ERR_THROW_FATAL(nn::svc::ReleaseMutex(GetHandle())); } NN_UTIL_DETAIL_DEFINE_SCOPED_LOCK(Mutex, Lock(), Unlock()); }} // namespace nn::os #endif // __cplusplus // 以下、C 用宣言 #include /*! @addtogroup nn_os @{ @defgroup nn_os_Mutex_c Mutex (C) @brief @ref nn::os::Mutex の C インタフェースモジュールです。 @{ */ /*! @struct nnosMutex @brief ミューテックスを表す C の構造体です。 @brief 対応するクラス @ref nn::os::Mutex を参照してください。 */ NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosMutex, nn::os::Mutex, 4, u32); NN_UTIL_DETAIL_CLIBIMPL_DECLARE_CONVERSION(nnosMutexToWaitObject, nnosMutex, nnosWaitObject); NN_UTIL_DETAIL_CLIBIMPL_DECLARE_CONVERSION(nnosWaitObjectToMutex, nnosWaitObject, nnosMutex); /*! @brief 対応する C++ 関数 @ref nn::os::Mutex::Initialize を参照してください。 */ NN_EXTERN_C void nnosMutexInitialize(nnosMutex* this_, bool initialLocked); /*! @brief 対応する C++ 関数 @ref nn::os::Mutex::TryInitialize を参照してください。 */ NN_EXTERN_C bool nnosMutexTryInitialize(nnosMutex* this_, bool initialLocked); /*! @brief 対応する C++ 関数 @ref nn::os::Mutex::Lock を参照してください。 */ NN_EXTERN_C void nnosMutexLock(nnosMutex* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Mutex::TryLock を参照してください。 */ NN_EXTERN_C bool nnosMutexTryLock(nnosMutex* this_, s64 timeout); /*! @brief 対応する C++ 関数 @ref nn::os::Mutex::Unlock を参照してください。 */ NN_EXTERN_C void nnosMutexUnlock(nnosMutex* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Mutex::Finalize を参照してください。 */ NN_EXTERN_C void nnosMutexFinalize(nnosMutex* this_); /*! @} @} */ #endif /* NN_OS_IPC_OS_MUTEX_H_ */