1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: os_BlockingQueue.h 4 5 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 33014 $ 14 *---------------------------------------------------------------------------*/ 15 16 /*! :private 17 @file 18 @brief BlockingQueue に関する API の宣言 19 20 :include nn/os.h 21 */ 22 23 #ifndef NN_OS_OS_INTERCORE_BLOCKINGQUEUE_H_ 24 #define NN_OS_OS_INTERCORE_BLOCKINGQUEUE_H_ 25 26 #include <nn/os/os_InterCoreLightSemaphore.h> 27 #include <nn/os/os_InterCoreCriticalSection.h> 28 #include <nn/fnd/fnd_Interlocked.h> 29 #include <nn/util/util_NonCopyable.h> 30 31 #ifdef __cplusplus 32 33 namespace nn { namespace os { 34 35 namespace detail { 36 37 /*! 38 :private 39 40 @brief ブロッキングキューの基底クラスです。 41 */ 42 template <class Locker> 43 class InterCoreBlockingQueueBase : private nn::util::NonCopyable<InterCoreBlockingQueueBase<Locker> > 44 { 45 protected: InterCoreBlockingQueueBase()46 InterCoreBlockingQueueBase() {} InterCoreBlockingQueueBase(uptr buffer[],size_t size)47 InterCoreBlockingQueueBase(uptr buffer[], size_t size) { Initialize(buffer, size); } 48 ~InterCoreBlockingQueueBase(); 49 void Initialize(uptr buffer[], size_t size); 50 nn::Result TryInitialize(uptr buffer[], size_t size); 51 void Finalize(); 52 void Enqueue(uptr data); 53 bool TryEnqueue(uptr data); 54 bool ForceEnqueue(uptr data, uptr* pOut); 55 void Jam(uptr data); 56 bool TryJam(uptr data); 57 uptr Dequeue(); 58 bool TryDequeue(uptr* pOut); 59 uptr GetFront() const; 60 bool TryGetFront(uptr* pOut) const; 61 62 // TODO: これらの関数の扱いを決める 63 GetWaitingEnqueueCount(void)64 s32 GetWaitingEnqueueCount(void) const 65 { return m_WaitingEnqueueCount; } 66 GetWaitingDequeueCount(void)67 s32 GetWaitingDequeueCount(void) const 68 { return m_WaitingDequeueCount; } 69 70 // テスト用内部メンバアクセサ GetSize()71 s32 GetSize() const 72 { return m_size; } 73 GetUsedCount()74 s32 GetUsedCount() const 75 { return m_usedCount; } 76 GetFirstIndex()77 s32 GetFirstIndex() const 78 { return m_firstIndex; } 79 80 private: 81 typedef typename Locker::ScopedLock ScopedLock; 82 83 uptr* m_ppBuffer; //!< キュー用バッファ 84 mutable InterCoreLightSemaphore m_EnqueueSemaphore; //!< キューへの挿入待ち用同期オブジェクト 85 mutable InterCoreLightSemaphore m_DequeueSemaphore; //!< キューからの取り出し待ち用同期オブジェクト 86 mutable Locker m_cs; //!< キュー操作用同期オブジェクト 87 size_t m_size; //!< キューのサイズ 88 s32 m_firstIndex; //!< キューの先頭へのインデックス 89 s32 m_usedCount; //!< キューに入っている要素数 90 mutable nn::fnd::InterlockedVariable<s32> m_WaitingEnqueueCount; //!< キューに挿入処理中のスレッド数 91 mutable nn::fnd::InterlockedVariable<s32> m_WaitingDequeueCount; //!< キューから取り出し処理中のスレッド数 92 93 //!< データ挿入待ちスレッドを起床します。 94 void NotifyEnqueue() const; 95 96 //!< キュー空き待ちスレッドを起床します。 97 void NotifyDequeue() const; 98 }; 99 100 } 101 102 103 /*! :private 104 @brief ブロッキングキューを扱う為のクラスです。 105 106 基本的に @ref InterCoreBlockingQueue と同じですが、スレッド同期に @ref InterCoreCriticalSection を 107 使っており、マルチコア間の同期に使用することを目的としています。 108 */ 109 class InterCoreBlockingQueue : private os::detail::InterCoreBlockingQueueBase<nn::os::InterCoreCriticalSection> 110 { 111 private: 112 typedef os::detail::InterCoreBlockingQueueBase<nn::os::InterCoreCriticalSection> Base; 113 public: 114 115 /*! :private 116 @brief コンストラクタです。 117 118 ブロッキングキューを構築します。 119 120 初期化処理を行わないコンストラクタと、初期化処理を行うコンストラクタがあります。 121 122 コンストラクタで初期化しない場合、使用する前には別途 @ref Initialize を呼んで初期化する必要があります。 123 */ InterCoreBlockingQueue()124 InterCoreBlockingQueue() {} 125 126 /*! :private 127 @brief コンストラクタです。 128 129 ブロッキングキューを構築し、初期化します。 130 131 @param[in] buffer キューに使用するバッファ。uptr 型の配列を指定します。 132 @param[in] size バッファのサイズ。配列の要素数を指定します。 133 */ InterCoreBlockingQueue(uptr buffer[],size_t size)134 InterCoreBlockingQueue(uptr buffer[], size_t size) : Base(buffer, size) {} 135 136 /*! :private 137 @brief デストラクタです。 138 139 内部で @ref Finalize を呼びます。 140 */ ~InterCoreBlockingQueue()141 ~InterCoreBlockingQueue() { Finalize(); } 142 143 /*! :private 144 @brief ブロッキングキューを指定したバッファとサイズで初期化します。 145 146 @param[in] buffer キューに使用するバッファ。uptr 型の配列を指定します。 147 @param[in] size バッファのサイズ。配列の要素数を指定します。 148 149 @return 無し。 150 */ Initialize(uptr buffer[],size_t size)151 void Initialize(uptr buffer[], size_t size) { Base::Initialize(buffer, size); } 152 153 /*! :private 154 @brief ブロッキングキューを指定したバッファとサイズで初期化します。 155 156 初期化に失敗した際は、失敗に応じた Result 値を返します。 157 158 @param[in] buffer キューに使用するバッファ。uptr 型の配列を指定します。 159 @param[in] size バッファのサイズ。配列の要素数を指定します。 160 161 @return 関数の実行結果を返します。 162 */ TryInitialize(uptr buffer[],size_t size)163 nn::Result TryInitialize(uptr buffer[], size_t size) { return Base::TryInitialize(buffer, size); } 164 165 /*! :private 166 @brief ブロッキングキューを破棄します。 167 168 デストラクタから自動的に呼び出されますが、明示的に呼ぶこともできます。 169 170 @return 無し。 171 */ Finalize()172 void Finalize() { Base::Finalize(); } 173 174 /*! :private 175 @brief キューの末尾に要素を挿入します。 176 177 キューの末尾にデータを挿入しますが、 178 キューが一杯 (full) であれば、この関数を呼び出したスレッドはブロックされます。 179 受信スレッドが動作して、キューからデータを取り出すとすぐに再開されます。 180 181 @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 182 これらのスレッドが起こされます。 183 184 @param[in] data 挿入する要素 185 186 @return 無し。 187 */ Enqueue(uptr data)188 void Enqueue(uptr data) { Base::Enqueue(data); } 189 190 /*! :private 191 @brief キューの末尾への要素の挿入を試行します。 192 193 キューに空きがあれば、末尾に要素を挿入し、true を返します。 194 キューに空きが無いとき、何もせず、false を返します。 195 196 要素の挿入がされたときに @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 197 これらのスレッドが起こされます。 198 199 @param[in] data 挿入する要素 200 201 @return 挿入されたとき true を返し、挿入されなかったとき false を返します。 202 */ TryEnqueue(uptr data)203 bool TryEnqueue(uptr data) { return Base::TryEnqueue(data); } 204 205 /*! :private 206 @brief キューの先頭に要素を挿入します。 207 208 キューの先頭にデータを挿入しますが、 209 キューが一杯 (full) であれば、この関数を呼び出したスレッドはブロックされます。 210 受信スレッドが動作して、キューからデータを取り出すとすぐに再開されます。 211 212 @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 213 これらのスレッドが起こされます。 214 215 @param[in] data 挿入する要素 216 217 @return 無し。 218 */ Jam(uptr data)219 void Jam(uptr data) { Base::Jam(data); } 220 221 /*! :private 222 @brief キューの先頭への要素の挿入を試行します。 223 224 キューに空きがあれば、先頭に要素を挿入し、true を返します。 225 キューに空きが無いとき、何もせず、false を返します。 226 227 要素の挿入がされたときに @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 228 これらのスレッドが起こされます。 229 230 @param[in] data 挿入する要素 231 232 @return 挿入されたとき true を返し、挿入されなかったとき false を返します。 233 */ TryJam(uptr data)234 bool TryJam(uptr data) { return Base::TryJam(data); } 235 236 /*! :private 237 @brief キューの先頭から要素を取り出します。 238 239 キューが空であるとき、キューが空でなくなるまでスレッドをブロックします。 240 キューが空でなければ、キューの先頭から要素を取り出しすぐに処理を返します。 241 242 @ref Enqueue や @ref Jam で待っているスレッドがあった場合、 243 これらのスレッドが起こされます。 244 245 @return キューから取り出した要素 246 */ Dequeue()247 uptr Dequeue() { return Base::Dequeue(); } 248 249 /*! :private 250 @brief キューの先頭から要素を取り出します。 251 252 キューが空でなれば、キューの先頭から要素を取り出し、true を返します。 253 キューが空のとき、何もせず、false を返します。 254 255 要素の挿入がされたときに @ref Dequeue や @ref GetFront で待っているスレッドがあった場合、 256 これらのスレッドが起こされます。 257 258 @param[out] pOut 取り出した要素を書き込むバッファ 259 260 @return 要素を取り出したとき true を返し、取り出さなかったとき false を返します。 261 */ TryDequeue(uptr * pOut)262 bool TryDequeue(uptr* pOut) { return Base::TryDequeue(pOut); } 263 264 /*! :private 265 @brief キューの先頭から要素を取得します。 266 267 キューが空であるとき、キューが空でなくなるまでスレッドをブロックします。 268 キューが空でなければ、キューの先頭の要素を取得します。キューの状態は変化しません。 269 270 @return キューの先頭の要素 271 */ GetFront()272 uptr GetFront() const { return Base::GetFront(); } 273 274 /*! :private 275 @brief キューの先頭から要素を取得します。 276 277 キューが空であるとき、何もせず false を返します。 278 キューが空でなければ、キューの先頭の要素を *pOut に書き込み、true を返します。キューの状態は変化しません。 279 280 @param[out] pOut 取り出す値の格納先 281 282 @return 要素を取得できたとき true を返し、取得できなかったとき false を返します。 283 */ TryGetFront(uptr * pOut)284 bool TryGetFront(uptr* pOut) const { return Base::TryGetFront(pOut); } 285 286 // TODO: テスト用 287 using Base::GetSize; 288 using Base::GetUsedCount; 289 using Base::GetFirstIndex; 290 291 }; 292 293 294 }} 295 296 #endif 297 298 // 以下、C 用宣言 299 300 #include <nn/util/detail/util_CLibImpl.h> 301 302 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosInterCoreBlockingQueue, nn::os::InterCoreBlockingQueue, 40 + NN_OS_INTERCORE_CRITICALSECTION_SIZE, u32); 303 304 NN_EXTERN_C void nnosInterCoreBlockingQueueInitialize(nnosInterCoreBlockingQueue* this_, uptr buffer[], size_t size); 305 306 NN_EXTERN_C bool nnosInterCoreBlockingQueueTryInitialize(nnosInterCoreBlockingQueue* this_, uptr buffer[], size_t size); 307 308 NN_EXTERN_C void nnosInterCoreBlockingQueueFinalize(nnosInterCoreBlockingQueue* this_); 309 310 NN_EXTERN_C bool nnosInterCoreBlockingQueueTryEnqueue(nnosInterCoreBlockingQueue* this_, uptr data); 311 312 NN_EXTERN_C void nnosInterCoreBlockingQueueEnqueue(nnosInterCoreBlockingQueue* this_, uptr data); 313 314 NN_EXTERN_C bool nnosInterCoreBlockingQueueTryJam(nnosInterCoreBlockingQueue* this_, uptr data); 315 316 NN_EXTERN_C void nnosInterCoreBlockingQueueJam(nnosInterCoreBlockingQueue* this_, uptr data); 317 318 NN_EXTERN_C bool nnosInterCoreBlockingQueueTryDequeue(nnosInterCoreBlockingQueue* this_, uptr* pOut); 319 320 NN_EXTERN_C uptr nnosInterCoreBlockingQueueDequeue(nnosInterCoreBlockingQueue* this_); 321 322 NN_EXTERN_C bool nnosInterCoreBlockingQueueTryGetFront(nnosInterCoreBlockingQueue* this_, uptr* pOut); 323 324 NN_EXTERN_C uptr nnosInterCoreBlockingQueueGetFront(nnosInterCoreBlockingQueue* this_); 325 326 #endif 327