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.

555 lines
16 KiB

  1. /*++
  2. Copyright (C) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. ADAPTHRD.CPP
  5. Abstract:
  6. History:
  7. --*/
  8. #include "precomp.h"
  9. #include <stdio.h>
  10. #include <process.h>
  11. #include <wbemcli.h>
  12. #include <cominit.h>
  13. #include "ntreg.h"
  14. #include "adapthrd.h"
  15. // IMPORTANT!!!!
  16. // This code MUST be revisited to do the following:
  17. // A>>>>> Exception Handling around the outside calls
  18. // B>>>>> Use a named mutex around the calls
  19. // C>>>>> Make the calls on another thread
  20. // D>>>>> Place and handle registry entries that indicate a bad DLL!
  21. ////////////////////////////////////////////////////////////////////////////////////////////
  22. //
  23. // CAdapThreadRequest
  24. //
  25. ////////////////////////////////////////////////////////////////////////////////////////////
  26. CAdapThreadRequest::CAdapThreadRequest( void )
  27. : m_hWhenDone( NULL ),
  28. m_hrReturn( WBEM_S_NO_ERROR )
  29. ////////////////////////////////////////////////////////////////////////////////////////////
  30. //
  31. // Constructor
  32. //
  33. ////////////////////////////////////////////////////////////////////////////////////////////
  34. {
  35. }
  36. CAdapThreadRequest::~CAdapThreadRequest( void )
  37. ////////////////////////////////////////////////////////////////////////////////////////////
  38. //
  39. // Destructor
  40. //
  41. ////////////////////////////////////////////////////////////////////////////////////////////
  42. {
  43. if ( NULL != m_hWhenDone )
  44. {
  45. CloseHandle( m_hWhenDone );
  46. }
  47. }
  48. HRESULT CAdapThreadRequest::EventLogError( void )
  49. {
  50. return 0;
  51. }
  52. ////////////////////////////////////////////////////////////////////////////////////////////
  53. //
  54. // CAdapThread
  55. //
  56. ////////////////////////////////////////////////////////////////////////////////////////////
  57. CAdapThread::CAdapThread( CAdapPerfLib* pPerfLib )
  58. : m_pPerfLib( pPerfLib ),
  59. m_hEventQuit( NULL ),
  60. m_hSemReqPending( NULL ),
  61. m_hThread( NULL ),
  62. m_fOk( FALSE )
  63. ////////////////////////////////////////////////////////////////////////////////////////////
  64. //
  65. // Constructor
  66. //
  67. ////////////////////////////////////////////////////////////////////////////////////////////
  68. {
  69. // Initialize the control members
  70. // ==============================
  71. Init();
  72. }
  73. CAdapThread::~CAdapThread()
  74. ////////////////////////////////////////////////////////////////////////////////////////////
  75. //
  76. // Destructor
  77. //
  78. ////////////////////////////////////////////////////////////////////////////////////////////
  79. {
  80. if ( NULL != m_hThread )
  81. {
  82. Shutdown();
  83. }
  84. Clear();
  85. // Clean up the queue
  86. // ==================
  87. while ( m_RequestQueue.Size() > 0 )
  88. {
  89. CAdapThreadRequest* pRequest = (CAdapThreadRequest*) m_RequestQueue.GetAt( 0 );
  90. if ( NULL != pRequest )
  91. {
  92. pRequest->Release();
  93. }
  94. m_RequestQueue.RemoveAt( 0 );
  95. }
  96. }
  97. BOOL CAdapThread::Init( void )
  98. ////////////////////////////////////////////////////////////////////////////////////////////
  99. //
  100. // Initializes the control variables
  101. //
  102. ////////////////////////////////////////////////////////////////////////////////////////////
  103. {
  104. if ( !m_fOk )
  105. {
  106. if ( ( m_hEventQuit = CreateEvent( NULL, TRUE, FALSE, NULL ) ) != NULL )
  107. {
  108. if ( ( m_hSemReqPending = CreateSemaphore( NULL, 0, 0x7FFFFFFF, NULL ) ) != NULL )
  109. {
  110. if ( ( m_hThreadReady = CreateEvent( NULL, TRUE, FALSE, NULL ) ) != NULL )
  111. {
  112. m_fOk = TRUE;
  113. }
  114. }
  115. }
  116. }
  117. if ( !m_fOk )
  118. {
  119. ERRORTRACE( ( LOG_WMIADAP, "CAdapThread::Init() failed.\n" ) );
  120. }
  121. return m_fOk;
  122. }
  123. BOOL CAdapThread::Clear( BOOL fClose )
  124. ////////////////////////////////////////////////////////////////////////////////////////////
  125. //
  126. // Clears the control variables and thread variables
  127. //
  128. ////////////////////////////////////////////////////////////////////////////////////////////
  129. {
  130. CInCritSec ics(&m_cs);
  131. // Don't close the handles unless we've been told to.
  132. m_fOk = FALSE;
  133. if ( NULL != m_hEventQuit )
  134. {
  135. if ( fClose )
  136. {
  137. CloseHandle( m_hEventQuit );
  138. }
  139. m_hEventQuit = NULL;
  140. }
  141. if ( NULL != m_hSemReqPending )
  142. {
  143. if ( fClose )
  144. {
  145. CloseHandle( m_hSemReqPending );
  146. }
  147. m_hSemReqPending = NULL;
  148. }
  149. if ( NULL != m_hThread )
  150. {
  151. if ( fClose )
  152. {
  153. CloseHandle( m_hThread );
  154. }
  155. m_hThread = NULL;
  156. }
  157. m_dwThreadId = 0;
  158. return TRUE;
  159. }
  160. HRESULT CAdapThread::Enqueue( CAdapThreadRequest* pRequest )
  161. ////////////////////////////////////////////////////////////////////////////////////////////
  162. //
  163. // Add a request to the request queue
  164. //
  165. ////////////////////////////////////////////////////////////////////////////////////////////
  166. {
  167. HRESULT hr = WBEM_NO_ERROR;
  168. // Ensure that the thread has started
  169. // ==================================
  170. hr = Begin();
  171. if ( SUCCEEDED( hr ) )
  172. {
  173. // We will use a new one for EVERY operation
  174. HANDLE hEventDone = CreateEvent( NULL, TRUE, FALSE, NULL );
  175. if ( NULL != hEventDone )
  176. {
  177. // Let the request know about the new event handle
  178. // ===========================================
  179. pRequest->SetWhenDoneHandle( hEventDone );
  180. // Auto-lock the queue
  181. // ===================
  182. CInCritSec ics( &m_cs );
  183. try
  184. {
  185. // Add the request to the queue
  186. // ============================
  187. m_RequestQueue.Add( (void*) pRequest );
  188. pRequest->AddRef();
  189. ReleaseSemaphore( m_hSemReqPending, 1, NULL );
  190. }
  191. catch(...)
  192. {
  193. hr = WBEM_E_OUT_OF_MEMORY;
  194. }
  195. }
  196. else
  197. {
  198. hr = WBEM_E_OUT_OF_MEMORY;
  199. }
  200. }
  201. return TRUE;
  202. }
  203. HRESULT CAdapThread::Begin( void )
  204. ////////////////////////////////////////////////////////////////////////////////////////////
  205. //
  206. // If the thread has not already started, then intializes the control variables, and starts
  207. // the thread.
  208. //
  209. ////////////////////////////////////////////////////////////////////////////////////////////
  210. {
  211. HRESULT hr = WBEM_S_NO_ERROR;
  212. // Verify that the thread does not already exist
  213. // =============================================
  214. if ( NULL == m_hThread )
  215. {
  216. // Coping will enter and exit the critical section
  217. CInCritSec ics( &m_cs );
  218. // Double check the thread handle here in case somebody fixed us up while we were
  219. // waiting on the critical section.
  220. if ( NULL == m_hThread )
  221. {
  222. // Initialize the control variables
  223. // ================================
  224. if ( Init() )
  225. {
  226. // Makes sure the pending event semaphore is signalled once for each entry in the queue
  227. // ====================================================================================
  228. if ( m_RequestQueue.Size() > 0 )
  229. {
  230. ReleaseSemaphore( m_hSemReqPending, m_RequestQueue.Size(), NULL );
  231. }
  232. // Start the thread
  233. // ================
  234. m_hThread = (HANDLE) _beginthreadex( NULL, 0, CAdapThread::ThreadProc, (void*) this,
  235. 0, (unsigned int *) &m_dwThreadId );
  236. if ( NULL == m_hThread )
  237. {
  238. hr = WBEM_E_FAILED;
  239. }
  240. else
  241. {
  242. if ( WAIT_OBJECT_0 != WaitForSingleObject( m_hThreadReady, 60000 ) )
  243. {
  244. hr = WBEM_E_FAILED;
  245. ERRORTRACE( ( LOG_WMIADAP, "Worker thread for %S could not be verified.\n", (LPCWSTR)m_pPerfLib->GetServiceName() ) );
  246. SetEvent( m_hEventQuit );
  247. }
  248. else
  249. {
  250. DEBUGTRACE( ( LOG_WMIADAP, "Worker thread for %S is 0x%x\n", (LPCWSTR)m_pPerfLib->GetServiceName(), m_dwThreadId ) );
  251. }
  252. }
  253. }
  254. else
  255. {
  256. hr = WBEM_E_FAILED;
  257. }
  258. } // IF NULL == m_hThread
  259. }
  260. if ( FAILED( hr ) )
  261. {
  262. ERRORTRACE( ( LOG_WMIADAP, "CAdapThread::Begin() failed: %X.\n", hr ) );
  263. }
  264. return hr;
  265. }
  266. unsigned CAdapThread::ThreadProc( void * pVoid )
  267. ////////////////////////////////////////////////////////////////////////////////////////////
  268. //
  269. // This is the static entry point fo the worker thread. It addref's the thread's perflib
  270. // (see comment below) and then calls the objects processing method.
  271. //
  272. ////////////////////////////////////////////////////////////////////////////////////////////
  273. {
  274. unsigned uRet;
  275. try
  276. {
  277. // The calling object
  278. // ==================
  279. CAdapThread* pThis = (CAdapThread*) pVoid;
  280. // The perflib to be processed
  281. // ===========================
  282. CAdapPerfLib* pPerfLib = pThis->m_pPerfLib;
  283. // In an attempt to avoid circular references, we are addrefing the performance library wrapper
  284. // instead of the thread object. The thread object will be destructed by the perflib wrapper
  285. // only after the final reference is released. This thread is dependent on the perflib, but is
  286. // by the thread wrapper. As a result, when the thread has completed processing, if we indicate
  287. // that we are finished with the perflib by releasing the perflib wrapper, then the thread wrapper
  288. // may destroyed at the same time. Note the use of auto-release.
  289. if ( NULL != pPerfLib )
  290. pPerfLib->AddRef();
  291. CAdapReleaseMe arm( pPerfLib );
  292. // Call the processing method
  293. // ==========================
  294. uRet = pThis->RealEntry();
  295. }
  296. catch(...)
  297. {
  298. // <Gasp> We have been betrayed... try to write something to the error log
  299. // =======================================================================
  300. CriticalFailADAPTrace( "An unhandled exception has been thrown in a worker thread." );
  301. uRet = ERROR_OUTOFMEMORY;
  302. }
  303. return uRet;
  304. }
  305. unsigned CAdapThread::RealEntry( void )
  306. ////////////////////////////////////////////////////////////////////////////////////////////
  307. //
  308. // This is the method that contains the loop that processes the requests. While there
  309. // are requests in the queue and the thread has not been instructed to terminate, then
  310. // grab a request and execute it. When the request has completed, then signal the completion
  311. // event to tell the originating thread that the request has been satisfied.
  312. //
  313. ////////////////////////////////////////////////////////////////////////////////////////////
  314. {
  315. HANDLE ahEvents[2];
  316. // Use local copies of these in case we have some timing issue in which we get destructed
  317. // on another thread, but for some reason this guy keeps going.
  318. HANDLE hPending = m_hSemReqPending,
  319. hQuit = m_hEventQuit;
  320. ahEvents[0] = hPending;
  321. ahEvents[1] = hQuit;
  322. DWORD dwWait = 0;
  323. DWORD dwReturn = 0;
  324. // Signal that everything is OK and we are ready to rock!
  325. // ======================================================
  326. if ( SetEvent( m_hThreadReady ) )
  327. {
  328. // If the m_hEventQuit event is signaled, or if it runs into a bizarre error,
  329. // exit loop, otherwise continue as long as there is requests in the queue
  330. // ==========================================================================
  331. while ( ( dwWait = WaitForMultipleObjects( 2, ahEvents, FALSE, INFINITE ) ) == WAIT_OBJECT_0 )
  332. {
  333. // Check for the quit event, since if both events are signalled, we'll let this
  334. // guy take precedence
  335. if ( WaitForSingleObject( hQuit, 0 ) == WAIT_OBJECT_0 )
  336. {
  337. break;
  338. }
  339. // Get the next request from of the FIFO queue
  340. // ===========================================
  341. m_cs.Enter();
  342. CAdapThreadRequest* pRequest = (CAdapThreadRequest*) m_RequestQueue.GetAt( 0 );
  343. CAdapReleaseMe armRequest( pRequest );
  344. m_RequestQueue.RemoveAt( 0 );
  345. m_cs.Leave();
  346. // Execute it
  347. // ==========
  348. dwReturn = pRequest->Execute( m_pPerfLib );
  349. // Fire the completion event
  350. // ==========================
  351. if ( NULL != pRequest->GetWhenDoneHandle() )
  352. {
  353. SetEvent( pRequest->GetWhenDoneHandle() );
  354. }
  355. }
  356. DEBUGTRACE( ( LOG_WMIADAP, "Thread 0x%x for %S is terminating\n", m_dwThreadId, (LPCWSTR)m_pPerfLib->GetServiceName() ) );
  357. // If the exit condition is not due to a signaled m_hEventQuit, then evaluate error
  358. // ================================================================================
  359. if ( WAIT_FAILED == dwWait )
  360. {
  361. dwReturn = GetLastError();
  362. }
  363. }
  364. if ( ERROR_SUCCESS != dwReturn )
  365. {
  366. ERRORTRACE( ( LOG_WMIADAP, "CAdapThread::RealEntry() for %S failed: %X.\n", (LPCWSTR)m_pPerfLib->GetServiceName(), dwReturn ) );
  367. }
  368. return dwReturn;
  369. }
  370. HRESULT CAdapThread::Shutdown( DWORD dwTimeout )
  371. ////////////////////////////////////////////////////////////////////////////////////////////
  372. //
  373. // Performs a gentle shutdown of the thread by signaling the exit event.
  374. //
  375. ////////////////////////////////////////////////////////////////////////////////////////////
  376. {
  377. HRESULT hr = WBEM_NO_ERROR;
  378. // Make sure that we are not killing ourself
  379. // =========================================
  380. if ( ( NULL != m_hThread ) && ( GetCurrentThreadId() != m_dwThreadId ) )
  381. {
  382. SetEvent( m_hEventQuit );
  383. DWORD dwWait = WaitForSingleObject( m_hThread, dwTimeout );
  384. switch ( dwWait )
  385. {
  386. case WAIT_OBJECT_0:
  387. {
  388. m_hThread = NULL;
  389. hr = WBEM_S_NO_ERROR;
  390. }break;
  391. case WAIT_TIMEOUT:
  392. {
  393. hr = WBEM_E_FAILED;
  394. }break;
  395. default:
  396. {
  397. hr = WBEM_E_FAILED;
  398. }
  399. }
  400. if ( FAILED( hr ) )
  401. {
  402. ERRORTRACE( ( LOG_WMIADAP, "CAdapThread::Shutdown() failed.\n" ) );
  403. }
  404. }
  405. else
  406. {
  407. hr = WBEM_S_FALSE;
  408. }
  409. return hr;
  410. }
  411. HRESULT CAdapThread::Reset( void )
  412. ////////////////////////////////////////////////////////////////////////////////////////////
  413. //
  414. // This function will be called if a thread apparently got eaten, in which case, we're
  415. // not sure if it will come back or not. So, we will clear our member data (not close anything)
  416. // and kick off a new processing thread. Please note that this could leak handles, but then again,
  417. // it looks like somebody ate a thread, so there are other potential problems afoot here.
  418. //
  419. ////////////////////////////////////////////////////////////////////////////////////////////
  420. {
  421. HRESULT hr = WBEM_S_NO_ERROR;
  422. // Signal the quit event so if the thread that is executing ever returns it will know to drop
  423. // out. Clear can then rid us of the appropriate handles so we can start all over again.
  424. SetEvent( m_hEventQuit );
  425. // Scoping will enter and exit the critical section, so if anyone tries to enqueue any requests
  426. // while we are executing, we don't step all over each other.
  427. CInCritSec ics( &m_cs );
  428. // Clear shouldn't close the handles
  429. Clear( FALSE );
  430. if ( Init() )
  431. {
  432. hr = Begin();
  433. }
  434. else
  435. {
  436. hr = WBEM_E_FAILED;
  437. }
  438. if ( FAILED( hr ) )
  439. {
  440. ERRORTRACE( ( LOG_WMIADAP, "CAdapThread::Reset() failed: %X.\n", hr ) );
  441. }
  442. return hr;
  443. }