1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_Alarm.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: 30270 $
14  *---------------------------------------------------------------------------*/
15 
16 /*! @file
17     @brief      Alarm に関する API の宣言
18 
19     :include nn/os.h
20 */
21 
22 #ifndef NN_OS_OS_ALARM_H_
23 #define NN_OS_OS_ALARM_H_
24 
25 #include <nn/os/os_ThreadPool.h>
26 #include <nn/os/os_Thread.h>
27 #include <nn/fnd/fnd_TimeSpan.h>
28 #include <nn/os/os_Timer.h>
29 #include <nn/util/util_NonCopyable.h>
30 #include <nn/fnd/fnd_Interlocked.h>
31 
32 typedef void (*nnosAlarmHandler)(void* param, bool cancelled);
33 
34 #ifdef __cplusplus
35 
36 namespace nn { namespace os {
37 
38 /*!
39   @brief アラームで実行されるハンドラを表す型です。
40 */
41 typedef void (*AlarmHandler)(void* param, bool cancelled);
42 
43 /*!
44     @brief アラームシステムを初期化します。
45 
46            この関数は将来的に削除される可能性があります。
47 */
48 void InitializeAlarmSystem(s32 priority = 0);
49 
50 size_t GetRequiredMemorySizeForAlarmSystem(void);
51 
52 /*!
53     @brief アラームを扱う為のクラスです。
54 
55     アラームはOSのタイマ機能を利用し、指定時間経過後にハンドラを呼び出します。
56     このとき、ハンドラの第1引数はアラームをセットした際の引数、第2引数には false が入って呼ばれます。
57 
58     (この段落の記述は、将来的に変更されます)
59     このクラスを使用するには、@ref nn::os::InitializeAlarmSystem を先に呼ぶ必要があります。
60     アラームハンドラの実行は特定のスレッドで行われますが、このスレッドは現時点の実装では 4 本に限られます。
61     このため、スレッドブロックするなど処理に長い時間がかかるハンドラをたくさん登録すると、
62     アラームシステムが不安定になります。
63     (将来変更される記述はここまで)
64 
65     アラームにはワンショットアラームと周期アラームの二種類があります。
66 
67     ワンショットアラームは @ref SetOneShot でセットし、一定時間後にハンドラが呼ばれます。
68     ハンドラが開始する前に再度 @ref SetOneShot や @ref SetPeriodic を呼び出すことはできません。
69     ハンドラ内で再度これらのセット関数を呼ぶことは可能です。
70 
71     周期アラームは @ref SetPeriodic でセットし、その後一定間隔でハンドラが呼ばれます。
72     周期アラームが動作している間は再度 @ref SetOneShot や @ref SetPeriodic を呼び出すことはできません。
73 
74     ハンドラが動作する前にアラームを停止したい場合は、@ref Cancel を呼び出します。
75     ハンドラが動作し始めていた場合は、@ref Cancel を呼んでも、ハンドラの動作が中断されることはありません。
76     アラームのセット中(周期アラームやワンショットアラームでハンドルが呼ばれる前)に @ref Cancel が呼ばれた場合、
77     アラームのハンドラが、第2引数に true を入れて呼び出されます。
78 
79 */
80 class Alarm : private nn::os::QueueableWaitTask, private nn::util::NonCopyable<Alarm>
81 {
82 public:
83 
84     /*!
85       @brief        オブジェクトを構築します。初期化は行いません。
86                     使用する前に、@ref Initialize を呼んで明示的に初期化する必要があります。
87     */
Alarm()88     Alarm() : m_Handler(0), m_Flags(Flags::Create(false, false, false)), m_Invoker(0) {}
89 
90     /*!
91       @brief        オブジェクトを破棄します。
92                     内部的に @ref Finalize を呼びます。
93                     アラームがセット中の場合にこの関数を呼ぶことはできません。
94     */
95     virtual ~Alarm();
96 
97     /*!
98       @brief        アラームオブジェクトの初期化をします。
99     */
100     void Initialize();
101 
102     /*!
103       @brief        アラームの終了処理をします。
104                     アラームがセット中の場合にこの関数を呼ぶことはできません。
105     */
106     void Finalize();
107 
108     /*!
109       @brief        ワンショットアラームを設定します。
110                     time 後にハンドラを一回だけ呼び出します。
111 
112       @param[in]    time        ハンドラを呼び出すまでの時間(ns)
113       @param[in]    handler     アラームのハンドラ
114       @param[in]    param       ハンドラに与えるパラメータ
115 
116       @return       無し。
117 
118     */
119     void SetOneShot(nn::fnd::TimeSpan time, AlarmHandler handler, void* param);
120 
121     template <typename T>
122     void SetOneShot(nn::fnd::TimeSpan time, void (*handler)(T* param, bool cancelled), T* param);
123 
124     /*!
125       @brief        周期アラームを設定します。
126                     initial 後にハンドラを一回だけ呼び出し、
127                     その後 interval 周期でハンドラを呼び出し続けます。
128 
129       @param[in]    initial     一度目にハンドラを呼び出すまでの時間
130       @param[in]    interval    二度目以降にハンドラを呼び出す間隔
131       @param[in]    handler     アラームのハンドラ
132       @param[in]    param       ハンドラに与えるパラメータ
133 
134       @return       無し。
135 
136     */
137     void SetPeriodic(nn::fnd::TimeSpan initial, nn::fnd::TimeSpan interval, AlarmHandler handler, void* param);
138 
139     template <typename T>
140     void SetPeriodic(nn::fnd::TimeSpan initial, nn::fnd::TimeSpan interval, void (*handler)(T* param, bool cancelled), T* param);
141 
142     /*!
143       @brief        周期アラームを設定します。
144                     interval 周期でハンドラを呼び出し続けます。
145 
146       @param[in]    interval    ハンドラを呼び出す間隔
147       @param[in]    handler     アラームのハンドラ
148       @param[in]    param       ハンドラに与えるパラメータ
149 
150       @return       無し。
151 
152     */
SetPeriodic(nn::fnd::TimeSpan interval,AlarmHandler handler,void * param)153     void SetPeriodic(nn::fnd::TimeSpan interval, AlarmHandler handler, void* param) { SetPeriodic(0, interval, handler, param); }
154 
155     template <typename T>
156     void SetPeriodic(nn::fnd::TimeSpan interval, void (*handler)(T* param, bool cancelled), T* param);
157 
158     /*!
159       @brief        設定済みのアラームを取り消します。
160 
161       @return       無し。
162 
163     */
164     void Cancel();
165 
166     /*!
167       @brief        アラームをセットできる状態であるかどうかを取得します。
168 
169                     アラームが既にセットされており、今後のハンドラ実行予定があるとき flase を返します。
170                     @ref Cancel が呼ばれた後も、一旦ハンドラが呼ばれるまでは true は返しません。
171 
172       @return       アラームがセットできる状態であれば true を返し、そうでなければ false を返します。
173     */
CanSet()174     bool CanSet() const { return !m_Flags.Read().isSet; }
175 
176 private:
177 
178     struct Flags
179     {
180         bool cancelled;
181         bool isOneShot;
182         bool isSet;
183         NN_PADDING1;
184 
CreateFlags185         static Flags Create(bool cancelled, bool isOneShot, bool isSet)
186         {
187             Flags ret = { cancelled, isOneShot, isSet };
188             return ret;
189         }
190     };
191 
192     struct CancelFunc;
193     struct InvokeFunc;
194     friend struct CancelFunc;
195     friend struct InvokeFunc;
196 
197     volatile AlarmHandler m_Handler;
198     void* volatile m_Parameter;
199     nn::fnd::InterlockedVariable<Flags> m_Flags;
200     IWaitTaskInvoker* m_Invoker;
201     Timer m_Timer;
202 
203     virtual void Invoke();
204     virtual nn::os::WaitObject* GetWaitObject();
205 };
206 
207 template <typename T>
SetOneShot(nn::fnd::TimeSpan time,void (* handler)(T * param,bool cancelled),T * param)208 inline void Alarm::SetOneShot(nn::fnd::TimeSpan time, void (*handler)(T* param, bool cancelled), T* param)
209 {
210     SetOneShot(time, reinterpret_cast<AlarmHandler&>(handler), reinterpret_cast<void*&>(param));
211 }
212 
213 template <typename T>
SetPeriodic(nn::fnd::TimeSpan initial,nn::fnd::TimeSpan interval,void (* handler)(T *,bool),T * param)214 inline void Alarm::SetPeriodic(nn::fnd::TimeSpan initial, nn::fnd::TimeSpan interval, void (*handler)(T*, bool), T* param)
215 {
216     SetPeriodic(initial, interval, reinterpret_cast<AlarmHandler&>(handler), reinterpret_cast<void*&>(param));
217 }
218 
219 template <typename T>
SetPeriodic(nn::fnd::TimeSpan interval,void (* handler)(T *,bool),T * param)220 inline void Alarm::SetPeriodic(nn::fnd::TimeSpan interval, void (*handler)(T*, bool), T* param)
221 {
222     SetPeriodic(interval, reinterpret_cast<AlarmHandler&>(handler), reinterpret_cast<void*&>(param));
223 }
224 
225 }} // namespace nn::os
226 
227 #endif // __cplusplus
228 
229 
230 // 以下、C 用宣言
231 
232 #include <nn/util/detail/util_CLibImpl.h>
233 
234 /*!
235   @addtogroup   nn_os               os
236   @{
237 */
238 
239 /*!
240   @brief 対応する C++ 関数 @ref nn::os::InitializeAlarmSystem を参照してください。
241 */
242 NN_EXTERN_C void nnosInitializeAlarmSystem(void);
243 
244 /*!
245   @}
246 */
247 
248 
249 /*!
250   @addtogroup   nn_os               os
251   @{
252 
253   @defgroup     nn_os_Alarm_c       Alarm (C)
254 
255   @brief        @ref nn::os::Alarm の C インタフェースモジュールです。
256 
257   @details      時間の指定は @ref nn::fnd::TimeSpan の代わりにナノ秒単位で直接指定します。
258 
259   @{
260 */
261 
262 /*!
263   @struct       nnosAlarm
264   @brief        アラームを表す C の構造体です。
265 
266   @brief 対応するクラス @ref nn::os::Alarm を参照してください。
267 */
268 NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosAlarm, nn::os::Alarm, 28, u32);
269 
270 /*!
271   @brief 対応する C++ 関数 @ref nn::os::Alarm::Initialize を参照してください。
272 */
273 NN_EXTERN_C void nnosAlarmInitialize(nnosAlarm* this_);
274 
275 /*!
276   @brief 対応する C++ 関数 @ref nn::os::Alarm::Finalize を参照してください。
277 */
278 NN_EXTERN_C void nnosAlarmFinalize(nnosAlarm* this_);
279 
280 /*!
281   @brief 対応する C++ 関数 @ref nn::os::Alarm::SetOneShot を参照してください。
282 */
283 NN_EXTERN_C void nnosAlarmSetOneShot(nnosAlarm* this_, s64 time, nnosAlarmHandler handler, void* param);
284 
285 /*!
286   @brief 対応する C++ 関数 @ref nn::os::Alarm::SetPeriodic を参照してください。
287 */
288 NN_EXTERN_C void nnosAlarmSetPeriodic(nnosAlarm* this_, s64 initial, s64 interval, nnosAlarmHandler handler, void* param);
289 
290 /*!
291   @brief 対応する C++ 関数 @ref nn::os::Alarm::Cancel を参照してください。
292 */
293 NN_EXTERN_C void nnosAlarmCancel(nnosAlarm* p);
294 
295 /*!
296   @brief 対応する C++ 関数を参照してください。@ref          nn::os::Alarm::CanSet
297 */
298 NN_EXTERN_C bool nnosAlarmCanSet(const nnosAlarm* p);
299 
300 /*!
301   @}
302 
303   @}
304 */
305 
306 #endif
307