// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// Timer.cpp
//
// Shared timer implementation.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
#pragma warning (disable : 4702)
namespace Concurrency
{
namespace details
{
///
/// A stub class that is friends with _Timer in order to avoid pulling in too many windows.h definitions into agents.h.
///
class _TimerStub
{
public:
///
/// Timer callback for Vista and above (except MSDK)
///
static void CALLBACK FireTimer(PTP_CALLBACK_INSTANCE, void* context, PTP_TIMER)
{
FireTimerXP(context, true);
}
///
/// Timer callback for XP and MSDK
///
static void CALLBACK FireTimerXP(PVOID pContext, BOOLEAN)
{
_Timer* pTimer = reinterpret_cast<_Timer *>(pContext);
pTimer->_Fire();
// Do not delete the timer - it will be deleted in the destructor
}
};
///
/// Constructs a new timer.
///
///
/// The duration and period of the timer in milliseconds.
///
///
/// An indication of whether the timer is repeating (periodic) or not.
///
_Timer::_Timer(unsigned int _Ms, bool _FRepeating)
: _M_hTimer(NULL)
, _M_ms(_Ms)
, _M_fRepeating(_FRepeating)
{
}
///
/// Starts the timer.
///
void _Timer::_Start()
{
if (_M_hTimer == NULL)
{
if ((_M_hTimer = RegisterAsyncTimerAndLoadLibrary(_M_ms, &_TimerStub::FireTimer, this, _M_fRepeating)) == nullptr)
{
throw std::bad_alloc();
}
}
}
///
/// Destroys the timer.
///
_Timer::~_Timer()
{
if (_M_hTimer != NULL)
_Stop();
}
///
/// Stops the timer.
///
void _Timer::_Stop()
{
DeleteAsyncTimerAndUnloadLibrary(static_cast(_M_hTimer));
_M_hTimer = NULL;
}
} // namespace details
///
/// Wait for a specified number of milliseconds
///
_CONCRTIMP void __cdecl wait(unsigned int milliseconds)
{
if (milliseconds < 1)
{
Context::Yield();
}
else
{
class TimerObj : public _Timer
{
public:
TimerObj(unsigned int mS) : _Timer(mS, false)
{
m_pContext = Context::CurrentContext();
_Start();
Context::Block();
}
private:
virtual void _Fire()
{
m_pContext->Unblock();
}
Context *m_pContext;
} _t(milliseconds);
}
}
} // namespace Concurrency