Leaked source code of windows server 2003
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.

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