worker.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 9k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //  worker.cpp
  2. //
  3. //      Implementation of the worker thread object
  4. //
  5. #include "priv.h"
  6. // Do not build this file if on Win9X or NT4
  7. #ifndef DOWNLEVEL_PLATFORM
  8. #include "resource.h"
  9. #include "worker.h"
  10. //--------------------------------------------------------------------
  11. //
  12. //
  13. //  CWorkerThread class
  14. //
  15. //
  16. //--------------------------------------------------------------------
  17. //  CWorkerThread constructor
  18. CWorkerThread::CWorkerThread() : _cRef(1)
  19. {
  20.     ASSERT(NULL == _hthreadWorker);
  21.     ASSERT(NULL == _hwndWorker);
  22.     ASSERT(FALSE == _fKillWorker);
  23.     ASSERT(NULL == _pwe);
  24.     ASSERT(0 == _cRefLockWorker);
  25.     InitializeCriticalSection(&_csWorker);
  26.     DllAddRef();
  27. }
  28. //  CWorkerThread destructor
  29. CWorkerThread::~CWorkerThread()
  30. {
  31.     ASSERT(0 == _cRefLockWorker);
  32.     SetListenerWT(NULL);
  33.     DeleteCriticalSection(&_csWorker);
  34.     DllRelease();
  35. }
  36. BOOL CWorkerThread::PostWorkerMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  37. {
  38.     BOOL bRet = FALSE;
  39.     _LockWorker();
  40.     // Only if we are not being killed, and the worker window is valid we
  41.     // post the message, we don't want to post to NULL window (desktop)
  42.     if (!_fKillWorker && _hwndWorker)
  43.         bRet = PostMessage(_hwndWorker, uMsg, wParam, lParam);
  44.     _UnlockWorker();
  45.     return bRet;
  46. }
  47. /*--------------------------------------------------------------------
  48. Purpose: IUnknown::QueryInterface
  49. */
  50. STDMETHODIMP CWorkerThread::QueryInterface(REFIID riid, LPVOID * ppvObj)
  51. {
  52.     static const QITAB qit[] = {
  53.         QITABENT(CWorkerThread, IARPWorker),
  54.         { 0 },
  55.     };
  56.     return QISearch(this, (LPCQITAB)qit, riid, ppvObj);
  57. }
  58. STDMETHODIMP_(ULONG) CWorkerThread::AddRef()
  59. {
  60.     LONG cRef = InterlockedIncrement(&_cRef);
  61.     TraceAddRef(CWorkerThread, cRef);
  62.     return cRef;
  63. }
  64. STDMETHODIMP_(ULONG) CWorkerThread::Release()
  65. {
  66.     LONG cRef = InterlockedDecrement(&_cRef);
  67.     TraceRelease(CWorkerThread, cRef);
  68.     if (cRef)
  69.         return cRef;
  70.     delete this;
  71.     return 0;
  72. }
  73. /*-------------------------------------------------------------------------
  74. Purpose: Sets the event listener so the worker thread can fire
  75.          events incrementally.
  76. */
  77. HRESULT CWorkerThread::SetListenerWT(IWorkerEvent * pwe)
  78. {
  79.     _LockWorker();
  80.     {
  81.         // We have to protect _pwe because it can be accessed by this
  82.         // thread and the main thread.
  83.         // Don't AddRef the event listener or we'll have a circular
  84.         // reference.
  85.         _pwe = pwe;
  86.     }
  87.     _UnlockWorker();
  88.     
  89.     return S_OK;
  90. }
  91. /*-------------------------------------------------------------------------
  92. Purpose: Start the thread
  93. */
  94. HRESULT CWorkerThread::StartWT(int iPriority)
  95. {
  96.     DWORD thid;     // Not used but we have to pass something in
  97.     // Create a hidden top-level window to post messages to from the
  98.     // worker thread
  99.     _hwndWorker = SHCreateWorkerWindow(_WorkerWndProcWrapper, NULL, 0, 0, NULL, this);
  100.     if (_hwndWorker)
  101.     {
  102.         AddRef(); // AddRef myself, the background thread is responsible of releasing
  103.         // this ref count
  104.         // Kick off the worker thread to do the slow enumeration.
  105.         _hthreadWorker = CreateThread(NULL, 0,
  106.                                       (LPTHREAD_START_ROUTINE)_ThreadStartProcWrapper,
  107.                                       (LPVOID)this, CREATE_SUSPENDED, &thid);
  108.         if (_hthreadWorker)
  109.         {
  110.             // Demote the priority so it doesn't interfere with the
  111.             // initial HTML databinding.
  112.             SetThreadPriority(_hthreadWorker, iPriority);
  113.             ResumeThread(_hthreadWorker);
  114.         }
  115.         else
  116.         {
  117.             // Release my refcount in case of failure
  118.             Release();
  119.             // If we can't create the background thread, don't bother with the window
  120.             DestroyWindow(_hwndWorker);
  121.             _hwndWorker = NULL;
  122.         }
  123.     }
  124.     return (_hthreadWorker != NULL) ? S_OK : E_FAIL;
  125. }
  126. /*-------------------------------------------------------------------------
  127. Purpose: Kills the worker thread if one is around
  128. */
  129. HRESULT CWorkerThread::KillWT(void)
  130. {
  131.     MSG msg;
  132.     // I should never call KillWT to kill myself
  133.     ASSERT(_hthreadWorker != GetCurrentThread());
  134.     
  135.     TraceMsg(TF_TASKS, "[%x] Killing worker thread...", _dwThreadId);
  136.     // Tell the worker thread to stop when it can
  137.     // Do this inside the critical section because we don't want random messages
  138.     // get posted to the worker window after this. 
  139.     _LockWorker();
  140.     _fKillWorker = TRUE;
  141.     _UnlockWorker();
  142.     
  143.     // If we have no worker thread, nothing to do
  144.     if (_hthreadWorker)
  145.     {
  146.         // Now wait for the worker to stop
  147.         if (WaitForSingleObject(_hthreadWorker, 10000) == WAIT_TIMEOUT)
  148.             TraceMsg(TF_ERROR, "[%x] Worker thread termination wait timed out!", _dwThreadId);
  149.         else
  150.             TraceMsg(TF_TASKS, "[%x] Worker thread wait exited cleanly", _dwThreadId);
  151.         // Now that the thread is stopped, release our hold so all its memory can go away
  152.         CloseHandle(_hthreadWorker);
  153.         _hthreadWorker = NULL;
  154.     }
  155.     
  156.     // Make sure that all messages to our worker HWND get processed
  157.     if (_hwndWorker)
  158.     {
  159.         while (PeekMessage(&msg, _hwndWorker, 0, 0, PM_REMOVE))
  160.             DispatchMessage(&msg);
  161.         DestroyWindow(_hwndWorker);
  162.         _hwndWorker = NULL;
  163.     }
  164.     SetListenerWT(NULL);
  165.     return S_OK;
  166. }
  167. //--------------------------------------------------------------------
  168. // Private methods
  169. void CWorkerThread::_LockWorker(void)
  170. {
  171.     EnterCriticalSection(&_csWorker);
  172.     DEBUG_CODE( _cRefLockWorker++; )
  173. }
  174. void CWorkerThread::_UnlockWorker(void)
  175. {
  176.     DEBUG_CODE( _cRefLockWorker--; )
  177.     LeaveCriticalSection(&_csWorker);
  178. }
  179. /*-------------------------------------------------------------------------
  180. Purpose: Static wndproc wrapper. Calls the real non-static WndProc.
  181. */
  182. LRESULT
  183. CALLBACK
  184. CWorkerThread::_WorkerWndProcWrapper(
  185.     HWND hwnd,
  186.     UINT uMsg,
  187.     WPARAM wParam,
  188.     LPARAM lParam
  189.     )
  190. {
  191.     if (uMsg == WM_DESTROY)
  192.         SetWindowLong(hwnd, 0, 0);
  193.     else
  194.     {
  195.         CWorkerThread * pWorker = (CWorkerThread*)GetWindowLong(hwnd, 0);
  196.         if (pWorker)
  197.             return pWorker->_WorkerWndProc(hwnd, uMsg, wParam, lParam);
  198.     }
  199.     return 0;
  200. }
  201. /*-------------------------------------------------------------------------
  202. Purpose: Used to fire events back to Trident since they can't be fired from
  203.          the worker thread.
  204. */
  205. LRESULT
  206. CWorkerThread::_WorkerWndProc(
  207.     HWND hwnd,
  208.     UINT uMsg,
  209.     WPARAM wParam,
  210.     LPARAM lParam
  211.     )
  212. {
  213.     switch (uMsg)
  214.     {
  215.     case WORKERWIN_FIRE_ROW_READY:  
  216.         // Posted by worker thread when async data is ready
  217.         _LockWorker();
  218.         {
  219.             if (_pwe)
  220.             {
  221.                 TraceMsg(TF_TASKS, "[%x] Firing event for row #%d", _dwThreadId, wParam);
  222.                 _pwe->FireOnDataReady((LONG)wParam);
  223.             }
  224.         }
  225.         _UnlockWorker();
  226.         return 0;
  227.         
  228.     case WORKERWIN_FIRE_FINISHED:   
  229.         // Posted by worker thread when thread is finished enumerating
  230.         // async data.
  231.         _LockWorker();
  232.         {
  233.             if (_pwe)
  234.             {
  235.                 TraceMsg(TF_TASKS, "[%x] Firing finished", _dwThreadId);
  236.                 _pwe->FireOnFinished();
  237.             }
  238.         }
  239.         _UnlockWorker();
  240.         return 0;
  241.     case WORKERWIN_FIRE_DATASETCHANGED:
  242.         // Posted by worker thread when matrix array finished enumerating
  243.         _LockWorker();
  244.         {
  245.             if (_pwe)
  246.             {
  247.                 TraceMsg(TF_TASKS, "[%x] Firing DatasetChanged", _dwThreadId);
  248.                 _pwe->FireOnDatasetChanged();
  249.             }
  250.         }
  251.         _UnlockWorker();
  252.         return 0;
  253.     }
  254.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  255. }
  256. /*-------------------------------------------------------------------------
  257. Purpose: Start and exit of worker thread to do slow app information
  258. */
  259. DWORD
  260. CALLBACK
  261. CWorkerThread::_ThreadStartProcWrapper(
  262.     LPVOID lpParam          // this pointer of object since wrapper is static
  263.     )
  264. {
  265.     CWorkerThread * pwt = (CWorkerThread *)lpParam;
  266.     pwt->_dwThreadId = GetCurrentThreadId();
  267.     
  268.     return pwt->_ThreadStartProc();
  269. }
  270. /*-------------------------------------------------------------------------
  271. Purpose: Contains the code run on the worker thread where we get the slow
  272.          information about applications
  273. */
  274. DWORD
  275. CWorkerThread::_ThreadStartProc()
  276. {
  277.     // Don't bother killing the worker window here, let the main thread take care
  278.     // of the life time of the worker window.
  279.     
  280.     // Signal that we don't have a worker thread anymore. Prevents race
  281.     // conditions.
  282.     _fKillWorker = FALSE;
  283.     TraceMsg(TF_TASKS, "[%x] Exiting worker thread", _dwThreadId);
  284.     // Release the ref count to "this" object at end of thread, be it CMtxArray or CDataSrc  because we
  285.     // AddRef()ed before this thread started. 
  286.     Release();
  287.     return 0;
  288. }
  289. #endif //DOWNLEVEL_PLATFORM