Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

495 lines
15 KiB

  1. /*++
  2. Copyright (C) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. RESYNC.CPP
  5. Abstract:
  6. History:
  7. a-davj 04-Mar-97 Created.
  8. ivanbrug 01-Sep-2000 changed for svchost migration
  9. --*/
  10. #include "precomp.h"
  11. #include <malloc.h>
  12. #include <tchar.h>
  13. #include "WinMgmt.h"
  14. #include "resync.h"
  15. // Timeout is a 64-bit value. See documentation on SetWaitableTimer
  16. // for why we are setting it this way.
  17. #define _SECOND 10000000
  18. #define RESYNC_TIMEOUT_INTERVAL 10 * _SECOND
  19. DWORD gdwADAPDelaySec = 0;
  20. DWORD gdwLodCtrDelaySec = 0;
  21. BOOL gfResyncInit = FALSE;
  22. HANDLE ghWaitableTimer = NULL;
  23. BOOL gfSpawnedResync = FALSE;
  24. HANDLE ghResyncThreadHandle = NULL;
  25. HANDLE ghResyncThreadEvent = NULL;
  26. CRITICAL_SECTION* g_pResyncCs = NULL;
  27. DWORD gdwResyncThreadId = 0;
  28. // A global handle used to store the last dredger we
  29. // kicked off!
  30. HANDLE ghChildProcessHandle = NULL;
  31. void ResetResyncTimer( HANDLE hResyncTimer, BOOL bIsLoadCtr )
  32. {
  33. DWORD dwErr = 0;
  34. __int64 qwDueTime = bIsLoadCtr?(gdwLodCtrDelaySec * _SECOND):(gdwADAPDelaySec * _SECOND); // RESYNC_TIMEOUT_INTERVAL;
  35. // Convert it to relative time
  36. qwDueTime *= -1;
  37. // Copy the relative time into a LARGE_INTEGER.
  38. LARGE_INTEGER li;
  39. li.LowPart = (DWORD) ( qwDueTime & 0xFFFFFFFF );
  40. li.HighPart = (LONG) ( qwDueTime >> 32 );
  41. if ( !SetWaitableTimer( hResyncTimer, &li, 0, NULL, NULL, FALSE ) )
  42. {
  43. dwErr = GetLastError();
  44. }
  45. }
  46. // This thread controls the actual shelling of a resync perf operation
  47. DWORD WINAPI ResyncPerfThread( void* pVoid )
  48. {
  49. RESYNCPERFDATASTRUCT* pResyncPerfData = (RESYNCPERFDATASTRUCT*) pVoid;
  50. // We get the two handles, copy them and wait on them
  51. // The first handle is the terminate event, the second is the
  52. // timer on which to spin off the resync
  53. BOOL bIsLodCtr = pResyncPerfData->m_bIsLodCtr;
  54. HANDLE aHandles[2];
  55. aHandles[0] = pResyncPerfData->m_hTerminate;
  56. HANDLE hTimer = pResyncPerfData->m_hWaitableTimer;
  57. CRITICAL_SECTION* pcs = pResyncPerfData->m_pcs;
  58. BOOL bFullDredge = pResyncPerfData->m_fFullDredge;
  59. delete pResyncPerfData;
  60. pResyncPerfData = NULL;
  61. // Reset the spawned flag
  62. gfSpawnedResync = FALSE;
  63. // Okay. Signal this event so the starting thread can get us going
  64. SetEvent( ghResyncThreadEvent );
  65. // Now, if ghChildProcessHandle is not NULL, then we've obviously kicked off a
  66. // dredge before. See where the last one is at. If it's not done, wait for
  67. // it to finish. We will always check this at the start of this chunk of code,
  68. // since we are really the only location in which the process handle can ever get set,
  69. // and there really shouldn't be more than one thread ever, waiting to start another
  70. // dredge
  71. if ( NULL != ghChildProcessHandle )
  72. {
  73. aHandles[1] = ghChildProcessHandle;
  74. DWORD dwWait = WaitForMultipleObjects( 2, aHandles, FALSE, INFINITE );
  75. // If abort was signalled, leave!
  76. if ( dwWait == WAIT_OBJECT_0 )
  77. {
  78. return 0;
  79. }
  80. // If the process handle was signalled, close the process, reset the timer
  81. // and we'll get ready to start the next dredge!
  82. if ( dwWait == WAIT_OBJECT_0 + 1 )
  83. {
  84. EnterCriticalSection( pcs );
  85. CloseHandle( ghChildProcessHandle );
  86. ghChildProcessHandle = NULL;
  87. ResetResyncTimer( hTimer, bIsLodCtr );
  88. LeaveCriticalSection( pcs );
  89. }
  90. }
  91. else
  92. {
  93. // If the Child Process Handle is NULL, we've never dredged before, so we'll
  94. // just reset the timer
  95. ResetResyncTimer( hTimer, bIsLodCtr );
  96. }
  97. BOOL fHoldOff = TRUE;
  98. // Reset this handle to the timer now
  99. aHandles[1] = hTimer;
  100. while ( fHoldOff )
  101. {
  102. // Wait for either the terminate event or the timer
  103. DWORD dwWait = WaitForMultipleObjects( 2, aHandles, FALSE, INFINITE );
  104. // This means the terminate was signaled
  105. if ( dwWait == WAIT_OBJECT_0 )
  106. {
  107. break;
  108. } else
  109. // This means the timer was signaled
  110. if ( dwWait == WAIT_OBJECT_0 + 1 )
  111. {
  112. EnterCriticalSection( pcs );
  113. // Finally, if the current thread id != gdwResyncThreadId, this means another
  114. // resync perf thread got kicked off, inside of the critical section,
  115. // so we should just let it wait on the timer. We don't really need to do
  116. // this, since the main thread will wait on this thread to complete before
  117. // it actually kicks off another thread.
  118. if ( GetCurrentThreadId() != gdwResyncThreadId )
  119. {
  120. // Used the following int 3 for debugging
  121. // _asm int 3;
  122. LeaveCriticalSection( pcs );
  123. break;
  124. }
  125. // Once we get through the critical section, check that the
  126. // timer is still signalled. If it is not, this means that somebody
  127. // got control of the critical section and reset the timer
  128. if ( WaitForSingleObject( aHandles[1], 0 ) == WAIT_OBJECT_0 )
  129. {
  130. // Last quick sanity check on the abort event
  131. if ( WaitForSingleObject( aHandles[0], 0 ) == WAIT_OBJECT_0 )
  132. {
  133. // Outa here!
  134. LeaveCriticalSection( pcs );
  135. break;
  136. }
  137. // Okay, we really will try to create the process now.
  138. gfSpawnedResync = TRUE;
  139. // We signalled to start the process, so make it so.
  140. PROCESS_INFORMATION pi;
  141. STARTUPINFO si;
  142. memset(&si, 0, sizeof(si));
  143. si.cb = sizeof(si);
  144. TCHAR * pWritebleBuffer = (TCHAR *)_alloca(sizeof(__T("WMIADAP.EXE /F"))+2);
  145. lstrcpy(pWritebleBuffer,(bFullDredge?__T("WMIADAP.EXE /F"):__T("WMIADAP.EXE")));
  146. BOOL bRes = CreateProcess(NULL,
  147. pWritebleBuffer,
  148. NULL,
  149. NULL,
  150. FALSE,
  151. CREATE_NO_WINDOW,
  152. NULL,
  153. NULL,
  154. &si,
  155. &pi);
  156. if(bRes)
  157. {
  158. // Who cares about this one?
  159. CloseHandle(pi.hThread);
  160. // Clean up our old values
  161. if ( NULL != ghChildProcessHandle )
  162. {
  163. CloseHandle( ghChildProcessHandle );
  164. ghChildProcessHandle = NULL;
  165. }
  166. ghChildProcessHandle = pi.hProcess;
  167. }
  168. // We're done
  169. fHoldOff = FALSE;
  170. } // Check that we're still signalled, or we will just have to go back to waiting
  171. LeaveCriticalSection( pcs );
  172. } // IF timer was signalled
  173. } // WHILE fHoldOff
  174. return 0;
  175. }
  176. // For the waitable timer
  177. //#define _SECOND 10000000
  178. // Create all the things we need
  179. BOOL InitResync( void )
  180. {
  181. if ( gfResyncInit )
  182. return gfResyncInit;
  183. if ( NULL == ghWaitableTimer )
  184. {
  185. ghWaitableTimer = CreateWaitableTimerW( NULL, TRUE, NULL );
  186. // We gotta big problem
  187. if ( NULL == ghWaitableTimer )
  188. {
  189. // Log an error here
  190. ERRORTRACE( ( LOG_WINMGMT, "Could not create a waitable timer for Resyncperf.\n" ) );
  191. }
  192. }
  193. if ( NULL == ghResyncThreadEvent )
  194. {
  195. ghResyncThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  196. // We gotta big problem
  197. if ( NULL == ghResyncThreadEvent )
  198. {
  199. // Log an event here
  200. ERRORTRACE( ( LOG_WINMGMT, "Could not create a ResyncThreadEvent event for Resyncperf.\n" ) );
  201. }
  202. }
  203. // This critical section won't be freed or deleted because of
  204. // potential timing issues. But since it's only one, I think
  205. // we can live with it.
  206. if ( NULL == g_pResyncCs )
  207. {
  208. g_pResyncCs = new CRITICAL_SECTION;
  209. // We gotta big problem
  210. if ( NULL == g_pResyncCs )
  211. {
  212. // Log an event here
  213. ERRORTRACE( ( LOG_WINMGMT, "Could not create a ResyncCs critical section for Resyncperf.\n" ) );
  214. }
  215. else
  216. {
  217. InitializeCriticalSection( g_pResyncCs );
  218. }
  219. }
  220. gfResyncInit = ( NULL != ghWaitableTimer &&
  221. NULL != g_pResyncCs &&
  222. NULL != ghResyncThreadEvent );
  223. // Read the initialization information
  224. Registry reg;
  225. if ( Registry::no_error == reg.Open( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\WBEM\\CIMOM" ) )
  226. {
  227. long lError = reg.GetDWORD( L"ADAPDelay", &gdwADAPDelaySec );
  228. if ( Registry::no_error == lError )
  229. {
  230. //This is what we want
  231. }
  232. else if ( ERROR_FILE_NOT_FOUND == reg.GetLastError() )
  233. {
  234. // Not set, so add it
  235. reg.SetDWORD( L"ADAPDelay", WMIADAP_DEFAULT_DELAY );
  236. gdwADAPDelaySec = WMIADAP_DEFAULT_DELAY;
  237. }
  238. else
  239. {
  240. // Error
  241. ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf experienced an error while attempting to read the WMIADAPDelay value in the CIMOM subkey. Continuing using a default value.\n" ) );
  242. gdwADAPDelaySec = WMIADAP_DEFAULT_DELAY;
  243. }
  244. lError = reg.GetDWORD( L"LodCtrDelay", &gdwLodCtrDelaySec );
  245. if ( Registry::no_error == lError )
  246. {
  247. //This is what we want
  248. }
  249. else if ( ERROR_FILE_NOT_FOUND == reg.GetLastError() )
  250. {
  251. // Not set, so add it
  252. reg.SetDWORD( L"LodCtrDelay", WMIADAP_DEFAULT_DELAY );
  253. gdwLodCtrDelaySec = WMIADAP_DEFAULT_DELAY_LODCTR;
  254. }
  255. else
  256. {
  257. // Error
  258. ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf experienced an error while attempting to read the WMIADAPDelay value in the CIMOM subkey. Continuing using a default value.\n" ) );
  259. gdwLodCtrDelaySec = WMIADAP_DEFAULT_DELAY_LODCTR;
  260. }
  261. }
  262. else
  263. {
  264. // Error
  265. ERRORTRACE( ( LOG_WINMGMT, "ResyncPerf could not open the CIMOM subkey to read initialization data. Continuing using a default value.\n" ) );
  266. gdwADAPDelaySec = WMIADAP_DEFAULT_DELAY;
  267. gdwLodCtrDelaySec = WMIADAP_DEFAULT_DELAY_LODCTR;
  268. }
  269. return gfResyncInit;
  270. }
  271. // PLEASE NOTE - THIS FUNCTION IS NOT REENTRANT! PLEASE DO NOT CALL IT ON MULTIPLE THREADS!
  272. void ResyncPerf( HANDLE hTerminate, BOOL bIsLodCtr )
  273. {
  274. // Assume that we should check the timer
  275. BOOL fFirstTime = !gfResyncInit;
  276. if ( !InitResync() )
  277. return;
  278. EnterCriticalSection( g_pResyncCs );
  279. // Now, if this or the first time, or the spawned resyncflag is set to TRUE, then we need
  280. // to kick off another thread. By checking gfSpawnedResync in a critical section, since
  281. // it only gets set in the same critical section, we ensure that we will resignal as needed
  282. // as well as only kick off a thread when we really need to.
  283. BOOL fSpawnThread = ( fFirstTime || gfSpawnedResync );
  284. if ( !fSpawnThread )
  285. {
  286. // We are here because we don't appear to have spawned a resync.
  287. // This is either because we are servicing many lodctr requests
  288. // within our time delay, or a dredger was started and
  289. // a previous request request to dredge is waiting for
  290. // the process to complete. If the child process handle
  291. // is not NULL, there is no real need to reset the
  292. // waitable timer
  293. if ( NULL == ghChildProcessHandle && ghResyncThreadHandle )
  294. {
  295. // Reset the timer here
  296. ResetResyncTimer( ghWaitableTimer , bIsLodCtr );
  297. }
  298. }
  299. LeaveCriticalSection( g_pResyncCs );
  300. if ( fSpawnThread )
  301. {
  302. HANDLE ahHandle[2];
  303. if ( NULL != ghResyncThreadHandle )
  304. {
  305. ahHandle[0] = hTerminate;
  306. ahHandle[1] = ghResyncThreadHandle;
  307. // Wait for ten seconds on this handle. If it is not signalled, something is
  308. // direly wrong. We're probably not going to be able to kick off a dredge
  309. // so put some info to this effect in the error log. The only time we should
  310. // have contention here, is when a lodctr event is signalled, just as the timer
  311. // becomes signalled. The resync thread will wake up and start another dredge
  312. // this thread will wait for the other thread to complete before continuing.
  313. // We will kick off another resync thread, which will start another dredge,
  314. // but it will wait for the first dredge to continue. This is a worst case
  315. // scenario, and arguably kicking off two dredges isn't that bad of a bailout
  316. DWORD dwRet = WaitForMultipleObjects( 2, ahHandle, FALSE, 10000 );
  317. // We're done
  318. if ( dwRet == WAIT_OBJECT_0 )
  319. {
  320. return;
  321. }
  322. if ( dwRet != WAIT_OBJECT_0 + 1 )
  323. {
  324. ERRORTRACE( ( LOG_WINMGMT, "The wait for a termination event or ResyncThreadHandle timed out in Resyncperf.\n" ) );
  325. return;
  326. }
  327. CloseHandle( ghResyncThreadHandle );
  328. ghResyncThreadHandle = NULL;
  329. }
  330. EnterCriticalSection( g_pResyncCs );
  331. DWORD dwThreadId = 0;
  332. RESYNCPERFDATASTRUCT* pResyncData = new RESYNCPERFDATASTRUCT;
  333. // Boy are we low on memory!
  334. if ( NULL == pResyncData )
  335. {
  336. LeaveCriticalSection( g_pResyncCs );
  337. // Log an event here
  338. ERRORTRACE( ( LOG_WINMGMT, "Could not create a RESYNCPERFDATASTRUCT in Resyncperf.\n" ) );
  339. return;
  340. }
  341. // Store the data for the resync operation
  342. pResyncData->m_hTerminate = hTerminate;
  343. pResyncData->m_hWaitableTimer = ghWaitableTimer;
  344. pResyncData->m_pcs = g_pResyncCs;
  345. pResyncData->m_fFullDredge = fFirstTime;
  346. pResyncData->m_bIsLodCtr = bIsLodCtr;
  347. ghResyncThreadHandle = CreateThread( NULL, 0,
  348. (LPTHREAD_START_ROUTINE)ResyncPerfThread, (void*) pResyncData,
  349. 0, &gdwResyncThreadId );
  350. LeaveCriticalSection( g_pResyncCs );
  351. if ( NULL == ghResyncThreadHandle )
  352. {
  353. LeaveCriticalSection( g_pResyncCs );
  354. // Log an event here
  355. ERRORTRACE( ( LOG_WINMGMT, "Could not create a ResyncPerfThread thread in Resyncperf.\n" ) );
  356. return;
  357. }
  358. else
  359. {
  360. // Wait for the resync thread event to be signalled by the thread we just started.
  361. // If it doesn't signal in 10 seconds, something is VERY wrong
  362. DWORD dwWait = WaitForSingleObject( ghResyncThreadEvent, INFINITE );
  363. if ( dwWait != WAIT_OBJECT_0 )
  364. {
  365. // Log an event
  366. ERRORTRACE( ( LOG_WINMGMT, "The ResyncPerfThread thread never signaled the ghResyncThreadEvent in Resyncperf.\n" ) );
  367. return;
  368. }
  369. }
  370. } // IF fSpawnThread
  371. }