/*++ Copyright (C) 1999-2001 Microsoft Corporation Module Name: RESYNC2.CPP Abstract: implements the listener for WDM events and events for sync-up with IdleTask History: ivanbrug 01-Oct-2000 changed for svchost migration --*/ #include "precomp.h" #include #include #include #include "WinMgmt.h" #include #include #include #include #include "resync2.h" #include "wbemdelta.h" // for DeltaDredge #include "arrtempl.h" // // // this is because WDMLib is __BADLY__ DESIGNED // ///////////////////////////////////////////////////////////// void WINAPI EventCallbackRoutine(PWNODE_HEADER WnodeHeader, ULONG_PTR Context) { return; } // // // This class listens on WDM events // ///////////////////////////////////////////////////////////// CWDMListener::CWDMListener(): m_dwSignature(SIG_WDMEVENTS_FREE), m_hEventAdd(NULL), m_hEventRem(NULL), m_hWaitAdd(NULL), m_hWaitRem(NULL), m_UnInited(TRUE), m_GuidAdd(GUID_MOF_RESOURCE_ADDED_NOTIFICATION), m_GuidRem(GUID_MOF_RESOURCE_REMOVED_NOTIFICATION) { } DWORD CWDMListener::OpenAdd() { DWORD dwErr; dwErr = WmiOpenBlock(&m_GuidAdd, WMIGUID_NOTIFICATION | SYNCHRONIZE, &m_hEventAdd); if (ERROR_SUCCESS == dwErr) { if (RegisterWaitForSingleObject(&m_hWaitAdd, m_hEventAdd, CWDMListener::EvtCallBackAdd, this, INFINITE, WT_EXECUTEONLYONCE)) { return ERROR_SUCCESS; } else { dwErr = GetLastError(); } } else { dwErr = GetLastError(); } // if here, some errors CloseAdd(); return dwErr; } DWORD CWDMListener::OpenRemove() { DWORD dwRet; dwRet = WmiOpenBlock(&m_GuidRem, WMIGUID_NOTIFICATION | SYNCHRONIZE, &m_hEventRem); if (ERROR_SUCCESS == dwRet) { if (RegisterWaitForSingleObject(&m_hWaitRem, m_hEventRem, CWDMListener::EvtCallBackRem, this, INFINITE, WT_EXECUTEONLYONCE)) { return ERROR_SUCCESS; } else { dwRet = GetLastError(); } } else { dwRet = GetLastError(); } CloseRemove(); return dwRet; } DWORD CWDMListener::CloseAdd() { if (m_hWaitAdd) { UnregisterWaitEx(m_hWaitAdd,NULL); m_hWaitAdd = NULL; } if (m_hEventAdd) { WmiCloseBlock(m_hEventAdd); m_hEventAdd = NULL; } return 0; } DWORD CWDMListener::CloseRemove() { if (m_hWaitRem) { UnregisterWaitEx(m_hWaitRem,NULL); m_hWaitRem = NULL; } if (m_hEventRem) { WmiCloseBlock(m_hEventRem); m_hEventRem = NULL; } return 0; } VOID CWDMListener::Unregister() { CInCritSec ics(&m_cs); if (m_UnInited) return; CloseAdd(); CloseRemove(); m_dwSignature = SIG_WDMEVENTS_FREE; m_UnInited = TRUE; } CWDMListener::~CWDMListener() { Unregister(); } DWORD CWDMListener::Register() { CInCritSec ics(&m_cs); if (!m_UnInited) // prevent multiple calls return 0; if (ERROR_SUCCESS == OpenAdd() && ERROR_SUCCESS == OpenRemove()) { m_dwSignature = SIG_WDMEVENTS_BUSY; m_UnInited = FALSE; } return GetLastError(); } VOID NTAPI CWDMListener::EvtCallBackAdd(VOID * pContext,BOOLEAN bTimerFired) { if (!GLOB_Monitor_IsRegistred()) return; CWDMListener * pThis = (CWDMListener *)pContext; if (NULL == pThis) return; if (SIG_WDMEVENTS_BUSY != pThis->m_dwSignature) return; pThis->EvtCallThis(bTimerFired,Type_Added); // // we have process the WDM event // since we are in the RtlpWorkerThread and // we are registred with WT_EXECUTEONLYONCE // REDO FROM START // { CInCritSec ics(&pThis->m_cs); if (ERROR_SUCCESS == pThis->CloseAdd()) { pThis->OpenAdd(); } } } VOID NTAPI CWDMListener::EvtCallBackRem(VOID * pContext,BOOLEAN bTimerFired) { if (!GLOB_Monitor_IsRegistred()) return; CWDMListener * pThis = (CWDMListener *)pContext; if (NULL == pThis) return; if (SIG_WDMEVENTS_BUSY != pThis->m_dwSignature) return; pThis->EvtCallThis(bTimerFired,Type_Removed); // // we have process the WDM event // since we are in the RtlpWorkerThread and // we are registred with WT_EXECUTEONLYONCE // REDO FROM START // { CInCritSec ics(&pThis->m_cs); if (ERROR_SUCCESS == pThis->CloseRemove()) { pThis->OpenRemove(); } } } VOID CWDMListener::EvtCallThis(BOOLEAN bTimerFired, int Type) { if (bTimerFired) { _DBG_ASSERT(FALSE); } else { if (m_UnInited) return; DWORD dwRet; if (Type_Added == Type) { dwRet = WmiReceiveNotifications(1,&m_hEventAdd,CWDMListener::WmiCallBack,(ULONG_PTR)this); } else if (Type_Removed == Type) { dwRet = WmiReceiveNotifications(1,&m_hEventRem,CWDMListener::WmiCallBack,(ULONG_PTR)this); } } } VOID WINAPI CWDMListener::WmiCallBack(PWNODE_HEADER Wnode, UINT_PTR NotificationContext) { // pThis is checked in the EventCallBack CWDMListener * pThis = (CWDMListener *)NotificationContext; #ifdef DEBUG_ADAP WCHAR pszClsID[40]; StringFromGUID2(Wnode->Guid,pszClsID,40); DBG_PRINTFA((pBuff,"Flag %08x ProvId %08x %p GUID %S\n", Wnode->Flags,Wnode->ProviderId,(ULONG_PTR)Wnode->ClientContext,pszClsID)); if (WNODE_FLAG_ALL_DATA & Wnode->Flags) { WNODE_ALL_DATA * pAllData = (WNODE_ALL_DATA *)Wnode; DWORD i; for (i=0;iInstanceCount;i++) { WCHAR pTmpBuff[MAX_PATH+1]; pTmpBuff[MAX_PATH] = 0; DWORD dwSize = (pAllData->OffsetInstanceDataAndLength[i].LengthInstanceData>MAX_PATH)?MAX_PATH:pAllData->OffsetInstanceDataAndLength[i].LengthInstanceData; memcpy(pTmpBuff,(BYTE*)pAllData+pAllData->OffsetInstanceDataAndLength[i].OffsetInstanceData,dwSize); DBG_PRINTFA((pBuff,"%d - %S\n",i,pTmpBuff)); } }; #endif #ifdef DBG if (!HeapValidate(GetProcessHeap(),0,NULL)) { DebugBreak(); } if (!HeapValidate(CWin32DefaultArena::GetArenaHeap(),0,NULL)) { DebugBreak(); } #endif CWMIBinMof WMIBinMof; //============================================================================= // Note: this combo will always succeed, as all the initialize is doing is // setting a flag to FALSE and returning S_OK //============================================================================= if( SUCCEEDED( WMIBinMof.Initialize(NULL,FALSE)) ) { if (WMIBinMof.BinaryMofEventChanged(Wnode)) { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"---- WMIBinMof.BinaryMofEventChanged == CHANGED ----\n")); #endif DEBUGTRACE((LOG_WINMGMT,"WDM event && WMIBinMof.BinaryMofEventChanged == TRUE\n")); ResyncPerf(RESYNC_TYPE_WDMEVENT); #ifdef DBG if (!HeapValidate(GetProcessHeap(),0,NULL)) { DebugBreak(); } if (!HeapValidate(CWin32DefaultArena::GetArenaHeap(),0,NULL)) { DebugBreak(); } #endif } else { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"---- WMIBinMof.BinaryMofEventChanged == NOT CHANGED ----\n")); #endif } } return; } CCounterEvts::CCounterEvts(): m_dwSignature(SIG_COUNTEEVENTS_BUSY), m_LoadCtrEvent(NULL), m_UnloadCtrEvent(NULL), m_Uninited(TRUE), m_WaitLoadCtr(NULL), m_WaitUnloadCtr(NULL), m_hWmiReverseAdapSetLodCtr(NULL), m_hWmiReverseAdapLodCtrDone(NULL), m_hPendingTasksStart(NULL), m_hPendingTasksComplete(NULL) { } // // allows localsystem to use the event // // // SDDL: L"O:SYG:SYD:(A;;0x1f0003;;;SY)" // DWORD g_LocalSystemSD[] = { 0x80040001, 0x00000014, 0x00000020, 0x00000000, 0x0000002c, 0x00000101, 0x05000000, 0x00000012, 0x00000101, 0x05000000, 0x00000012, 0x00300002, 0x00000001, 0x00140000, 0x001f0003, 0x00000101, 0x05000000, 0x00000012, 0x00000000, 0x00000000 }; // // allow administrators and localsystem to use the event // // // SDDL: L"O:SYG:SYD:(A;;0x1f0003;;;SY)(A;;0x1f0003;;;BA)" // DWORD g_LocalSystemAdminsSD[] = { 0x80040001, 0x00000014, 0x00000020, 0x00000000, 0x0000002c, 0x00000101, 0x05000000, 0x00000012, 0x00000101, 0x05000000, 0x00000012, 0x00340002, 0x00000002, 0x00140000, 0x001f0003, 0x00000101, 0x05000000, 0x00000012, 0x00180000, 0x001f0003, 0x00000201, 0x05000000, 0x00000020, 0x00000220 }; DWORD CCounterEvts::Init() { if (!m_Uninited) return 0; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = (LPVOID)g_LocalSystemAdminsSD; sa.bInheritHandle = FALSE; m_LoadCtrEvent = CreateEvent(&sa, FALSE, FALSE,LOAD_CTR_EVENT_NAME); if (NULL == m_LoadCtrEvent) goto end_fail; m_UnloadCtrEvent = CreateEvent(&sa, FALSE, FALSE, UNLOAD_CTR_EVENT_NAME); if (NULL == m_UnloadCtrEvent) goto end_fail; m_hWmiReverseAdapSetLodCtr = CreateEvent(&sa,FALSE,FALSE,REVERSE_DREDGE_EVENT_NAME_SET); if (NULL == m_hWmiReverseAdapSetLodCtr) goto end_fail; m_hWmiReverseAdapLodCtrDone = CreateEvent(&sa,FALSE,FALSE,REVERSE_DREDGE_EVENT_NAME_ACK); if (NULL == m_hWmiReverseAdapLodCtrDone) goto end_fail; sa.lpSecurityDescriptor = (LPVOID)g_LocalSystemSD; m_hPendingTasksStart = CreateEvent(&sa,FALSE,FALSE,PENDING_TASK_START); if (!m_hPendingTasksStart) goto end_fail; m_hPendingTasksComplete = CreateEvent(&sa,TRUE,TRUE,PENDING_TASK_COMPLETE); if (!m_hPendingTasksComplete) goto end_fail; m_Uninited = FALSE; return NO_ERROR; end_fail: return GetLastError(); } VOID NTAPI CCounterEvts::EvtCallBackLoad(VOID * pContext,BOOLEAN bTimerFired) { if (!GLOB_Monitor_IsRegistred()) return; CCounterEvts * pCounter = (CCounterEvts *)pContext; if (NULL == pCounter) return; if (SIG_COUNTEEVENTS_BUSY != pCounter->m_dwSignature) return; pCounter->CallBack(bTimerFired,Type_Load); } VOID NTAPI CCounterEvts::EvtCallBackUnload(VOID * pContext,BOOLEAN bTimerFired) { if (!GLOB_Monitor_IsRegistred()) return; CCounterEvts * pCounter = (CCounterEvts *)pContext; if (NULL == pCounter) return; if (SIG_COUNTEEVENTS_BUSY != pCounter->m_dwSignature) return; pCounter->CallBack(bTimerFired,Type_Unload); } VOID NTAPI CCounterEvts::EvtCallBackPendingTask(VOID * pContext,BOOLEAN bTimerFired) { if (!GLOB_Monitor_IsRegistred()) return; CCounterEvts * pCounter = (CCounterEvts *)pContext; if (NULL == pCounter) return; if (SIG_COUNTEEVENTS_BUSY != pCounter->m_dwSignature) return; pCounter->CallBackPending(bTimerFired); } VOID CCounterEvts::CallBack(BOOLEAN bTimerFired,int Type) { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"CallBack with type %d called\n",Type)); #endif if (GLOB_IsResyncAllowed()) { DWORD dwRet = WaitForSingleObject(m_hWmiReverseAdapSetLodCtr,0); if (WAIT_OBJECT_0 == dwRet) { // this is the hack not to spawn a Delta Dredge when there is before a Reverese Dredge #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff," - SetEvent(m_hWmiReverseAdapLodCtrDone);\n")); #endif SetEvent(m_hWmiReverseAdapLodCtrDone); } else { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff," - ResyncPerf(RESYNC_TYPE_LODCTR);\n")); #endif ResyncPerf(RESYNC_TYPE_LODCTR); } } } VOID CCounterEvts::CallBackPending(BOOLEAN bTimerFired) { if (GLOB_IsResyncAllowed()) { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff," - PendingTask Start set\n")); #endif ResyncPerf(RESYNC_TYPE_PENDING_TASKS); } } VOID RevertRegister_(HANDLE & hWaitHandle) { UnregisterWaitEx(hWaitHandle,NULL); hWaitHandle = NULL; } DWORD CCounterEvts::Register() { // automatic reset if (!RegisterWaitForSingleObject(&m_WaitLoadCtr, m_LoadCtrEvent, CCounterEvts::EvtCallBackLoad, this, INFINITE, WT_EXECUTEDEFAULT)) return GetLastError(); OnDeleteIf UnReg1(m_WaitLoadCtr); // automatic reset if(!RegisterWaitForSingleObject(&m_WaitUnloadCtr, m_UnloadCtrEvent, CCounterEvts::EvtCallBackUnload, this, INFINITE, WT_EXECUTEDEFAULT)) return GetLastError(); OnDeleteIf UnReg2(m_WaitUnloadCtr); if (!RegisterWaitForSingleObject(&m_hWaitPendingTasksStart, m_hPendingTasksStart, CCounterEvts::EvtCallBackPendingTask, this, INFINITE, WT_EXECUTEDEFAULT)) return GetLastError(); OnDeleteIf UnReg3(m_hWaitPendingTasksStart); // here everything is OK UnReg1.dismiss(); UnReg2.dismiss(); UnReg3.dismiss(); m_dwSignature = SIG_COUNTEEVENTS_BUSY; return ERROR_SUCCESS; } DWORD CCounterEvts::Unregister() { if (m_WaitLoadCtr) { UnregisterWaitEx(m_WaitLoadCtr,NULL); m_WaitLoadCtr = NULL; } if (m_WaitUnloadCtr) { UnregisterWaitEx(m_WaitUnloadCtr,NULL); m_WaitUnloadCtr = NULL; } if (m_hWaitPendingTasksStart) { UnregisterWaitEx(m_hWaitPendingTasksStart,NULL); m_hWaitPendingTasksStart = NULL; } m_dwSignature = SIG_COUNTEEVENTS_FREE; return 0; } VOID CCounterEvts::UnInit() { if (!m_Uninited) return; if(m_LoadCtrEvent) { CloseHandle(m_LoadCtrEvent); m_LoadCtrEvent = NULL; } if(m_UnloadCtrEvent) { CloseHandle(m_UnloadCtrEvent); m_UnloadCtrEvent = NULL; } if (m_hWmiReverseAdapSetLodCtr) { CloseHandle(m_hWmiReverseAdapSetLodCtr); m_hWmiReverseAdapSetLodCtr = NULL; } if (m_hWmiReverseAdapLodCtrDone) { CloseHandle(m_hWmiReverseAdapLodCtrDone); m_hWmiReverseAdapLodCtrDone = NULL; } if (m_hPendingTasksStart) { CloseHandle(m_hPendingTasksStart); m_hPendingTasksStart = NULL; } if (m_hPendingTasksComplete) { CloseHandle(m_hPendingTasksComplete); m_hPendingTasksComplete = NULL; } m_Uninited = TRUE; } CCounterEvts::~CCounterEvts() { if (!m_Uninited) UnInit(); m_dwSignature = SIG_COUNTEEVENTS_FREE; } // // this is the main abstraction // the child classes will call the ResyncPerf function, // as long as the CWbemServices write hook. // The ResyncPerf function will grab the global monitor // and register a Timer Callback // the gate will be implemented in the GetAvailable function // // ///////////////////////////////////////////////////////////////////// CMonitorEvents::CMonitorEvents(): m_bInit(FALSE), m_bRegistred(FALSE) { }; CMonitorEvents::~CMonitorEvents() { } // // We install a console control handler because we want to unregister // the WDM event monitor before the GIUD_REMOVE events gets in // the console applications get notified of shutdown before services and drivers // //////////////////////////////////////////////////////// BOOL WINAPI CMonitorEvents::MonitorCtrlHandler( DWORD dwCtrlType ) { BOOL bRet = FALSE; switch(dwCtrlType) { case CTRL_SHUTDOWN_EVENT: GLOB_GetMonitor()->m_WDMListener.Unregister(); #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"WDM Handles closed\n")); #endif bRet = TRUE; break; default: bRet = FALSE; }; return bRet; }; BOOL CMonitorEvents::Init() { if (m_bInit) return TRUE; CInCritSec ics(&m_cs); if (m_bInit) return TRUE; m_dwSig = 'VEOM'; m_CntsEvts.Init(); m_dwADAPDelaySec = WMIADAP_DEFAULT_DELAY; m_dwLodCtrDelaySec = WMIADAP_DEFAULT_DELAY_LODCTR; m_dwTimeToFull = WMIADAP_DEFAULT_TIMETOFULL; m_dwTimeToKillAdap = MAX_PROCESS_WAIT; memset(&m_FileTime,0,sizeof(m_FileTime)); RegRead(); for (DWORD i=0;i cm(hKey); DWORD dwType; DWORD dwSize = sizeof(DWORD); lRet = RegQueryValueEx(hKey, TEXT("ADAPDelay"), NULL, &dwType, (BYTE *)&m_dwADAPDelaySec, &dwSize); if (ERROR_SUCCESS == lRet && REG_DWORD == dwType) { //This is what we want } else if ( ERROR_FILE_NOT_FOUND == lRet ) { dwTemp = WMIADAP_DEFAULT_DELAY; RegSetValueEx(hKey, TEXT("ADAPDelay"), NULL, REG_DWORD, (BYTE *)&dwTemp, sizeof(DWORD)); } else { // Error ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf experienced an error while attempting to read the WMIADAPDelay value in the CIMOM subkey. Continuing using a default value.\n" ) ); } dwSize = sizeof(DWORD); lRet = RegQueryValueEx(hKey, TEXT("LodCtrDelay"), NULL, &dwType, (BYTE *)&m_dwLodCtrDelaySec, &dwSize); if (ERROR_SUCCESS == lRet && REG_DWORD == dwType) { //This is what we want } else if ( ERROR_FILE_NOT_FOUND == lRet ) { dwTemp = WMIADAP_DEFAULT_DELAY_LODCTR; RegSetValueEx(hKey, TEXT("LodCtrDelay"), NULL, REG_DWORD, (BYTE *)&dwTemp, sizeof(DWORD)); } else { // Error ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf experienced an error while attempting to read the WMIADAPDelay value in the CIMOM subkey. Continuing using a default value.\n" ) ); } dwSize = sizeof(DWORD); lRet = RegQueryValueEx(hKey, ADAP_TIME_TO_FULL, NULL, &dwType, (BYTE *)&m_dwTimeToFull, &dwSize); if (ERROR_SUCCESS == lRet && REG_DWORD == dwType) { //This is what we want } else if ( ERROR_FILE_NOT_FOUND == lRet ) { dwTemp = WMIADAP_DEFAULT_TIMETOFULL; RegSetValueEx(hKey, ADAP_TIME_TO_FULL, NULL, REG_DWORD, (BYTE *)&dwTemp, sizeof(DWORD)); } else { // Error ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf experienced an error while attempting to read the WMIADAPDelay value in the CIMOM subkey. Continuing using a default value.\n" ) ); } dwSize = sizeof(DWORD); lRet = RegQueryValueEx(hKey, ADAP_TIME_TO_KILL_ADAP, NULL, &dwType, (BYTE *)&m_dwTimeToKillAdap, &dwSize); if (ERROR_SUCCESS == lRet && REG_DWORD == dwType) { //This is what we want } else if ( ERROR_FILE_NOT_FOUND == lRet ) { dwTemp = MAX_PROCESS_WAIT; RegSetValueEx(hKey, ADAP_TIME_TO_KILL_ADAP, NULL, REG_DWORD, (BYTE *)&dwTemp, sizeof(DWORD)); } else { // Error ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf experienced an error while attempting to read the %S value in the CIMOM subkey. Continuing using a default value.\n",ADAP_TIME_TO_KILL_ADAP)); } //ADAP_TIMESTAMP_FULL dwSize = sizeof(FILETIME); lRet = RegQueryValueEx(hKey, ADAP_TIMESTAMP_FULL, NULL, &dwType, (BYTE *)&m_FileTime, &dwSize); } else { // Error ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf could not open the CIMOM subkey to read initialization data. Continuing using a default value.\n" ) ); } } // // // //////////////////////////////////////////////////////// ResyncPerfTask * CMonitorEvents::GetAvailable(DWORD dwReason) { ResyncPerfTask * pPerf = NULL; CInCritSec ics(&m_cs); if (m_ResyncTasks[dwReason].bFree) { m_ResyncTasks[dwReason].bFree = FALSE; m_ResyncTasks[dwReason].Type = dwReason; pPerf = &m_ResyncTasks[dwReason]; } return pPerf; } TCHAR * g_Strings[] = { TEXT("/F /T"), // FULL Throttle TEXT("/D /T"), // DELTA Throttle TEXT("/R /T"), // REVERSE_ADAPTER Throttle TEXT("/F /R /T"), // FULL REVERSE_ADAPTER Throttle TEXT("/D /R /T"), // DELTA REVERSE_ADAPTER Throttle TEXT("/F /R") // FULL REVERSE no Throttle }; void inline DoUnThrottleDredges() { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"DoUnThrottleDredges\n")); #endif RegSetDWORD(HKEY_LOCAL_MACHINE,HOME_REG_PATH,DO_THROTTLE,0); return; } void inline DoThrottleDredges() { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"DoThrottleDredges\n")); #endif RegSetDWORD(HKEY_LOCAL_MACHINE,HOME_REG_PATH,DO_THROTTLE,1); return; } BOOL CMonitorEvents::CreateProcess_(TCHAR * pCmdLine, CMonitorEvents * pMonitor, ResyncPerfTask * pPerf) { BOOL bRes = FALSE; STARTUPINFO si; PROCESS_INFORMATION ProcInfo; memset(&si,0,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_FORCEOFFFEEDBACK; // Get the appropriate cmdline and attach the proper command line switches LPTSTR pWriteableBuff = GetWMIADAPCmdLine( 64 ); CVectorDeleteMe vdm( pWriteableBuff ); if ( NULL == pWriteableBuff ) { ERRORTRACE((LOG_WINMGMT,"Memory Allocation error spawning dredger!\n")); pMonitor->Lock(); pPerf->bFree = TRUE; pMonitor->Unlock(); return bRes; } #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"Creating process: %S\n",pCmdLine)); #endif DEBUGTRACE((LOG_WINMGMT,"Creating process: %S\n",pCmdLine)); bRes = CreateProcess(pWriteableBuff, pCmdLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &ProcInfo); if (bRes) { CloseHandle(ProcInfo.hThread); pPerf->hProcess = ProcInfo.hProcess; if (RegisterWaitForSingleObject(&pPerf->hWaitHandle, pPerf->hProcess, CMonitorEvents::EventCallBack, pPerf, pMonitor->m_dwTimeToKillAdap, WT_EXECUTEONLYONCE|WT_EXECUTEINWAITTHREAD)) { // // we don't need to free the slot, // because the event callback will do that // } else { DEBUGTRACE((LOG_WINMGMT,"Unable to schedule WmiADAP process termination handler: err %d\n",GetLastError())); CloseHandle(pPerf->hProcess); pPerf->hProcess = NULL; pMonitor->Lock(); pPerf->bFree = TRUE; pMonitor->Unlock(); } } else { ERRORTRACE((LOG_WINMGMT,"CreatProcess %S err: %d\n",pWriteableBuff,GetLastError())); pMonitor->Lock(); pPerf->bFree = TRUE; pMonitor->Unlock(); } return bRes; } VOID NTAPI CMonitorEvents::EventCallBack(VOID * pContext,BOOLEAN bTimerFired) { if (!GLOB_Monitor_IsRegistred()) return; ResyncPerfTask * pPerf = (ResyncPerfTask *)pContext; if (!pPerf || (SIG_RESYNC_PERF != pPerf->dwSig)) return; CMonitorEvents * pMonitor = pPerf->pMonitor; HANDLE hProcess = pPerf->hProcess; if(bTimerFired) { // // The LONG time-out for our process has expired // Kill The Process // TerminateProcess(pPerf->hProcess,0); #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"WmiADAP did not finish within %d msec\n",pMonitor->m_dwTimeToKillAdap)); #endif ERRORTRACE((LOG_WINMGMT,"the ResyncTask of type %d timed-out and has been killed\n",pPerf->Type)); } else { // // the handle has been signaled, meaning that // the process exited normally // #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"ResyncPerf for task %d completed\n",pPerf->Type)); #endif } CloseHandle(pPerf->hProcess); // // if there was a call to ProcessIdleTasks // if we were forced to unthrottle the running tasks // revert back // if (RESYNC_TYPE_PENDING_TASKS == pPerf->Type) { pMonitor->m_bFullReverseNeeded = FALSE; DoThrottleDredges(); #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"Setting the WMI_ProcessIdleTasksComplete\n")); #endif if (GLOB_GetMonitor()->IsRegistred()) SetEvent(GLOB_GetMonitor()->GetTaskCompleteEvent()); } else // a process has exited or it has been terminated { LONG nProc = InterlockedDecrement(&pMonitor->m_OutStandingProcesses); #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"(-) Outstanding Tasks %d\n",pMonitor->m_OutStandingProcesses)); #endif if (0 == nProc && pMonitor->m_bFullReverseNeeded) { // Create Here the process CMonitorEvents * pMonitor = GLOB_GetMonitor(); ResyncPerfTask * pPerfTask = pMonitor->GetAvailable(RESYNC_TYPE_PENDING_TASKS); if (pPerfTask) { TCHAR pCmdLine[64]; StringCchCopy(pCmdLine,64,TEXT("wmiadap.exe ")); StringCchCat(pCmdLine,64,g_Strings[pPerfTask->CmdType]); CMonitorEvents::CreateProcess_(pCmdLine,pMonitor,pPerfTask); } else { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"GetAvailable(RESYNC_TYPE_PENDING_TASKS) returned NULL\n")); #endif } } } pPerf->hProcess = NULL; pMonitor->Lock(); pPerf->bFree = TRUE; pMonitor->Unlock(); UnregisterWaitEx(pPerf->hWaitHandle,NULL); pPerf->hWaitHandle = NULL; } // // This is the main function executed when // -1- the LoadCtr/UnlaodCtr events are set // -2- the Unthrottle events is set by Schedule via the API exposed in Advapi32 // -3- it runs the 4-minutes-after-boot dredge // This function also take care of Reverse-Adapter dredges, if needed // //////////////////////////////////////////////////////////////// VOID NTAPI CMonitorEvents::TimerCallBack(VOID * pContext,BOOLEAN bTimerFired) { if (!GLOB_Monitor_IsRegistred()) { return; } if(bTimerFired) { ResyncPerfTask * pPerf = (ResyncPerfTask *)pContext; CMonitorEvents * pMonitor = pPerf->pMonitor; BOOL bFreeSlot = FALSE; #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"TIMER: Command Type %x\n",pPerf->Type)); #endif // check if the Delta Task was disabled on the Fly if (!pPerf->Enabled) { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"Task %d was disabled on the fly\n",pPerf->Type)); #endif bFreeSlot = TRUE; goto unregister_timer; } BOOL bDoSomething = TRUE; BOOL RunDeltaLogic = TRUE; BOOL AddReverseAdapter = FALSE; BOOL WDMTriggeredReverseAdapter = FALSE; BOOL bDoFullSystemReverseHere = FALSE; if (RESYNC_TYPE_PENDING_TASKS == pPerf->Type) { pMonitor->Lock(); // here disable tasks that are on the wait list for (DWORD i=0;im_ResyncTasks[i].hTimer) { #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"Disabling the pending task %d\n",i)); #endif pMonitor->m_ResyncTasks[i].Enabled = FALSE; } } } pMonitor->Unlock(); // now check if the are processes running DoUnThrottleDredges(); if (pMonitor->m_OutStandingProcesses) { pMonitor->m_bFullReverseNeeded = TRUE; // no need to CreateProcess, the last outstanding process will do that #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"OutStandingProcess, no CreateProcessHere\n")); #endif bFreeSlot = TRUE; goto unregister_timer; } else // no processes outstanding, create the process now { bDoFullSystemReverseHere = TRUE; #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"GOTO CreateProcess\n")); #endif goto createprocess_label; } } if (RESYNC_TYPE_INITIAL == pPerf->Type ) { // check if the Reverse Adapters need a Delta LONG lRet; HKEY hKey; DWORD dwTemp; lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WBEM_REG_REVERSE_KEY, NULL, KEY_READ, &hKey); if (ERROR_SUCCESS == lRet) { DWORD dwType; DWORD dwSize = sizeof(DWORD); DWORD dwVal; lRet = RegQueryValueEx(hKey, WBEM_REG_REVERSE_VALUE, NULL, &dwType, (BYTE *)&dwVal, &dwSize); // if the key is there, is NULL and it is of the right type // OR if the key is not there if( ERROR_SUCCESS == lRet && REG_DWORD == dwType && dwVal ) { AddReverseAdapter = TRUE; #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"\"Performance Refresh\" key set to %d\n",dwVal)); #endif DEBUGTRACE((LOG_WINMGMT,"\"Performance Refresh\" key set to %d\n",dwVal)); } RegCloseKey(hKey); } // check the WDM stuff if (!AddReverseAdapter) { #ifdef DBG if (!HeapValidate(GetProcessHeap(),0,NULL)) { DebugBreak(); } if (!HeapValidate(CWin32DefaultArena::GetArenaHeap(),0,NULL)) { DebugBreak(); } #endif CWMIBinMof BinMof; //============================================================================= // Note: this combo will always succeed, as all the initialize is doing is // setting a flag to FALSE and returning S_OK //============================================================================= if( SUCCEEDED( BinMof.Initialize(NULL,FALSE) ) ) { WDMTriggeredReverseAdapter = BinMof.BinaryMofsHaveChanged(); if (WDMTriggeredReverseAdapter) { // override the previous decition AddReverseAdapter = TRUE; #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"BinaryMofs DO HAVE changed\n")); #endif DEBUGTRACE((LOG_WINMGMT,"CWMIBinMof.BinaryMofsHaveChanged == TRUE\n")); } #ifdef DBG if (!HeapValidate(GetProcessHeap(),0,NULL)) { DebugBreak(); } if (!HeapValidate(CWin32DefaultArena::GetArenaHeap(),0,NULL)) { DebugBreak(); } #endif } } // overrides delta with full, if the case if (WMIADAP_DEFAULT_TIMETOFULL == pMonitor->GetFullTime()) { // no override } else // read timestamp and decide { ULARGE_INTEGER li; li.LowPart = pMonitor->GetTimeStamp().dwLowDateTime; li.HighPart = pMonitor->GetTimeStamp().dwHighDateTime; __int64 Seconds = pMonitor->GetFullTime(); Seconds *= 10000000; // number of 100ns units in 1 second ULARGE_INTEGER liNow; GetSystemTimeAsFileTime((FILETIME *)&liNow); if ((li.QuadPart + Seconds) < liNow.QuadPart) { pPerf->CmdType = RESYNC_FULL_THROTTLE; RunDeltaLogic = FALSE; } } } // end if command type initial if ((RESYNC_TYPE_INITIAL == pPerf->Type) && RunDeltaLogic) { DWORD ret = DeltaDredge2(0,NULL); #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"DeltaDredge2 ret %d\n",ret)); #endif switch(ret) { case FULL_DREDGE: pPerf->CmdType = RESYNC_FULL_THROTTLE; break; case PARTIAL_DREDGE: pPerf->CmdType = RESYNC_DELTA_THROTTLE; break; case NO_DREDGE: // // this is the case where we do nothing DEBUGTRACE((LOG_WINMGMT,"No Dredge to run\n")); // bDoSomething = FALSE; break; default: // // never here // break; } #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"DeltaDredge2() ret = %d, bDoSomething = %d \n",ret,bDoSomething)); #endif DEBUGTRACE((LOG_WINMGMT,"DeltaDredge2() ret = %d, bDoSomething = %d \n",ret,bDoSomething)); } if (bDoSomething || AddReverseAdapter) { createprocess_label: TCHAR pCmdLine[64]; StringCchCopy(pCmdLine,64,TEXT("wmiadap.exe ")); if (bDoFullSystemReverseHere) { StringCchCat(pCmdLine,64,g_Strings[pPerf->CmdType]); } else { if (bDoSomething && AddReverseAdapter) { StringCchCat(pCmdLine,64,g_Strings[pPerf->CmdType]); StringCchCat(pCmdLine,64,TEXT(" /R")); } if (bDoSomething && !AddReverseAdapter) { StringCchCat(pCmdLine,64,g_Strings[pPerf->CmdType]); } if (!bDoSomething && AddReverseAdapter) { StringCchCat(pCmdLine,64,g_Strings[RESYNC_RADAPD_THROTTLE]); } } CMonitorEvents::CreateProcess_(pCmdLine,pMonitor,pPerf); if (GLOB_GetMonitor()->IsRegistred()) { if (!bDoFullSystemReverseHere) { InterlockedIncrement(&(GLOB_GetMonitor()->m_OutStandingProcesses)); #ifdef DEBUG_ADAP DBG_PRINTFA((pBuff,"(+) Outstanding Tasks %d\n",GLOB_GetMonitor()->m_OutStandingProcesses)); #endif } } } else { pMonitor->Lock(); pPerf->bFree = TRUE; pMonitor->Unlock(); } unregister_timer: if (bFreeSlot) { pMonitor->Lock(); pPerf->bFree = TRUE; pMonitor->Unlock(); } DeleteTimerQueueTimer(NULL,pPerf->hTimer,NULL); pPerf->hTimer = NULL; pPerf->Enabled = TRUE; } else { // never here _DBG_ASSERT(FALSE); } } // // // /////////////////////////////////////////////// DWORD ResyncPerf(DWORD dwReason) { if(!GLOB_IsResyncAllowed()) { ERRORTRACE((LOG_WINMGMT,"ResyncPerf disable g_fSetup or g_fDoResync\n")); return 0; } ResyncPerfTask * pPerfTask = GLOB_GetMonitor()->GetAvailable(dwReason); if (pPerfTask) { // here you have the slot for execution // tell Reverse_Adapter that it's scheduled if (RESYNC_TYPE_WDMEVENT == dwReason || RESYNC_TYPE_CLASSCREATION == dwReason) { LONG lRet; HKEY hKey; DWORD dwTemp; lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WBEM_REG_REVERSE_KEY, NULL, KEY_READ|KEY_WRITE, &hKey); if (ERROR_SUCCESS == lRet) { DWORD dwType; DWORD dwSize = sizeof(DWORD); DWORD dwVal; lRet = RegQueryValueEx(hKey, WBEM_REG_REVERSE_VALUE, NULL, &dwType, (BYTE *)&dwVal, &dwSize); // if the key is there, is NULL and it is of the right type // OR if the key is not there if((ERROR_SUCCESS == lRet && REG_DWORD == dwType && 0 == dwVal) || (ERROR_FILE_NOT_FOUND == lRet)) { dwVal = 1; RegSetValueEx(hKey, WBEM_REG_REVERSE_VALUE, 0, REG_DWORD, (BYTE *)&dwVal, sizeof(DWORD)); } RegCloseKey(hKey); } }; if (CreateTimerQueueTimer(&pPerfTask->hTimer, NULL, CMonitorEvents::TimerCallBack, pPerfTask, pPerfTask->dwTimeDue, 0, WT_EXECUTEONLYONCE|WT_EXECUTELONGFUNCTION)) { return 0; } else { // ERRORTRACE return GetLastError(); } } else { // no slot availables return ERROR_BUSY; } } // // // This function is called by the Hook installed in wbemcore // that monitors class creation // /////////////////////////////////////////// DWORD __stdcall DredgeRA(VOID * pReserved) { //DBG_PRINTFA((pBuff,"Classes\n")); return ResyncPerf(RESYNC_TYPE_CLASSCREATION); };