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.

181 lines
4.4 KiB

  1. //
  2. // Copyright (c) 2001 Microsoft Corporation. All rights reserved.
  3. //
  4. // Declaration of CWorkerThread.
  5. //
  6. #include "stdinc.h"
  7. #include <process.h>
  8. #include "workthread.h"
  9. unsigned int __stdcall WorkerThread(LPVOID lpThreadParameter)
  10. {
  11. reinterpret_cast<CWorkerThread*>(lpThreadParameter)->Main();
  12. return 0;
  13. }
  14. HRESULT
  15. CWorkerThread::Create()
  16. {
  17. if (m_hThread)
  18. return S_FALSE;
  19. if (!m_hEvent)
  20. return E_FAIL; // The constructor was unable to create the event we'll need to run the thread so we can't create it.
  21. m_hrCOM = E_FAIL;
  22. m_fEnd = false;
  23. m_hThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, WorkerThread, this, 0, &m_uiThreadId));
  24. return m_hThread ? S_OK : E_FAIL;
  25. }
  26. void
  27. CWorkerThread::Terminate(bool fWaitForThreadToExit)
  28. {
  29. if (!m_hThread)
  30. return;
  31. EnterCriticalSection(&m_CriticalSection);
  32. m_fEnd = true;
  33. SetEvent(m_hEvent);
  34. LeaveCriticalSection(&m_CriticalSection);
  35. if (fWaitForThreadToExit)
  36. {
  37. // Wait until the other thread stops processing.
  38. WaitForSingleObject(m_hThread, INFINITE);
  39. }
  40. CloseHandle(m_hThread);
  41. m_hThread = NULL;
  42. }
  43. CWorkerThread::CWorkerThread(bool fUsesCOM, bool fDeferCreation)
  44. : m_hThread(NULL),
  45. m_uiThreadId(0),
  46. m_fUsesCOM(fUsesCOM)
  47. {
  48. InitializeCriticalSection(&m_CriticalSection);
  49. // Note: on pre-Blackcomb OS's, this call can raise an exception; if it
  50. // ever pops in stress, we can add an exception handler and retry loop.
  51. m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  52. if (!m_hEvent)
  53. return;
  54. if (!fDeferCreation)
  55. Create();
  56. }
  57. CWorkerThread::~CWorkerThread()
  58. {
  59. Terminate(false);
  60. CloseHandle(m_hEvent);
  61. DeleteCriticalSection(&m_CriticalSection);
  62. }
  63. HRESULT CWorkerThread::Call(FunctionPointer pfn, void *pvParams, UINT cbParams, bool fBlock)
  64. {
  65. if (!m_hThread)
  66. return E_FAIL;
  67. if (fBlock && GetCurrentThreadId() == m_uiThreadId)
  68. {
  69. // The call is already on this thread so just do it.
  70. pfn(pvParams);
  71. return S_OK;
  72. }
  73. TListItem<CallInfo> *pItem = new TListItem<CallInfo>;
  74. if (!pItem)
  75. return E_OUTOFMEMORY;
  76. CallInfo &rinfo = pItem->GetItemValue();
  77. rinfo.pfn = pfn;
  78. rinfo.hEventOut = fBlock ? CreateEvent(NULL, FALSE, FALSE, NULL) : 0;
  79. if (rinfo.hEventOut)
  80. {
  81. // Synchronous call -- OK to reference via pointer to params
  82. rinfo.pvParams = pvParams;
  83. }
  84. else
  85. {
  86. // Asynchronous call -- need to copy params
  87. rinfo.pvParams = new char[cbParams];
  88. if (!rinfo.pvParams)
  89. {
  90. delete pItem;
  91. return E_OUTOFMEMORY;
  92. }
  93. CopyMemory(rinfo.pvParams, pvParams, cbParams);
  94. }
  95. EnterCriticalSection(&m_CriticalSection);
  96. m_Calls.AddHead(pItem);
  97. HANDLE hEventCall = rinfo.hEventOut; // Can't refer to rinfo after we set the event because the worker will delete the event.
  98. SetEvent(m_hEvent);
  99. LeaveCriticalSection(&m_CriticalSection);
  100. if (hEventCall)
  101. {
  102. WaitForSingleObject(hEventCall, INFINITE);
  103. if (FAILED(m_hrCOM))
  104. return m_hrCOM;
  105. CloseHandle(hEventCall);
  106. }
  107. return S_OK;
  108. }
  109. void CWorkerThread::Main()
  110. {
  111. if (m_fUsesCOM)
  112. {
  113. m_hrCOM = CoInitialize(NULL);
  114. if (FAILED(m_hrCOM))
  115. {
  116. Trace(1, "Error: CoInitialize failed: 0x%08x.\n", m_hrCOM);
  117. }
  118. }
  119. for (;;)
  120. {
  121. // block until there's something to do
  122. WaitForSingleObject(m_hEvent, INFINITE);
  123. EnterCriticalSection(&m_CriticalSection);
  124. // check for end
  125. if (m_fEnd)
  126. {
  127. LeaveCriticalSection(&m_CriticalSection);
  128. if (m_fUsesCOM && SUCCEEDED(m_hrCOM))
  129. CoUninitialize();
  130. _endthreadex(0);
  131. }
  132. // take all the list items
  133. TListItem<CallInfo> *m_pCallHead = m_Calls.GetHead();
  134. m_Calls.RemoveAll();
  135. LeaveCriticalSection(&m_CriticalSection);
  136. // call each function
  137. TListItem<CallInfo> *m_pCall = m_pCallHead;
  138. while (m_pCall)
  139. {
  140. CallInfo &rinfo = m_pCall->GetItemValue();
  141. if (SUCCEEDED(m_hrCOM))
  142. rinfo.pfn(rinfo.pvParams);
  143. if (rinfo.hEventOut)
  144. SetEvent(rinfo.hEventOut);
  145. else
  146. delete[] rinfo.pvParams;
  147. TListItem<CallInfo> *m_pNext = m_pCall->GetNext();
  148. delete m_pCall;
  149. m_pCall = m_pNext;
  150. }
  151. }
  152. }