290 lines
5.9 KiB
C++
290 lines
5.9 KiB
C++
/******************************************************************************
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
Utils_ThreadPool.cpp
|
|
|
|
Abstract:
|
|
This file contains the implementation of classes to wrapper the thread-pooling API.
|
|
|
|
Revision History:
|
|
Davide Massarenti (Dmassare) 04/15/2001
|
|
created
|
|
|
|
******************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
MPC::Pooling::Base::Base()
|
|
{
|
|
// MPC::CComSafeAutoCriticalSection m_cs;
|
|
m_dwInCallback = 0; // DWORD m_dwInCallback;
|
|
m_dwThreadID = 0; // DWORD m_dwThreadID;
|
|
}
|
|
|
|
void MPC::Pooling::Base::Lock()
|
|
{
|
|
m_cs.Lock();
|
|
|
|
if(m_dwInCallback && m_dwThreadID != ::GetCurrentThreadId())
|
|
{
|
|
//
|
|
// Wait for the callback to finish.
|
|
//
|
|
while(m_dwInCallback)
|
|
{
|
|
m_cs.Unlock();
|
|
::Sleep( 1 );
|
|
m_cs.Lock();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MPC::Pooling::Base::Unlock()
|
|
{
|
|
m_cs.Unlock();
|
|
}
|
|
|
|
void MPC::Pooling::Base::AddRef()
|
|
{
|
|
DWORD dwThreadID = ::GetCurrentThreadId();
|
|
|
|
m_cs.Lock();
|
|
|
|
while(m_dwInCallback && m_dwThreadID != dwThreadID)
|
|
{
|
|
m_cs.Unlock();
|
|
::Sleep( 1 );
|
|
m_cs.Lock();
|
|
}
|
|
|
|
m_dwInCallback++;
|
|
m_dwThreadID = dwThreadID;
|
|
|
|
m_cs.Unlock();
|
|
}
|
|
|
|
void MPC::Pooling::Base::Release()
|
|
{
|
|
m_cs.Lock();
|
|
|
|
if(m_dwInCallback) m_dwInCallback--;
|
|
|
|
if(!m_dwInCallback) m_dwThreadID = 0;
|
|
|
|
m_cs.Unlock();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MPC::Pooling::Timer::Timer( /*[in]*/ DWORD dwFlags )
|
|
{
|
|
m_dwFlags = dwFlags; // DWORD m_dwFlags;
|
|
m_hTimer = INVALID_HANDLE_VALUE; // HANDLE m_hTimer;
|
|
}
|
|
|
|
MPC::Pooling::Timer::~Timer()
|
|
{
|
|
(void)Reset();
|
|
}
|
|
|
|
VOID CALLBACK MPC::Pooling::Timer::TimerFunction( PVOID lpParameter, BOOLEAN TimerOrWaitFired )
|
|
{
|
|
MPC::Pooling::Timer* pThis = (MPC::Pooling::Timer*)lpParameter;
|
|
|
|
pThis->AddRef();
|
|
|
|
pThis->Execute( TimerOrWaitFired );
|
|
|
|
pThis->Release();
|
|
}
|
|
|
|
HRESULT MPC::Pooling::Timer::Set( /*[in]*/ DWORD dwTimeout, /*[in]*/ DWORD dwPeriod )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Pooling::Timer::Set" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLockGeneric<Base> lock( this );
|
|
|
|
|
|
//
|
|
// Unfortunately, we cannot hold any lock while trying to destroy the timer...
|
|
//
|
|
while(m_hTimer != INVALID_HANDLE_VALUE)
|
|
{
|
|
lock = NULL;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Reset());
|
|
|
|
lock = this;
|
|
}
|
|
|
|
|
|
if(dwTimeout)
|
|
{
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CreateTimerQueueTimer( &m_hTimer, NULL, TimerFunction, this, dwTimeout, dwPeriod, m_dwFlags ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT MPC::Pooling::Timer::Reset()
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Pooling::Timer::Reset" );
|
|
|
|
HRESULT hr;
|
|
HANDLE hTimer;
|
|
|
|
|
|
//
|
|
// Unfortunately, we cannot hold any lock while trying to destroy the timer...
|
|
//
|
|
Lock();
|
|
|
|
hTimer = m_hTimer;
|
|
m_hTimer = INVALID_HANDLE_VALUE;
|
|
|
|
Unlock();
|
|
|
|
|
|
if(hTimer != INVALID_HANDLE_VALUE)
|
|
{
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::DeleteTimerQueueTimer( NULL, hTimer, INVALID_HANDLE_VALUE ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT MPC::Pooling::Timer::Execute( BOOLEAN TimerOrWaitFired )
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MPC::Pooling::Event::Event( /*[in]*/ DWORD dwFlags )
|
|
{
|
|
// MPC::CComSafeAutoCriticalSection m_cs;
|
|
m_dwFlags = dwFlags; // DWORD m_dwFlags;
|
|
m_hWaitHandle = NULL; // HANDLE m_hWaitHandle;
|
|
m_hEvent = NULL; // HANDLE m_hEvent;
|
|
}
|
|
|
|
MPC::Pooling::Event::~Event()
|
|
{
|
|
(void)Reset();
|
|
}
|
|
|
|
VOID CALLBACK MPC::Pooling::Event::WaitOrTimerFunction( PVOID lpParameter, BOOLEAN TimerOrWaitFired )
|
|
{
|
|
MPC::Pooling::Event* pThis = (MPC::Pooling::Event*)lpParameter;
|
|
|
|
pThis->AddRef();
|
|
|
|
pThis->Signaled( TimerOrWaitFired );
|
|
|
|
pThis->Release();
|
|
}
|
|
|
|
void MPC::Pooling::Event::Attach( /*[in]*/ HANDLE hEvent )
|
|
{
|
|
Reset();
|
|
|
|
Lock();
|
|
|
|
m_hEvent = hEvent;
|
|
|
|
Unlock();
|
|
}
|
|
|
|
HRESULT MPC::Pooling::Event::Set( /*[in]*/ DWORD dwTimeout )
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Pooling::Event::Set" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLockGeneric<Base> lock( this );
|
|
|
|
|
|
//
|
|
// Unfortunately, we cannot hold any lock while trying to destroy the event...
|
|
//
|
|
while(m_hWaitHandle)
|
|
{
|
|
lock = NULL;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Reset());
|
|
|
|
lock = this;
|
|
}
|
|
|
|
if(m_hEvent)
|
|
{
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::RegisterWaitForSingleObject( &m_hWaitHandle, m_hEvent, WaitOrTimerFunction, this, dwTimeout, m_dwFlags ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT MPC::Pooling::Event::Reset()
|
|
{
|
|
__MPC_FUNC_ENTRY( COMMONID, "MPC::Pooling::Event::Reset" );
|
|
|
|
HRESULT hr;
|
|
HANDLE hWaitHandle;
|
|
DWORD dwThreadID;
|
|
|
|
|
|
//
|
|
// Unfortunately, we cannot hold any lock while trying to destroy the event...
|
|
//
|
|
Lock();
|
|
|
|
dwThreadID = m_dwThreadID;
|
|
hWaitHandle = m_hWaitHandle;
|
|
m_hWaitHandle = NULL;
|
|
|
|
Unlock();
|
|
|
|
|
|
if(hWaitHandle)
|
|
{
|
|
if(dwThreadID == ::GetCurrentThreadId()) // Same thread, it would deadlock...
|
|
{
|
|
(void)::UnregisterWaitEx( hWaitHandle, NULL );
|
|
}
|
|
else
|
|
{
|
|
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::UnregisterWaitEx( hWaitHandle, INVALID_HANDLE_VALUE ));
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__MPC_FUNC_CLEANUP;
|
|
|
|
__MPC_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT MPC::Pooling::Event::Signaled( BOOLEAN TimerOrWaitFired )
|
|
{
|
|
return S_FALSE;
|
|
}
|