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