1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_LightBarrier.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: 38846 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NN_OS_OS_LIGHTBARRIER_H_
17 #define NN_OS_OS_LIGHTBARRIER_H_
18 
19 #ifdef __cplusplus
20 
21 #include <nn/os/os_WaitableCounter.h>
22 #include <nn/assert.h>
23 #include <nn/WithInitialize.h>
24 #include <nn/util/detail/util_ScopedLockImpl.h>
25 #include <cstdlib>
26 
27 namespace nn { namespace os {
28 
29 /* Please see man pages for details
30 
31 
32 
33 
34 */
35 
36 /*
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49  */
50 class LightBarrier
51 {
52 private:
53     struct IncrementIfLessThan_1
54     {
operatorIncrementIfLessThan_155         bool operator()(s32& x)
56         {
57             if( x < -1 )
58             {
59                 ++x;
60                 return true;
61             }
62             else
63             {
64                 return false;
65             }
66         }
67     };
68 
69 private:
70     WaitableCounter     m_CounterPlus;
71     WaitableCounter     m_CounterMinus;
72     s32                 m_ReleaseCountAndSign;
73 
74 public:
75     //----------------------------------------
76     //
77     //
78 
79     /*
80 
81 
82 
83 
84 
85 
86 
87 
88      */
LightBarrier()89     LightBarrier() {}
90 
91     /*
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102      */
LightBarrier(s32 numWait)103     LightBarrier(s32 numWait) { Initialize(numWait); }
104 
105     /*
106 
107 
108 
109 
110 
111 
112      */
Initialize(s32 numWait)113     void Initialize(s32 numWait)
114     {
115         NN_MIN_TASSERT_( numWait, 1 );
116 
117         *m_CounterPlus  = - numWait;
118         *m_CounterMinus = - numWait;
119         m_ReleaseCountAndSign = numWait;
120     }
121 
122     /*
123 
124 
125 
126 
127      */
Finalize()128     void Finalize() {}
129 
130     //
131 
132     //----------------------------------------
133     //
134     //
135 
136     /*
137 
138 
139 
140 
141 
142 
143 
144      */
GetReleaseCount()145     s32 GetReleaseCount() const { return std::abs(m_ReleaseCountAndSign); }
146 
147     /*
148 
149 
150 
151 
152 
153 
154 
155      */
GetNumOfWaiting()156     s32 GetNumOfWaiting() const
157     {
158         const s32 relCountAndSign = m_ReleaseCountAndSign;
159         s32 minusRemain;
160         s32 relCount;
161 
162         if( relCountAndSign > 0 )
163         {
164             minusRemain = *m_CounterPlus;
165             relCount    = relCountAndSign;
166         }
167         else
168         {
169             minusRemain = *m_CounterMinus;
170             relCount    = - relCountAndSign;
171         }
172 
173         return (minusRemain == 0) ? 0: relCount + minusRemain;
174     }
175 
176     //
177 
178     //----------------------------------------
179     //
180     //
181 
182     /*
183 
184 
185 
186 
187 
188 
189 
190      */
Await()191     void Await()
192     {
193         const s32 relCountAndSign = m_ReleaseCountAndSign;
194 
195         if( relCountAndSign > 0 )
196         {
197             AwaitImpl(&m_CounterPlus, &m_CounterMinus, relCountAndSign);
198         }
199         else
200         {
201             AwaitImpl(&m_CounterMinus, &m_CounterPlus, - relCountAndSign);
202         }
203     }
204 
205     //
206 
207 private:
AwaitImpl(nn::os::WaitableCounter * pCur,nn::os::WaitableCounter * pNext,s32 relCount)208     void AwaitImpl(nn::os::WaitableCounter* pCur, nn::os::WaitableCounter* pNext, s32 relCount)
209     {
210         IncrementIfLessThan_1 updater;
211 
212         if( (*pCur)->AtomicUpdateConditional(updater) )
213         {
214             pCur->WaitIfLessThan(0);
215         }
216         else
217         {
218             m_ReleaseCountAndSign = - m_ReleaseCountAndSign;
219             **pNext = - relCount;
220             **pCur  = 0;
221             pCur->SignalAll();
222         }
223     }
224 };
225 
226 
227 }} // namespace nn::os
228 
229 #endif // __cplusplus
230 
231 // TODO: Requires an API for C.
232 
233 #endif  // ifndef NN_OS_OS_LIGHTBARRIER_H_
234