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.

746 lines
21 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: dsthread.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // FILE: dsThread.cpp
  11. #include "stdafx.h"
  12. #include "dssnap.h" // Note: this has to be before dsthread.h
  13. #include "dsthread.h"
  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. void WaitForThreadShutdown(HANDLE* phThreadArray, DWORD dwCount)
  20. {
  21. TRACE(L"entering WaitForThreadShutdown()\n");
  22. while (TRUE)
  23. {
  24. //
  25. // NOTE: this will block the console. This the intended behavior
  26. // to keep MMC from breaking on none re-entrant code.
  27. //
  28. DWORD dwWaitResult = WaitForMultipleObjectsEx(
  29. dwCount,
  30. phThreadArray, // handle array
  31. TRUE, // wait for all
  32. INFINITE, // time-out
  33. FALSE);// signal completion routine
  34. //TRACE(L"after MsgWaitForMultipleObjects()\n");
  35. //TRACE(L"dwWaitResult = 0x%x\n", dwWaitResult);
  36. if (dwWaitResult == WAIT_OBJECT_0 ||
  37. (WAIT_FAILED == dwWaitResult))
  38. {
  39. // woke up because the thread handle got signalled,
  40. // or because the handle is no longer valid (thread already terminated)
  41. // can proceed
  42. TRACE(L"WaitForMultipleObjectsEx() succeeded\n");
  43. break;
  44. }
  45. else
  46. {
  47. TRACE(L"WaitForMultipleObjectsEx() return 0x%x\n", dwWaitResult);
  48. }
  49. /* Whistler bug #176012 MMC: Assert m_pScopeTree == 0
  50. This message pump causes the UI not to be blocked which means
  51. MMC can reach code that is not re-entrant.
  52. else
  53. {
  54. // woke up because there is a message in the queue
  55. // need to pump
  56. MSG msg;
  57. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  58. {
  59. TRACE(L"inside while(PeekMessage())\n");
  60. ASSERT(msg.message != WM_QUIT);
  61. DispatchMessage(&msg);
  62. }
  63. }*/
  64. } // while
  65. TRACE(L"exiting WaitForThreadShutdown()\n");
  66. }
  67. ////////////////////////////////////////////////////////////////////
  68. // CHiddenWnd
  69. const UINT CHiddenWnd::s_ThreadStartNotificationMessage = WM_USER + 1;
  70. const UINT CHiddenWnd::s_ThreadTooMuchDataNotificationMessage = WM_USER + 2;
  71. const UINT CHiddenWnd::s_ThreadHaveDataNotificationMessage = WM_USER + 3;
  72. const UINT CHiddenWnd::s_ThreadDoneNotificationMessage = WM_USER + 4;
  73. const UINT CHiddenWnd::s_SheetCloseNotificationMessage = WM_DSA_SHEET_CLOSE_NOTIFY; // propcfg.h
  74. const UINT CHiddenWnd::s_SheetCreateNotificationMessage = WM_DSA_SHEET_CREATE_NOTIFY; // propcfg.h
  75. const UINT CHiddenWnd::s_RefreshAllNotificationMessage = WM_USER + 7;
  76. const UINT CHiddenWnd::s_ThreadShutDownNotificationMessage = WM_USER + 8;
  77. BOOL CHiddenWnd::Create()
  78. {
  79. RECT rcPos;
  80. ZeroMemory(&rcPos, sizeof(RECT));
  81. HWND hWnd = CWindowImpl<CHiddenWnd>::Create( NULL, //HWND hWndParent,
  82. rcPos, //RECT& rcPos,
  83. NULL, //LPCTSTR szWindowName = NULL,
  84. WS_POPUP, //DWORD dwStyle = WS_CHILD | WS_VISIBLE,
  85. 0x0, //DWORD dwExStyle = 0,
  86. 0 //UINT nID = 0
  87. );
  88. return hWnd != NULL;
  89. }
  90. LRESULT CHiddenWnd::OnThreadStartNotification(UINT, WPARAM, LPARAM, BOOL&)
  91. {
  92. TRACE(_T("CHiddenWnd::OnThreadStartNotification()\n"));
  93. ASSERT(m_pCD != NULL);
  94. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_state == notStarted);
  95. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_nThreadID != 0);
  96. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_hThreadHandle != NULL);
  97. m_pCD->m_pBackgroundThreadInfo->m_state = running;
  98. return 1;
  99. }
  100. LRESULT CHiddenWnd::OnThreadShutDownNotification(UINT, WPARAM, LPARAM, BOOL&)
  101. {
  102. TRACE(_T("CHiddenWnd::OnThreadShutDownNotification()\n"));
  103. ASSERT(m_pCD != NULL);
  104. ASSERT(m_pCD->m_pBackgroundThreadInfo->m_state == shuttingDown);
  105. m_pCD->m_pBackgroundThreadInfo->m_state = terminated;
  106. return 1;
  107. }
  108. LRESULT CHiddenWnd::OnThreadTooMuchDataNotification(UINT, WPARAM wParam, LPARAM, BOOL&)
  109. {
  110. TRACE(_T("CHiddenWnd::OnThreadTooMuchDataNotification()\n"));
  111. ASSERT(m_pCD != NULL);
  112. // ingnore if we are shutting down (i.e. not running state)
  113. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  114. {
  115. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  116. m_pCD->_OnTooMuchData(pUINode);
  117. }
  118. return 1;
  119. }
  120. LRESULT CHiddenWnd::OnThreadHaveDataNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  121. {
  122. TRACE(_T("CHiddenWnd::OnThreadHaveDataNotification()\n"));
  123. ASSERT(m_pCD != NULL);
  124. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  125. CThreadQueryResult* pResult = reinterpret_cast<CThreadQueryResult*>(lParam);
  126. // ingnore if we are shutting down (i.e. not running state)
  127. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  128. {
  129. m_pCD->_OnHaveData(pUINode, pResult);
  130. }
  131. else
  132. {
  133. // going down, eat up data
  134. if (pResult != NULL)
  135. delete pResult;
  136. }
  137. return 1;
  138. }
  139. LRESULT CHiddenWnd::OnThreadDoneNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&)
  140. {
  141. HRESULT ReturnedHr = (HRESULT)lParam;
  142. ASSERT(m_pCD != NULL);
  143. // ingnore if we are shutting down (i.e. not running state)
  144. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  145. {
  146. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  147. m_pCD->_OnDone(pUINode, ReturnedHr);
  148. }
  149. return 1;
  150. }
  151. LRESULT CHiddenWnd::OnSheetCloseNotification(UINT, WPARAM wParam, LPARAM, BOOL&)
  152. {
  153. ASSERT(m_pCD != NULL);
  154. CUINode* pUINode = reinterpret_cast<CUINode*>(wParam);
  155. m_pCD->_OnSheetClose(pUINode);
  156. return 1;
  157. }
  158. LRESULT CHiddenWnd::OnSheetCreateNotification(UINT, WPARAM wParam, LPARAM, BOOL&)
  159. {
  160. ASSERT(m_pCD != NULL);
  161. PDSA_SEC_PAGE_INFO pDsaSecondaryPageInfo = reinterpret_cast<PDSA_SEC_PAGE_INFO>(wParam);
  162. ASSERT(pDsaSecondaryPageInfo != NULL);
  163. // ingnore if we are shutting down (i.e. not running state)
  164. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  165. {
  166. m_pCD->_OnSheetCreate(pDsaSecondaryPageInfo);
  167. }
  168. ::LocalFree(pDsaSecondaryPageInfo);
  169. return 1;
  170. }
  171. LRESULT CHiddenWnd::OnRefreshAllNotification(UINT, WPARAM, LPARAM, BOOL&)
  172. {
  173. ASSERT(m_pCD != NULL);
  174. // ingnore if we are shutting down (i.e. not running state)
  175. if (m_pCD->m_pBackgroundThreadInfo->m_state == running)
  176. {
  177. m_pCD->ForceRefreshAll();
  178. }
  179. return 1;
  180. }
  181. ////////////////////////////////////////////////////////////////////
  182. // CBackgroundThreadBase
  183. CBackgroundThreadBase::CBackgroundThreadBase()
  184. {
  185. m_bAutoDelete = FALSE;
  186. m_hWnd = NULL;
  187. m_pCD = NULL;
  188. }
  189. CBackgroundThreadBase::~CBackgroundThreadBase()
  190. {
  191. }
  192. BOOL CBackgroundThreadBase::Start(HWND hWnd, CDSComponentData* pCD)
  193. {
  194. // this function executes in the context of the parent thread
  195. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  196. ASSERT(::IsWindow(hWnd));
  197. m_hWnd = hWnd;
  198. m_pCD = pCD;
  199. return CreateThread();
  200. }
  201. BOOL CBackgroundThreadBase::InitInstance()
  202. {
  203. // this function executes in the context of the child thread
  204. HRESULT hr = ::CoInitialize(NULL);
  205. if (FAILED(hr))
  206. return FALSE;
  207. return SUCCEEDED(hr);
  208. }
  209. int CBackgroundThreadBase::ExitInstance()
  210. {
  211. ::CoUninitialize();
  212. PostExitNotification();
  213. // Sleep(1000);
  214. return CWinThread::ExitInstance();
  215. }
  216. BOOL CBackgroundThreadBase::PostMessageToWnd(UINT msg, WPARAM wParam, LPARAM lParam)
  217. {
  218. ASSERT(::IsWindow(m_hWnd));
  219. return ::PostMessage(m_hWnd, msg, wParam, lParam);
  220. }
  221. ////////////////////////////////////////////////////////////////////
  222. // CBackgroundThreadInfo
  223. CBackgroundThreadInfo::CBackgroundThreadInfo()
  224. {
  225. m_nThreadID = 0;
  226. m_hThreadHandle = 0;
  227. m_state = notStarted;
  228. m_pThreadObj = 0;
  229. }
  230. ////////////////////////////////////////////////////////////////////
  231. // CDispatcherThread
  232. #define WORKER_THREAD_COUNT 2
  233. CDispatcherThread::CDispatcherThread()
  234. {
  235. m_nArrCount = WORKER_THREAD_COUNT;
  236. m_pThreadInfoArr = (CBackgroundThreadInfo*)malloc(m_nArrCount*sizeof(CBackgroundThreadInfo));
  237. if (m_pThreadInfoArr != NULL)
  238. {
  239. ZeroMemory(m_pThreadInfoArr, m_nArrCount*sizeof(CBackgroundThreadInfo));
  240. }
  241. }
  242. CDispatcherThread::~CDispatcherThread()
  243. {
  244. if (m_pThreadInfoArr)
  245. {
  246. for (UINT idx = 0; idx < m_nArrCount; ++idx)
  247. {
  248. if (m_pThreadInfoArr[idx].m_pThreadObj)
  249. {
  250. delete m_pThreadInfoArr[idx].m_pThreadObj;
  251. m_pThreadInfoArr[idx].m_pThreadObj = 0;
  252. }
  253. }
  254. free(m_pThreadInfoArr);
  255. }
  256. }
  257. int CDispatcherThread::Run()
  258. {
  259. TRACE(_T("CDispatcherThread::Run() starting\n"));
  260. BOOL bShuttingDown = FALSE;
  261. MSG msg;
  262. // initialize the message pump
  263. ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  264. // get let the main thread know we are entering the loop
  265. PostMessageToWnd(CHiddenWnd::s_ThreadStartNotificationMessage,0,0);
  266. BOOL bQuit = FALSE;
  267. while(!bQuit && ::GetMessage(&msg, NULL, 0, 0))
  268. {
  269. switch(msg.message)
  270. {
  271. case DISPATCH_THREAD_RUN_MSG:
  272. {
  273. if (bShuttingDown)
  274. {
  275. // going down, eat up the message
  276. CDSThreadQueryInfo* pQueryInfo = reinterpret_cast<CDSThreadQueryInfo*>(msg.lParam);
  277. // reclaim memory in the queue
  278. delete pQueryInfo;
  279. }
  280. else
  281. {
  282. // get a thread from the thread pool
  283. UINT nEntry = GetThreadEntryFromPool();
  284. ASSERT(m_pThreadInfoArr[nEntry].m_nThreadID != 0);
  285. ASSERT(m_pThreadInfoArr[nEntry].m_state == running);
  286. // forward the processing request to the thread from the pool
  287. ::PostThreadMessage(m_pThreadInfoArr[nEntry].m_nThreadID,
  288. DISPATCH_THREAD_RUN_MSG, msg.wParam, msg.lParam);
  289. // move the thread to a busy state
  290. m_pThreadInfoArr[nEntry].m_state = busy;
  291. }
  292. }
  293. break;
  294. case DISPATCH_THREAD_DONE_MSG:
  295. {
  296. UINT nThreadID = (UINT)(msg.wParam);
  297. ReturnThreadToPool(nThreadID);
  298. }
  299. break;
  300. case THREAD_SHUTDOWN_MSG:
  301. {
  302. TRACE(L"CDispatcherThread got THREAD_SHUTDOWN_MSG\n");
  303. ASSERT(!bShuttingDown);
  304. // asked to shut down
  305. bShuttingDown = TRUE;
  306. // if no threads running, we go down immediately
  307. // otherwise we have to wait for them to terminate
  308. bQuit = BroadcastShutDownAllThreads();
  309. TRACE(L"BroadcastShutDownAllThreads() returned bQuit = %d\n", bQuit);
  310. }
  311. break;
  312. case THREAD_SHUTDOWN_ACK_MSG:
  313. {
  314. TRACE(L"CDispatcherThread got THREAD_SHUTDOWN_ACK_MSG\n");
  315. ASSERT(bShuttingDown);
  316. // worker thread has gone down
  317. UINT nThreadID = (UINT)(msg.wParam);
  318. bQuit = MarkThreadAsTerminated(nThreadID);
  319. TRACE(L"MarkThreadAsTerminated() returned bQuit = %d\n", bQuit);
  320. }
  321. break;
  322. default:
  323. {
  324. // unknown message, just let it through
  325. ::DispatchMessage(&msg);
  326. } // default
  327. } //switch
  328. } // while
  329. ASSERT(bShuttingDown);
  330. // wait now for all the thread handles to become signalled
  331. WaitForAllWorkerThreadsToExit();
  332. TRACE(_T("CDispatcherThread::Run() is terminating\n"));
  333. return ExitInstance();
  334. }
  335. void CDispatcherThread::PostExitNotification()
  336. {
  337. // we are finally done shutting down, let the main thread know
  338. // that we are going down
  339. PostMessageToWnd(CHiddenWnd::s_ThreadShutDownNotificationMessage, 0, 0);
  340. TRACE(_T("CDispatcherThread::PostExitNotification() posted thread shutdown notification\n"));
  341. }
  342. UINT CDispatcherThread::_GetEntryFromArray()
  343. {
  344. UINT nFreeSlot = m_nArrCount; // set as "not found"
  345. for (UINT k=0; k<m_nArrCount; k++)
  346. {
  347. if ( (m_pThreadInfoArr[k].m_nThreadID == 0) && (nFreeSlot == m_nArrCount))
  348. nFreeSlot = k; // remember the first free slot
  349. if ((m_pThreadInfoArr[k].m_nThreadID != 0) && (m_pThreadInfoArr[k].m_state == running))
  350. return k; // found an idle running thread
  351. }
  352. // not found any idle thread, return an empty slot
  353. if (nFreeSlot == m_nArrCount)
  354. {
  355. // no free space anymore, need to reallocate array
  356. int nAlloc = m_nArrCount*2;
  357. CBackgroundThreadInfo* temp = (CBackgroundThreadInfo*)realloc(m_pThreadInfoArr, sizeof(CBackgroundThreadInfo)*nAlloc);
  358. if (temp)
  359. {
  360. m_pThreadInfoArr = temp;
  361. ::ZeroMemory(&m_pThreadInfoArr[m_nArrCount], sizeof(CBackgroundThreadInfo)*m_nArrCount);
  362. nFreeSlot = m_nArrCount; // first free in new block
  363. m_nArrCount = nAlloc;
  364. }
  365. }
  366. return nFreeSlot;
  367. }
  368. UINT CDispatcherThread::GetThreadEntryFromPool()
  369. {
  370. UINT nEntry = _GetEntryFromArray();
  371. // if the entry is empty, need to
  372. // spawn a thread and wait it is running
  373. if (m_pThreadInfoArr[nEntry].m_nThreadID == 0)
  374. {
  375. // If there is a thread object for this entry
  376. // delete it and create a new one
  377. if (m_pThreadInfoArr[nEntry].m_pThreadObj)
  378. {
  379. delete m_pThreadInfoArr[nEntry].m_pThreadObj;
  380. m_pThreadInfoArr[nEntry].m_pThreadObj = 0;
  381. }
  382. // create the thread
  383. CWorkerThread* pThreadObj = new CWorkerThread(m_nThreadID);
  384. ASSERT(pThreadObj != NULL);
  385. if (pThreadObj == NULL)
  386. return 0;
  387. // start the the thread
  388. ASSERT(m_pThreadInfoArr[nEntry].m_hThreadHandle == NULL);
  389. ASSERT(m_pThreadInfoArr[nEntry].m_state == notStarted);
  390. if (!pThreadObj->Start(GetHiddenWnd(),GetCD()))
  391. return 0;
  392. ASSERT(pThreadObj->m_nThreadID != 0);
  393. ASSERT(pThreadObj->m_hThread != NULL);
  394. // copy the thread info we need from the thread object
  395. m_pThreadInfoArr[nEntry].m_hThreadHandle = pThreadObj->m_hThread;
  396. m_pThreadInfoArr[nEntry].m_nThreadID = pThreadObj->m_nThreadID;
  397. m_pThreadInfoArr[nEntry].m_pThreadObj = pThreadObj;
  398. // wait for the thread to start
  399. MSG msg;
  400. while(TRUE)
  401. {
  402. if (::PeekMessage(&msg,(HWND)-1,WORKER_THREAD_START_MSG, WORKER_THREAD_START_MSG,
  403. PM_REMOVE))
  404. {
  405. TRACE(_T("CDispatcherThread::GetThreadFromPool() got WORKER_THREAD_START_MSG\n"));
  406. m_pThreadInfoArr[nEntry].m_state = running;
  407. break;
  408. }
  409. } // while
  410. } // if
  411. ASSERT(m_pThreadInfoArr[nEntry].m_state == running);
  412. ASSERT(m_pThreadInfoArr[nEntry].m_nThreadID != 0);
  413. return nEntry;
  414. }
  415. void CDispatcherThread::ReturnThreadToPool(UINT nThreadID)
  416. {
  417. ASSERT(nThreadID != 0);
  418. for (UINT k=0; k<m_nArrCount; k++)
  419. {
  420. if (m_pThreadInfoArr[k].m_nThreadID == nThreadID)
  421. {
  422. // return the thread to a busy state
  423. m_pThreadInfoArr[k].m_state = running;
  424. return;
  425. }
  426. }
  427. ASSERT(FALSE); // should never get here
  428. }
  429. BOOL CDispatcherThread::BroadcastShutDownAllThreads()
  430. {
  431. BOOL bQuit = TRUE;
  432. for (UINT k=0; k<m_nArrCount; k++)
  433. {
  434. if (m_pThreadInfoArr[k].m_nThreadID != 0)
  435. {
  436. ::PostThreadMessage(m_pThreadInfoArr[k].m_nThreadID, THREAD_SHUTDOWN_MSG,0,0);
  437. bQuit = FALSE;
  438. }
  439. }
  440. TRACE(L"CDispatcherThread::BroadcastShutDownAllThreads() returning %d\n", bQuit);
  441. return bQuit;
  442. }
  443. BOOL CDispatcherThread::MarkThreadAsTerminated(UINT nThreadID)
  444. {
  445. TRACE(L"CDispatcherThread::MarkThreadAsTerminated()\n");
  446. ASSERT(nThreadID != 0);
  447. for (UINT k=0; k<m_nArrCount; k++)
  448. {
  449. if (m_pThreadInfoArr[k].m_nThreadID == nThreadID)
  450. {
  451. // mark the thread as done
  452. TRACE(L"marking thread k = %d as terminated\n", k);
  453. ASSERT(m_pThreadInfoArr[k].m_state == running);
  454. m_pThreadInfoArr[k].m_state = terminated;
  455. break;
  456. }
  457. }
  458. // check if all the threads are terminated
  459. for (k=0; k<m_nArrCount; k++)
  460. {
  461. if ((m_pThreadInfoArr[k].m_nThreadID != 0) &&
  462. (m_pThreadInfoArr[k].m_state != terminated))
  463. {
  464. // at least one thread is still running
  465. return FALSE;
  466. }
  467. }
  468. // all the threads are gone (terminated state)
  469. return TRUE;
  470. }
  471. void CDispatcherThread::WaitForAllWorkerThreadsToExit()
  472. {
  473. TRACE(L"CDispatcherThread::WaitForAllWorkerThreadsToExit()\n");
  474. // wait for the dispatcher thread handle to become signalled
  475. DWORD nCount = 0;
  476. HANDLE* pHandles = new HANDLE[m_nArrCount];
  477. if (!pHandles)
  478. {
  479. TRACE(L"Failed to allocate space for the handles\n");
  480. return;
  481. }
  482. ::ZeroMemory(pHandles, sizeof(HANDLE)*m_nArrCount);
  483. for (UINT k=0; k<m_nArrCount; k++)
  484. {
  485. if (m_pThreadInfoArr[k].m_nThreadID != 0)
  486. {
  487. TRACE(L"m_pThreadInfoArr[%d].m_state = %d\n", k, m_pThreadInfoArr[k].m_state);
  488. ASSERT(m_pThreadInfoArr[k].m_state == terminated);
  489. ASSERT(m_pThreadInfoArr[k].m_hThreadHandle != NULL);
  490. pHandles[nCount++] = m_pThreadInfoArr[k].m_hThreadHandle;
  491. }
  492. }
  493. if (nCount == 0)
  494. {
  495. TRACE(L"WARNING: no worker threads to wait for!!!\n");
  496. return;
  497. }
  498. TRACE(L"before WaitForThreadShutdown() loop on %d worker threads\n", nCount);
  499. WaitForThreadShutdown(pHandles, nCount);
  500. TRACE(L"after WaitForThreadShutdown() loop on worker threads\n");
  501. #if (FALSE)
  502. TRACE(L"before WaitForMultipleObjects() on worker threads\n");
  503. WaitForMultipleObjects(nCount, pHandles, TRUE /*fWaitAll*/, INFINITE);
  504. TRACE(L"after WaitForMultipleObjects() on worker threads\n");
  505. #endif
  506. delete[] pHandles;
  507. pHandles = 0;
  508. }
  509. ////////////////////////////////////////////////////////////////////
  510. // CWorkerThread
  511. CWorkerThread::CWorkerThread(UINT nParentThreadID)
  512. : m_nMaxQueueLength(99),
  513. m_currWParamCookie(0),
  514. m_nParentThreadID(nParentThreadID),
  515. m_bQuit(FALSE),
  516. m_pCurrentQueryResult(0)
  517. {
  518. ASSERT(nParentThreadID != 0);
  519. }
  520. CWorkerThread::~CWorkerThread()
  521. {
  522. ASSERT(m_pCurrentQueryResult == NULL);
  523. }
  524. int CWorkerThread::Run()
  525. {
  526. HRESULT hr = S_OK;
  527. TRACE(_T("CWorkerThread::Run() starting\n"));
  528. MSG msg;
  529. // initialize the message pump
  530. ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  531. // get let the main thread know we are entering the loop
  532. ::PostThreadMessage(m_nParentThreadID, WORKER_THREAD_START_MSG, 0,0);
  533. ASSERT(m_bQuit == FALSE);
  534. while(!m_bQuit && ::GetMessage(&msg, NULL, 0, 0))
  535. {
  536. if(msg.message == DISPATCH_THREAD_RUN_MSG)
  537. {
  538. m_currWParamCookie = msg.wParam;
  539. //::MessageBox(NULL, _T("Wait"), _T("Thread"), MB_OK);
  540. CThreadQueryInfo* pQueryInfo = reinterpret_cast<CThreadQueryInfo*>(msg.lParam);
  541. hr = GetCD()->QueryFromWorkerThread(pQueryInfo, this);
  542. // make sure we flush the result set
  543. SendCurrentQueryResult();
  544. // if we had to many items, let the hidden window know
  545. if (pQueryInfo->m_bTooMuchData)
  546. {
  547. PostMessageToWnd(CHiddenWnd::s_ThreadTooMuchDataNotificationMessage,
  548. m_currWParamCookie, (LPARAM)0);
  549. }
  550. delete pQueryInfo; // not needed anymore
  551. // tell the hidden window we are done
  552. PostMessageToWnd(CHiddenWnd::s_ThreadDoneNotificationMessage,
  553. m_currWParamCookie, (LPARAM)hr);
  554. // tell the dispatcher thread we are done processing
  555. ::PostThreadMessage(m_nParentThreadID, DISPATCH_THREAD_DONE_MSG, m_nThreadID,0);
  556. m_currWParamCookie = 0; // reset
  557. }
  558. else if (msg.message == THREAD_SHUTDOWN_MSG)
  559. {
  560. TRACE(_T("CWorkerThread::Run() got THREAD_SHUTDOWN_MSG\n"));
  561. m_bQuit = TRUE;
  562. }
  563. else
  564. {
  565. // unknown message, just let it through
  566. ::DispatchMessage(&msg);
  567. }
  568. } // while
  569. TRACE(_T("CWorkerThread::Run() is terminating\n"));
  570. return ExitInstance();
  571. }
  572. void CWorkerThread::PostExitNotification()
  573. {
  574. // we are finally done shutting down, let the main thread know
  575. // that we are going down
  576. ::PostThreadMessage(m_nParentThreadID, THREAD_SHUTDOWN_ACK_MSG, m_nThreadID,0);
  577. TRACE(_T("CWorkerThread::PostExitNotification() posted THREAD_SHUTDOWN_ACK_MSG, m_nThreadID = 0x%x\n"),
  578. m_nThreadID);
  579. }
  580. void CWorkerThread::AddToQueryResult(CUINode* pUINode)
  581. {
  582. ASSERT(!m_bQuit);
  583. if (m_pCurrentQueryResult == NULL)
  584. {
  585. m_pCurrentQueryResult = new CThreadQueryResult;
  586. }
  587. ASSERT(m_pCurrentQueryResult != NULL);
  588. m_pCurrentQueryResult->m_nodeList.AddTail(pUINode);
  589. if (m_pCurrentQueryResult->m_nodeList.GetCount() > m_nMaxQueueLength)
  590. SendCurrentQueryResult();
  591. // check to see if we are forced to abort
  592. MSG msg;
  593. if (::PeekMessage(&msg,(HWND)-1,THREAD_SHUTDOWN_MSG, THREAD_SHUTDOWN_MSG,
  594. PM_REMOVE))
  595. {
  596. TRACE(_T("CWorkerThread::AddToQueryResult() got THREAD_SHUTDOWN_MSG\n"));
  597. m_bQuit = TRUE;
  598. }
  599. }
  600. void CWorkerThread::SendCurrentQueryResult()
  601. {
  602. if(m_pCurrentQueryResult != NULL)
  603. {
  604. // wParam has the cookie, that we just ship back
  605. PostMessageToWnd(CHiddenWnd::s_ThreadHaveDataNotificationMessage,
  606. m_currWParamCookie, reinterpret_cast<LPARAM>(m_pCurrentQueryResult));
  607. m_pCurrentQueryResult = NULL;
  608. }
  609. }