示例#1
0
DWORD
CNdasEventMonitor::OnTaskStart()
{
	
	BOOL bTerminateThread(FALSE);

	// 15 sec = 10,000,000 nanosec
	// negative value means relative time
	LARGE_INTEGER liDueTime;
	liDueTime.QuadPart = - 10 * 1000 * 1000;

	BOOL fSuccess = ::SetWaitableTimer(
		m_hHeartbeatMonitorTimer, 
		&liDueTime, 
		HEARTBEAT_MONITOR_INTERVAL, 
		NULL, 
		NULL, 
		FALSE);

	if (!fSuccess) {
		DPErrorEx(_FT("Setting waitable timer failed: "));
	}

	do {

		//
		// Lock against m_vLogDevice set change
		//
		this->Lock();

		DWORD dwLogDevices = m_vLogDevices.size();
		DWORD dwHandles = 3 + 2 * dwLogDevices;
		HANDLE* hWaitingHandles = new HANDLE[dwHandles];

		hWaitingHandles[0] = m_hTaskTerminateEvent;
		hWaitingHandles[1] = m_hLogDeviceSetChangeEvent;
		hWaitingHandles[2] = m_hHeartbeatMonitorTimer;

		PCNdasLogicalDeviceVector::const_iterator itr = m_vLogDevices.begin();
		for (DWORD i = 3; itr != m_vLogDevices.end(); ++itr, ++i) {
			PCNdasLogicalDevice pLogDevice = *itr;
			hWaitingHandles[i] = pLogDevice->GetDisconnectEvent();
			hWaitingHandles[dwLogDevices + i] = pLogDevice->GetAlarmEvent();
		}
 		this->Unlock();

		fSuccess = ::ResetEvent(m_hLogDeviceSetChangeEvent);
		_ASSERTE(fSuccess);

		BOOL bResetLogDeviceSet(FALSE);

		do {

			DWORD dwWaitResult = ::WaitForMultipleObjects(
				dwHandles, 
				hWaitingHandles, 
				FALSE, 
				INFINITE);

			if (WAIT_OBJECT_0 == dwWaitResult) {
				//
				// Terminate Thread Event
				//
				bTerminateThread = TRUE;
			} else if (WAIT_OBJECT_0 + 1 == dwWaitResult) {
				//
				// LogicalDeviceSetChange Event
				//
				bResetLogDeviceSet = TRUE;
			} else if (WAIT_OBJECT_0 + 2 == dwWaitResult) {

				ximeta::CAutoLock autolock(this);

				//
				// Heartbeat Monitor Timer Event
				//
				PCNdasDeviceSet::const_iterator devitr = m_hbMonDevices.begin();
				m_bIterating = TRUE;
				for (; devitr != m_hbMonDevices.end();) {
					PCNdasDevice pDevice = *devitr;
					BOOL fDetach = pDevice->OnStatusCheck();
					if (fDetach) {
						devitr = m_hbMonDevices.erase(devitr);
						pDevice->Release();
					} else {
						++devitr;
					}
				}
				m_bIterating = FALSE;

				//
				// Check the logical devices
				//
				std::for_each(
					m_vLogDevices.begin(),
					m_vLogDevices.end(),
					NdasLogicalDeviceStatusCheck);

			} else if (WAIT_OBJECT_0 + 3 <= dwWaitResult &&
				dwWaitResult < WAIT_OBJECT_0 + 3 + dwLogDevices)
			{
				//
				// Disconnect Event
				//
				DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3);
				BOOL fHandled = OnLogicalDeviceDisconnected(n);
				if (!fHandled) {
					fSuccess = ::ResetEvent(hWaitingHandles[dwWaitResult - WAIT_OBJECT_0]);
					_ASSERTE(fSuccess);
				}

			} else if (WAIT_OBJECT_0 + 3 + dwLogDevices <= dwWaitResult &&
				dwWaitResult < WAIT_OBJECT_0 + 3 + 2 * dwLogDevices)
			{
				//
				// Alarm Event
				//
				DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3 + dwLogDevices);
				BOOL fHandled = OnLogicalDeviceAlarmed(n);
				if (!fHandled) {
					fSuccess = ::ResetEvent(hWaitingHandles[dwWaitResult - WAIT_OBJECT_0]);
					_ASSERTE(fSuccess);
				}

			} else {
//				_ASSERTE(FALSE);
				// Some handles may be already invalid.
				// LogicalDeviceSetChange Event
				//
				bResetLogDeviceSet = TRUE;
				DPErrorEx(_FT("Wait failed: "));
			}

		} while (!bResetLogDeviceSet && !bTerminateThread);

		delete [] hWaitingHandles;

	} while (!bTerminateThread);

	fSuccess = ::CancelWaitableTimer(m_hHeartbeatMonitorTimer);
	if (!fSuccess) {
		DPErrorEx(_FT("Canceling waitable timer failed: "));
	}

	return 0;
}
DWORD
CNdasEventMonitor::ThreadStart(HANDLE hStopEvent)
{
	CCoInitialize coinit(COINIT_MULTITHREADED);

	// 15 sec = 10,000,000 nanosec
	// negative value means relative time
	LARGE_INTEGER liDueTime;
	liDueTime.QuadPart = - 10 * 1000 * 1000;

	BOOL success = ::SetWaitableTimer(
		m_HeartbeatMonitorTimer, 
		&liDueTime, 
		HEARTBEAT_MONITOR_INTERVAL, 
		NULL, 
		NULL, 
		FALSE);

	if (!success) 
	{
		XTLTRACE2(NDASSVC_EVENTMON, TRACE_LEVEL_ERROR,
			"Setting waitable timer failed, error=0x%X\n", GetLastError());
	}

	XTLVERIFY( ::ResetEvent(m_NdasLogicalUnitSetChanged) );

	std::vector<HANDLE> waitHandles;
	waitHandles.reserve(20);

	// Lock-free copy of the devices and logDevices
	CInterfaceArray<INdasDevice> ndasDevices;
	CInterfaceArray<INdasLogicalUnit> ndasLogicalUnits;

	while (true)
	{
		//
		// Copy m_NdasDevices and m_NdasLogicalUnits to devices and logDevices
		// for lock free accesses
		//
		// DEVICE READER LOCK REGION
		{
			XTL::CReaderLockHolder holder(m_NdasDeviceDataLock);
			ndasDevices.Copy(m_NdasDevices);
		}
		{
			XTL::CReaderLockHolder holder(m_NdasLogicalUnitDataLock);
			ndasLogicalUnits.Copy(m_NdasLogicalUnits);
		}
		// DEVICE READER LOCK REGION

		//
		// Recreate wait handles
		//
		size_t ndasLogicalUnitCount = ndasLogicalUnits.GetCount();
		waitHandles.resize(3 + ndasLogicalUnitCount * 2);

		waitHandles[0] = hStopEvent;
		waitHandles[1] = m_NdasLogicalUnitSetChanged;
		waitHandles[2] = m_HeartbeatMonitorTimer;

		// Disconnect events i=[3 ...3+nLogDevices)
		// Alarm Events events i=[3+nLogDevices ... 3+2*nLogDevices)
		for (size_t index = 0; index < ndasLogicalUnitCount; ++index)
		{
			INdasLogicalUnit* pNdasLogicalUnit = ndasLogicalUnits.GetAt(index);
			waitHandles[3 + index] = 
				NdasLogicalUnitDisconnectEvent()(pNdasLogicalUnit);
			waitHandles[3 + index + ndasLogicalUnitCount] = 
				NdasLogicalUnitAlarmEvent()(pNdasLogicalUnit);
		}

		DWORD nWaitHandles = waitHandles.size();

		DWORD waitResult = ::WaitForMultipleObjects(
			nWaitHandles, 
			&waitHandles[0], 
			FALSE, 
			INFINITE);

		if (WAIT_OBJECT_0 == waitResult)
		{
			// Terminate Thread Event
			XTLVERIFY( ::CancelWaitableTimer(m_HeartbeatMonitorTimer) );
			return 0;
		}
		else if (WAIT_OBJECT_0 + 1 == waitResult) 
		{
			// Logical device set change event
			XTLVERIFY( ::ResetEvent(m_NdasLogicalUnitSetChanged) );
			continue;
		} 
		else if (WAIT_OBJECT_0 + 2 == waitResult) 
		{
			// Heartbeat Monitor Timer Event
			AtlForEach(ndasDevices, InvokeTimerEventSink<INdasDevice>());
			AtlForEach(ndasLogicalUnits, InvokeTimerEventSink<INdasLogicalUnit>());
		}
		else if (
			waitResult >= WAIT_OBJECT_0 + 3 &&
			waitResult < WAIT_OBJECT_0 + 3 + ndasLogicalUnitCount)
		{
			XTLVERIFY( ::ResetEvent(waitHandles[waitResult - WAIT_OBJECT_0]) );
			// Disconnect Event
			DWORD n = waitResult - (WAIT_OBJECT_0 + 3);
			OnLogicalDeviceDisconnected(ndasLogicalUnits[n]);
		} 
		else if (
			waitResult >= WAIT_OBJECT_0 + 3 + ndasLogicalUnitCount &&
			waitResult < WAIT_OBJECT_0 + 3 + 2 * ndasLogicalUnitCount)
		{
			XTLVERIFY( ::ResetEvent(waitHandles[waitResult - WAIT_OBJECT_0]) );
			// Alarm Event
			DWORD n = waitResult - (WAIT_OBJECT_0 + 3 + ndasLogicalUnitCount);
			OnLogicalDeviceAlarmed(ndasLogicalUnits[n]);
		}
		else 
		{
			XTLASSERT(FALSE);
		}
	}
}