1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_LightEvent.cpp
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: 46347 $
14 *---------------------------------------------------------------------------*/
15
16 #include <nn/os.h>
17
18 //---------------------------------------------------------------------------
19
20
21 namespace nn {
22 namespace os {
23
Initialize(bool isManualReset)24 void LightEvent::Initialize(bool isManualReset)
25 {
26 m_Lock.Initialize();
27 *m_Counter = isManualReset ? NOT_SIGNALED_MANUAL: NOT_SIGNALED_AUTO;
28 }
29
30 // Get whether flag is set.
TryWait()31 bool LightEvent::TryWait()
32 {
33 if( *m_Counter == SIGNALED_MANUAL )
34 {
35 // The flag is not reset because this is a manual reset.
36 return true;
37 }
38 else
39 {
40 // If the flag is set, reset the flag and return true.
41 return m_Counter->CompareAndSwap(SIGNALED_AUTO, NOT_SIGNALED_AUTO) == SIGNALED_AUTO;
42 }
43 }
44
TryWait(fnd::TimeSpan timeout)45 bool LightEvent::TryWait(fnd::TimeSpan timeout)
46 {
47 switch( *m_Counter )
48 {
49 // Wait for the flag to be set and do not clear the flag.
50 case NOT_SIGNALED_MANUAL:
51 return m_Counter.WaitIfLessThan(0, timeout) == ResultSuccess();
52
53 // Do not wait because the flag is set.
54 case SIGNALED_MANUAL: return true;
55
56 // Wait because the flag is not set.
57 case NOT_SIGNALED_AUTO: break;
58
59 // Do not wait because the flag is set. Reset the flag.
60 case SIGNALED_AUTO:
61 {
62 if( m_Counter->CompareAndSwap(SIGNALED_AUTO, NOT_SIGNALED_AUTO) == SIGNALED_AUTO )
63 {
64 return true;
65 }
66 }
67 break;
68 }
69
70
71 os::Tick begin = os::Tick::GetSystemCurrent();
72 os::Tick end = begin + timeout;
73
74 for(;;)
75 {
76 os::Tick remainTick = end - os::Tick::GetSystemCurrent();
77
78 if( remainTick <= 0 )
79 {
80 return false;
81 }
82
83 Result result = m_Counter.WaitIfLessThan(0, remainTick);
84
85 if( result != ResultSuccess() )
86 {
87 return false;
88 }
89
90 if( *m_Counter == SIGNALED_AUTO )
91 {
92 if( m_Counter->CompareAndSwap(SIGNALED_AUTO, NOT_SIGNALED_AUTO) == SIGNALED_AUTO )
93 {
94 return true;
95 }
96 }
97 }
98 }
99
100 // Wait until the flag is set.
Wait()101 void LightEvent::Wait()
102 {
103 for(;;)
104 {
105 switch( *m_Counter )
106 {
107 // Wait for the flag to be set and do not clear the flag.
108 case NOT_SIGNALED_MANUAL: m_Counter.WaitIfLessThan(0); return;
109
110 // Do not wait because the flag is set.
111 case SIGNALED_MANUAL: return;
112
113 // Wait because the flag is not set.
114 case NOT_SIGNALED_AUTO: break;
115
116 // Do not wait because the flag is set. Reset the flag.
117 case SIGNALED_AUTO:
118 {
119 if( m_Counter->CompareAndSwap(SIGNALED_AUTO, NOT_SIGNALED_AUTO) == SIGNALED_AUTO )
120 {
121 return;
122 }
123 }
124 break;
125 }
126
127 // Wait until the flag is set.
128 // If the flag is set, m_Counter changes from NOT_SIGNALED_AUTO to SIGNALED_AUTO.
129 m_Counter.WaitIfLessThan(0);
130 }
131 }
132
133 // Set the flag.
Signal()134 void LightEvent::Signal()
135 {
136 if( *m_Counter == NOT_SIGNALED_AUTO )
137 {
138 *m_Counter = SIGNALED_AUTO;
139 // In case of auto reset, the thread with the highest priority wakes up.
140 // The flag is reset at the same time the thread wakes up.
141 m_Counter.Signal(1);
142 }
143 else if( *m_Counter == NOT_SIGNALED_MANUAL )
144 {
145 SimpleLock::ScopedLock lock(m_Lock);
146 *m_Counter = SIGNALED_MANUAL;
147 // In case of manual reset, all waiting threads wake up.
148 // The flag is not reset even if the thread wakes up.
149 m_Counter.SignalAll();
150 }
151 // The flag remains unchanged if there is no waiting threads.
152 }
153
154 // Cancel threads waiting for the flag to be set.
Pulse()155 void LightEvent::Pulse()
156 {
157 switch( *m_Counter )
158 {
159 case SIGNALED_MANUAL:
160 {
161 SimpleLock::ScopedLock lock(m_Lock);
162 *m_Counter = NOT_SIGNALED_MANUAL;
163 m_Counter.SignalAll();
164 }
165 break;
166
167 case NOT_SIGNALED_MANUAL:
168 // Wake up all threads waiting for the flag to be set.
169 // The flag is reset at the same time the thread wakes up.
170 m_Counter.SignalAll();
171 break;
172
173 case NOT_SIGNALED_AUTO:
174 // Of the threads waiting for a flag to be set, wakes up the highest priority thread.
175 //
176 // The flag is reset at the same time the thread wakes up.
177 m_Counter.Signal(1);
178 break;
179
180 case SIGNALED_AUTO:
181 // Reset the flag.
182 *m_Counter = NOT_SIGNALED_AUTO;
183 break;
184 }
185 }
186
187 // Clear the flag.
ClearSignal()188 void LightEvent::ClearSignal()
189 {
190 if( *m_Counter == SIGNALED_MANUAL )
191 {
192 SimpleLock::ScopedLock lock(m_Lock);
193 *m_Counter = NOT_SIGNALED_MANUAL;
194 }
195 else if( *m_Counter == SIGNALED_AUTO )
196 {
197 *m_Counter = NOT_SIGNALED_AUTO;
198 }
199 }
200
201 }
202 }
203
204
205
206 using namespace nn;
207
208
209 // C Function Definitions
210
211 #include <new>
212
213 using namespace nn::os;
214
215 extern "C" {
216
nnosLightEventInitialize(nnosLightEvent * p,bool isManualReset)217 void nnosLightEventInitialize(nnosLightEvent* p, bool isManualReset)
218 {
219 new (p) LightEvent(isManualReset);
220 }
221
nnosLightEventIsSignaled(nnosLightEvent * p)222 bool nnosLightEventIsSignaled(nnosLightEvent* p)
223 {
224 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
225 return pLightEvent->IsSignaled();
226 }
227
nnosLightEventIsManualReset(nnosLightEvent * p)228 bool nnosLightEventIsManualReset(nnosLightEvent* p)
229 {
230 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
231 return pLightEvent->IsManualReset();
232 }
233
nnosLightEventTryWait(nnosLightEvent * p)234 bool nnosLightEventTryWait(nnosLightEvent* p)
235 {
236 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
237 return pLightEvent->TryWait();
238 }
239
nnosLightEventWait(nnosLightEvent * p)240 void nnosLightEventWait(nnosLightEvent* p)
241 {
242 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
243 pLightEvent->Wait();
244 }
245
nnosLightEventSignal(nnosLightEvent * p)246 void nnosLightEventSignal(nnosLightEvent* p)
247 {
248 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
249 pLightEvent->Signal();
250 }
251
nnosLightEventPulse(nnosLightEvent * p)252 void nnosLightEventPulse(nnosLightEvent* p)
253 {
254 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
255 pLightEvent->Pulse();
256 }
257
nnosLightEventClearSignal(nnosLightEvent * p)258 void nnosLightEventClearSignal(nnosLightEvent* p)
259 {
260 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
261 pLightEvent->ClearSignal();
262 }
263
nnosLightEventFinalize(nnosLightEvent * p)264 void nnosLightEventFinalize(nnosLightEvent* p)
265 {
266 LightEvent* pLightEvent = reinterpret_cast<LightEvent*>(p);
267 pLightEvent->Finalize();
268 pLightEvent->~LightEvent();
269 }
270
271 } // extern "C"
272