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.

259 lines
5.9 KiB

  1. #include "stock.h"
  2. #pragma hdrstop
  3. #include "runtask.h"
  4. #define SUPERCLASS
  5. // #define TF_RUNTASK TF_GENERAL
  6. #define TF_RUNTASK 0
  7. // #define TF_RUNTASKV TF_CUSTOM1 // verbose version
  8. #define TF_RUNTASKV 0
  9. // constructor
  10. CRunnableTask::CRunnableTask(DWORD dwFlags)
  11. {
  12. _lState = IRTIR_TASK_NOT_RUNNING;
  13. _dwFlags = dwFlags;
  14. ASSERT(NULL == _hDone);
  15. if (_dwFlags & RTF_SUPPORTKILLSUSPEND)
  16. {
  17. // we signal this on suspend or kill
  18. // Explicitly call the ANSI version so we don't need to worry
  19. // about whether we're being built UNICODE and have to switch
  20. // to a wrapper function...
  21. _hDone = CreateEventA(NULL, TRUE, FALSE, NULL);
  22. }
  23. #ifdef DEBUG
  24. _dwTaskID = GetTickCount();
  25. TraceMsg(TF_RUNTASK, "CRunnableTask (%#lx): creating task", _dwTaskID);
  26. #endif
  27. _cRef = 1;
  28. }
  29. // destructor
  30. CRunnableTask::~CRunnableTask()
  31. {
  32. DEBUG_CODE( TraceMsg(TF_RUNTASK, "CRunnableTask (%#lx): deleting task", _dwTaskID); )
  33. if (_hDone)
  34. CloseHandle(_hDone);
  35. }
  36. STDMETHODIMP CRunnableTask::QueryInterface( REFIID riid, LPVOID * ppvObj )
  37. {
  38. if ( ppvObj == NULL )
  39. {
  40. return E_INVALIDARG;
  41. }
  42. if ( riid == IID_IRunnableTask )
  43. {
  44. *ppvObj = SAFECAST( this, IRunnableTask *);
  45. AddRef();
  46. }
  47. else
  48. return E_NOINTERFACE;
  49. return NOERROR;
  50. }
  51. STDMETHODIMP_(ULONG) CRunnableTask::AddRef()
  52. {
  53. InterlockedIncrement(&_cRef);
  54. return _cRef;
  55. }
  56. STDMETHODIMP_ (ULONG) CRunnableTask::Release()
  57. {
  58. if (0 == _cRef)
  59. {
  60. AssertMsg(0, TEXT("CRunnableTask::Release called too many times!"));
  61. return 0;
  62. }
  63. if ( InterlockedDecrement(&_cRef) == 0)
  64. {
  65. delete this;
  66. return 0;
  67. }
  68. return _cRef;
  69. }
  70. /*----------------------------------------------------------
  71. Purpose: IRunnableTask::Run method
  72. This does a lot of the state-related work, and then
  73. calls the derived-class's RunRT() method.
  74. */
  75. STDMETHODIMP CRunnableTask::Run(void)
  76. {
  77. HRESULT hr = E_FAIL;
  78. // Are we already running?
  79. if (_lState == IRTIR_TASK_RUNNING)
  80. {
  81. // Yes; nothing to do
  82. hr = S_FALSE;
  83. }
  84. else if ( _lState == IRTIR_TASK_PENDING )
  85. {
  86. hr = E_FAIL;
  87. }
  88. else if ( _lState == IRTIR_TASK_NOT_RUNNING )
  89. {
  90. // Say we're running
  91. LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_RUNNING);
  92. if ( lRes == IRTIR_TASK_PENDING )
  93. {
  94. _lState = IRTIR_TASK_FINISHED;
  95. return NOERROR;
  96. }
  97. if (_lState == IRTIR_TASK_RUNNING)
  98. {
  99. // Prepare to run
  100. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): initialize to run", _dwTaskID); )
  101. hr = RunInitRT();
  102. ASSERT(E_PENDING != hr);
  103. }
  104. if (SUCCEEDED(hr))
  105. {
  106. if (_lState == IRTIR_TASK_RUNNING)
  107. {
  108. // Continue to do the work
  109. hr = InternalResumeRT();
  110. }
  111. else if (_lState == IRTIR_TASK_SUSPENDED)
  112. {
  113. // it is possible that RunInitRT took a little longer to complete and our state changed
  114. // from running to suspended with _hDone signaled, which would cause us to not call
  115. // internal resume. We simulate internal resume here
  116. if (_hDone)
  117. ResetEvent(_hDone);
  118. hr = E_PENDING;
  119. }
  120. }
  121. if (FAILED(hr) && E_PENDING != hr)
  122. {
  123. DEBUG_CODE( TraceMsg(TF_WARNING, "CRunnableTask (%#lx): task failed to run: %#lx", _dwTaskID, hr); )
  124. }
  125. // Are we finished?
  126. if (_lState != IRTIR_TASK_SUSPENDED || hr != E_PENDING)
  127. {
  128. // Yes
  129. _lState = IRTIR_TASK_FINISHED;
  130. }
  131. }
  132. return hr;
  133. }
  134. /*----------------------------------------------------------
  135. Purpose: IRunnableTask::Kill method
  136. */
  137. STDMETHODIMP CRunnableTask::Kill(BOOL fWait)
  138. {
  139. if ( !(_dwFlags & RTF_SUPPORTKILLSUSPEND) )
  140. return E_NOTIMPL;
  141. if (_lState != IRTIR_TASK_RUNNING)
  142. return S_FALSE;
  143. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): killing task", _dwTaskID); )
  144. LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_PENDING);
  145. if (lRes == IRTIR_TASK_FINISHED)
  146. {
  147. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): task already finished", _dwTaskID); )
  148. _lState = lRes;
  149. }
  150. else if (_hDone)
  151. {
  152. // signal the event it is likely to be waiting on
  153. SetEvent(_hDone);
  154. }
  155. return KillRT(fWait);
  156. }
  157. /*----------------------------------------------------------
  158. Purpose: IRunnableTask::Suspend method
  159. */
  160. STDMETHODIMP CRunnableTask::Suspend( void )
  161. {
  162. if ( !(_dwFlags & RTF_SUPPORTKILLSUSPEND) )
  163. return E_NOTIMPL;
  164. if (_lState != IRTIR_TASK_RUNNING)
  165. return E_FAIL;
  166. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): suspending task", _dwTaskID); )
  167. LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_SUSPENDED);
  168. if (IRTIR_TASK_FINISHED == lRes)
  169. {
  170. // we finished before we could suspend
  171. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): task already finished", _dwTaskID); )
  172. _lState = lRes;
  173. return NOERROR;
  174. }
  175. if (_hDone)
  176. SetEvent(_hDone);
  177. return SuspendRT();
  178. }
  179. /*----------------------------------------------------------
  180. Purpose: IRunnableTask::Resume method
  181. */
  182. STDMETHODIMP CRunnableTask::Resume(void)
  183. {
  184. if (_lState != IRTIR_TASK_SUSPENDED)
  185. return E_FAIL;
  186. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): resuming task", _dwTaskID); )
  187. _lState = IRTIR_TASK_RUNNING;
  188. if (_hDone)
  189. ResetEvent(_hDone);
  190. return ResumeRT();
  191. }
  192. /*----------------------------------------------------------
  193. Purpose: IRunnableTask::IsRunning method
  194. */
  195. STDMETHODIMP_( ULONG ) CRunnableTask:: IsRunning ( void )
  196. {
  197. return _lState;
  198. }