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