/*---------------------------------------------------------------------------* Project: Horizon File: os_BlockingQueue.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: 33014 $ *---------------------------------------------------------------------------*/ /*! :private @file @brief BlockingQueue に関する API の宣言 :include nn/os.h */ #ifndef NN_OS_OS_INTERCORE_BLOCKINGQUEUE_H_ #define NN_OS_OS_INTERCORE_BLOCKINGQUEUE_H_ #include #include #include #include #ifdef __cplusplus namespace nn { namespace os { namespace detail { /*! :private @brief ブロッキングキューの基底クラスです。 */ template class InterCoreBlockingQueueBase : private nn::util::NonCopyable > { protected: InterCoreBlockingQueueBase() {} InterCoreBlockingQueueBase(uptr buffer[], size_t size) { Initialize(buffer, size); } ~InterCoreBlockingQueueBase(); void Initialize(uptr buffer[], size_t size); nn::Result TryInitialize(uptr buffer[], size_t size); void Finalize(); void Enqueue(uptr data); bool TryEnqueue(uptr data); bool ForceEnqueue(uptr data, uptr* pOut); void Jam(uptr data); bool TryJam(uptr data); uptr Dequeue(); bool TryDequeue(uptr* pOut); uptr GetFront() const; bool TryGetFront(uptr* pOut) const; // TODO: これらの関数の扱いを決める s32 GetWaitingEnqueueCount(void) const { return m_WaitingEnqueueCount; } s32 GetWaitingDequeueCount(void) const { return m_WaitingDequeueCount; } // テスト用内部メンバアクセサ s32 GetSize() const { return m_size; } s32 GetUsedCount() const { return m_usedCount; } s32 GetFirstIndex() const { return m_firstIndex; } private: typedef typename Locker::ScopedLock ScopedLock; uptr* m_ppBuffer; //!< キュー用バッファ mutable InterCoreLightSemaphore m_EnqueueSemaphore; //!< キューへの挿入待ち用同期オブジェクト mutable InterCoreLightSemaphore m_DequeueSemaphore; //!< キューからの取り出し待ち用同期オブジェクト mutable Locker m_cs; //!< キュー操作用同期オブジェクト size_t m_size; //!< キューのサイズ s32 m_firstIndex; //!< キューの先頭へのインデックス s32 m_usedCount; //!< キューに入っている要素数 mutable nn::fnd::InterlockedVariable m_WaitingEnqueueCount; //!< キューに挿入処理中のスレッド数 mutable nn::fnd::InterlockedVariable m_WaitingDequeueCount; //!< キューから取り出し処理中のスレッド数 //!< データ挿入待ちスレッドを起床します。 void NotifyEnqueue() const; //!< キュー空き待ちスレッドを起床します。 void NotifyDequeue() const; }; } /*! :private @brief ブロッキングキューを扱う為のクラスです。 基本的に @ref InterCoreBlockingQueue と同じですが、スレッド同期に @ref InterCoreCriticalSection を 使っており、マルチコア間の同期に使用することを目的としています。 */ class InterCoreBlockingQueue : private os::detail::InterCoreBlockingQueueBase { private: typedef os::detail::InterCoreBlockingQueueBase Base; public: /*! :private @brief コンストラクタです。 ブロッキングキューを構築します。 初期化処理を行わないコンストラクタと、初期化処理を行うコンストラクタがあります。 コンストラクタで初期化しない場合、使用する前には別途 @ref Initialize を呼んで初期化する必要があります。 */ InterCoreBlockingQueue() {} /*! :private @brief コンストラクタです。 ブロッキングキューを構築し、初期化します。 @param[in] buffer キューに使用するバッファ。uptr 型の配列を指定します。 @param[in] size バッファのサイズ。配列の要素数を指定します。 */ InterCoreBlockingQueue(uptr buffer[], size_t size) : Base(buffer, size) {} /*! :private @brief デストラクタです。 内部で @ref Finalize を呼びます。 */ ~InterCoreBlockingQueue() { Finalize(); } /*! :private @brief ブロッキングキューを指定したバッファとサイズで初期化します。 @param[in] buffer キューに使用するバッファ。uptr 型の配列を指定します。 @param[in] size バッファのサイズ。配列の要素数を指定します。 @return 無し。 */ void Initialize(uptr buffer[], size_t size) { Base::Initialize(buffer, size); } /*! :private @brief ブロッキングキューを指定したバッファとサイズで初期化します。 初期化に失敗した際は、失敗に応じた Result 値を返します。 @param[in] buffer キューに使用するバッファ。uptr 型の配列を指定します。 @param[in] size バッファのサイズ。配列の要素数を指定します。 @return 関数の実行結果を返します。 */ nn::Result TryInitialize(uptr buffer[], size_t size) { return Base::TryInitialize(buffer, size); } /*! :private @brief ブロッキングキューを破棄します。 デストラクタから自動的に呼び出されますが、明示的に呼ぶこともできます。 @return 無し。 */ void Finalize() { Base::Finalize(); } /*! :private @brief キューの末尾に要素を挿入します。 キューの末尾にデータを挿入しますが、 キューが一杯 (full) であれば、この関数を呼び出したスレッドはブロックされます。 受信スレッドが動作して、キューからデータを取り出すとすぐに再開されます。 @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 これらのスレッドが起こされます。 @param[in] data 挿入する要素 @return 無し。 */ void Enqueue(uptr data) { Base::Enqueue(data); } /*! :private @brief キューの末尾への要素の挿入を試行します。 キューに空きがあれば、末尾に要素を挿入し、true を返します。 キューに空きが無いとき、何もせず、false を返します。 要素の挿入がされたときに @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 これらのスレッドが起こされます。 @param[in] data 挿入する要素 @return 挿入されたとき true を返し、挿入されなかったとき false を返します。 */ bool TryEnqueue(uptr data) { return Base::TryEnqueue(data); } /*! :private @brief キューの先頭に要素を挿入します。 キューの先頭にデータを挿入しますが、 キューが一杯 (full) であれば、この関数を呼び出したスレッドはブロックされます。 受信スレッドが動作して、キューからデータを取り出すとすぐに再開されます。 @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 これらのスレッドが起こされます。 @param[in] data 挿入する要素 @return 無し。 */ void Jam(uptr data) { Base::Jam(data); } /*! :private @brief キューの先頭への要素の挿入を試行します。 キューに空きがあれば、先頭に要素を挿入し、true を返します。 キューに空きが無いとき、何もせず、false を返します。 要素の挿入がされたときに @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 これらのスレッドが起こされます。 @param[in] data 挿入する要素 @return 挿入されたとき true を返し、挿入されなかったとき false を返します。 */ bool TryJam(uptr data) { return Base::TryJam(data); } /*! :private @brief キューの先頭から要素を取り出します。 キューが空であるとき、キューが空でなくなるまでスレッドをブロックします。 キューが空でなければ、キューの先頭から要素を取り出しすぐに処理を返します。 @ref Enqueue や @ref Jam で待っているスレッドがあった場合、 これらのスレッドが起こされます。 @return キューから取り出した要素 */ uptr Dequeue() { return Base::Dequeue(); } /*! :private @brief キューの先頭から要素を取り出します。 キューが空でなれば、キューの先頭から要素を取り出し、true を返します。 キューが空のとき、何もせず、false を返します。 要素の挿入がされたときに @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 これらのスレッドが起こされます。 @param[out] pOut 取り出した要素を書き込むバッファ @return 要素を取り出したとき true を返し、取り出さなかったとき false を返します。 */ bool TryDequeue(uptr* pOut) { return Base::TryDequeue(pOut); } /*! :private @brief キューの先頭から要素を取得します。 キューが空であるとき、キューが空でなくなるまでスレッドをブロックします。 キューが空でなければ、キューの先頭の要素を取得します。キューの状態は変化しません。 @return キューの先頭の要素 */ uptr GetFront() const { return Base::GetFront(); } /*! :private @brief キューの先頭から要素を取得します。 キューが空であるとき、何もせず false を返します。 キューが空でなければ、キューの先頭の要素を *pOut に書き込み、true を返します。キューの状態は変化しません。 @param[out] pOut 取り出す値の格納先 @return 要素を取得できたとき true を返し、取得できなかったとき false を返します。 */ bool TryGetFront(uptr* pOut) const { return Base::TryGetFront(pOut); } // TODO: テスト用 using Base::GetSize; using Base::GetUsedCount; using Base::GetFirstIndex; }; }} #endif // 以下、C 用宣言 #include NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosInterCoreBlockingQueue, nn::os::InterCoreBlockingQueue, 40 + NN_OS_INTERCORE_CRITICALSECTION_SIZE, u32); NN_EXTERN_C void nnosInterCoreBlockingQueueInitialize(nnosInterCoreBlockingQueue* this_, uptr buffer[], size_t size); NN_EXTERN_C bool nnosInterCoreBlockingQueueTryInitialize(nnosInterCoreBlockingQueue* this_, uptr buffer[], size_t size); NN_EXTERN_C void nnosInterCoreBlockingQueueFinalize(nnosInterCoreBlockingQueue* this_); NN_EXTERN_C bool nnosInterCoreBlockingQueueTryEnqueue(nnosInterCoreBlockingQueue* this_, uptr data); NN_EXTERN_C void nnosInterCoreBlockingQueueEnqueue(nnosInterCoreBlockingQueue* this_, uptr data); NN_EXTERN_C bool nnosInterCoreBlockingQueueTryJam(nnosInterCoreBlockingQueue* this_, uptr data); NN_EXTERN_C void nnosInterCoreBlockingQueueJam(nnosInterCoreBlockingQueue* this_, uptr data); NN_EXTERN_C bool nnosInterCoreBlockingQueueTryDequeue(nnosInterCoreBlockingQueue* this_, uptr* pOut); NN_EXTERN_C uptr nnosInterCoreBlockingQueueDequeue(nnosInterCoreBlockingQueue* this_); NN_EXTERN_C bool nnosInterCoreBlockingQueueTryGetFront(nnosInterCoreBlockingQueue* this_, uptr* pOut); NN_EXTERN_C uptr nnosInterCoreBlockingQueueGetFront(nnosInterCoreBlockingQueue* this_); #endif