/*---------------------------------------------------------------------------* Project: Horizon File: os_Alarm.h Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 30270 $ *---------------------------------------------------------------------------*/ /*! @file @brief Alarm に関する API の宣言 :include nn/os.h */ #ifndef NN_OS_OS_ALARM_H_ #define NN_OS_OS_ALARM_H_ #include #include #include #include #include #include typedef void (*nnosAlarmHandler)(void* param, bool cancelled); #ifdef __cplusplus namespace nn { namespace os { /*! @brief アラームで実行されるハンドラを表す型です。 */ typedef void (*AlarmHandler)(void* param, bool cancelled); /*! @brief アラームシステムを初期化します。 この関数は将来的に削除される可能性があります。 */ void InitializeAlarmSystem(s32 priority = 0); size_t GetRequiredMemorySizeForAlarmSystem(void); /*! @brief アラームを扱う為のクラスです。 アラームはOSのタイマ機能を利用し、指定時間経過後にハンドラを呼び出します。 このとき、ハンドラの第1引数はアラームをセットした際の引数、第2引数には false が入って呼ばれます。 (この段落の記述は、将来的に変更されます) このクラスを使用するには、@ref nn::os::InitializeAlarmSystem を先に呼ぶ必要があります。 アラームハンドラの実行は特定のスレッドで行われますが、このスレッドは現時点の実装では 4 本に限られます。 このため、スレッドブロックするなど処理に長い時間がかかるハンドラをたくさん登録すると、 アラームシステムが不安定になります。 (将来変更される記述はここまで) アラームにはワンショットアラームと周期アラームの二種類があります。 ワンショットアラームは @ref SetOneShot でセットし、一定時間後にハンドラが呼ばれます。 ハンドラが開始する前に再度 @ref SetOneShot や @ref SetPeriodic を呼び出すことはできません。 ハンドラ内で再度これらのセット関数を呼ぶことは可能です。 周期アラームは @ref SetPeriodic でセットし、その後一定間隔でハンドラが呼ばれます。 周期アラームが動作している間は再度 @ref SetOneShot や @ref SetPeriodic を呼び出すことはできません。 ハンドラが動作する前にアラームを停止したい場合は、@ref Cancel を呼び出します。 ハンドラが動作し始めていた場合は、@ref Cancel を呼んでも、ハンドラの動作が中断されることはありません。 アラームのセット中(周期アラームやワンショットアラームでハンドルが呼ばれる前)に @ref Cancel が呼ばれた場合、 アラームのハンドラが、第2引数に true を入れて呼び出されます。 */ class Alarm : private nn::os::QueueableWaitTask, private nn::util::NonCopyable { public: /*! @brief オブジェクトを構築します。初期化は行いません。 使用する前に、@ref Initialize を呼んで明示的に初期化する必要があります。 */ Alarm() : m_Handler(0), m_Flags(Flags::Create(false, false, false)), m_Invoker(0) {} /*! @brief オブジェクトを破棄します。 内部的に @ref Finalize を呼びます。 アラームがセット中の場合にこの関数を呼ぶことはできません。 */ virtual ~Alarm(); /*! @brief アラームオブジェクトの初期化をします。 */ void Initialize(); /*! @brief アラームの終了処理をします。 アラームがセット中の場合にこの関数を呼ぶことはできません。 */ void Finalize(); /*! @brief ワンショットアラームを設定します。 time 後にハンドラを一回だけ呼び出します。 @param[in] time ハンドラを呼び出すまでの時間(ns) @param[in] handler アラームのハンドラ @param[in] param ハンドラに与えるパラメータ @return 無し。 */ void SetOneShot(nn::fnd::TimeSpan time, AlarmHandler handler, void* param); template void SetOneShot(nn::fnd::TimeSpan time, void (*handler)(T* param, bool cancelled), T* param); /*! @brief 周期アラームを設定します。 initial 後にハンドラを一回だけ呼び出し、 その後 interval 周期でハンドラを呼び出し続けます。 @param[in] initial 一度目にハンドラを呼び出すまでの時間 @param[in] interval 二度目以降にハンドラを呼び出す間隔 @param[in] handler アラームのハンドラ @param[in] param ハンドラに与えるパラメータ @return 無し。 */ void SetPeriodic(nn::fnd::TimeSpan initial, nn::fnd::TimeSpan interval, AlarmHandler handler, void* param); template void SetPeriodic(nn::fnd::TimeSpan initial, nn::fnd::TimeSpan interval, void (*handler)(T* param, bool cancelled), T* param); /*! @brief 周期アラームを設定します。 interval 周期でハンドラを呼び出し続けます。 @param[in] interval ハンドラを呼び出す間隔 @param[in] handler アラームのハンドラ @param[in] param ハンドラに与えるパラメータ @return 無し。 */ void SetPeriodic(nn::fnd::TimeSpan interval, AlarmHandler handler, void* param) { SetPeriodic(0, interval, handler, param); } template void SetPeriodic(nn::fnd::TimeSpan interval, void (*handler)(T* param, bool cancelled), T* param); /*! @brief 設定済みのアラームを取り消します。 @return 無し。 */ void Cancel(); /*! @brief アラームをセットできる状態であるかどうかを取得します。 アラームが既にセットされており、今後のハンドラ実行予定があるとき flase を返します。 @ref Cancel が呼ばれた後も、一旦ハンドラが呼ばれるまでは true は返しません。 @return アラームがセットできる状態であれば true を返し、そうでなければ false を返します。 */ bool CanSet() const { return !m_Flags.Read().isSet; } private: struct Flags { bool cancelled; bool isOneShot; bool isSet; NN_PADDING1; static Flags Create(bool cancelled, bool isOneShot, bool isSet) { Flags ret = { cancelled, isOneShot, isSet }; return ret; } }; struct CancelFunc; struct InvokeFunc; friend struct CancelFunc; friend struct InvokeFunc; volatile AlarmHandler m_Handler; void* volatile m_Parameter; nn::fnd::InterlockedVariable m_Flags; IWaitTaskInvoker* m_Invoker; Timer m_Timer; virtual void Invoke(); virtual nn::os::WaitObject* GetWaitObject(); }; template inline void Alarm::SetOneShot(nn::fnd::TimeSpan time, void (*handler)(T* param, bool cancelled), T* param) { SetOneShot(time, reinterpret_cast(handler), reinterpret_cast(param)); } template inline void Alarm::SetPeriodic(nn::fnd::TimeSpan initial, nn::fnd::TimeSpan interval, void (*handler)(T*, bool), T* param) { SetPeriodic(initial, interval, reinterpret_cast(handler), reinterpret_cast(param)); } template inline void Alarm::SetPeriodic(nn::fnd::TimeSpan interval, void (*handler)(T*, bool), T* param) { SetPeriodic(interval, reinterpret_cast(handler), reinterpret_cast(param)); } }} // namespace nn::os #endif // __cplusplus // 以下、C 用宣言 #include /*! @addtogroup nn_os os @{ */ /*! @brief 対応する C++ 関数 @ref nn::os::InitializeAlarmSystem を参照してください。 */ NN_EXTERN_C void nnosInitializeAlarmSystem(void); /*! @} */ /*! @addtogroup nn_os os @{ @defgroup nn_os_Alarm_c Alarm (C) @brief @ref nn::os::Alarm の C インタフェースモジュールです。 @details 時間の指定は @ref nn::fnd::TimeSpan の代わりにナノ秒単位で直接指定します。 @{ */ /*! @struct nnosAlarm @brief アラームを表す C の構造体です。 @brief 対応するクラス @ref nn::os::Alarm を参照してください。 */ NN_UTIL_DETAIL_CLIBIMPL_DEFINE_BUFFER_CLASS(nnosAlarm, nn::os::Alarm, 28, u32); /*! @brief 対応する C++ 関数 @ref nn::os::Alarm::Initialize を参照してください。 */ NN_EXTERN_C void nnosAlarmInitialize(nnosAlarm* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Alarm::Finalize を参照してください。 */ NN_EXTERN_C void nnosAlarmFinalize(nnosAlarm* this_); /*! @brief 対応する C++ 関数 @ref nn::os::Alarm::SetOneShot を参照してください。 */ NN_EXTERN_C void nnosAlarmSetOneShot(nnosAlarm* this_, s64 time, nnosAlarmHandler handler, void* param); /*! @brief 対応する C++ 関数 @ref nn::os::Alarm::SetPeriodic を参照してください。 */ NN_EXTERN_C void nnosAlarmSetPeriodic(nnosAlarm* this_, s64 initial, s64 interval, nnosAlarmHandler handler, void* param); /*! @brief 対応する C++ 関数 @ref nn::os::Alarm::Cancel を参照してください。 */ NN_EXTERN_C void nnosAlarmCancel(nnosAlarm* p); /*! @brief 対応する C++ 関数を参照してください。@ref nn::os::Alarm::CanSet */ NN_EXTERN_C bool nnosAlarmCanSet(const nnosAlarm* p); /*! @} @} */ #endif