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