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); } } }