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.

253 lines
6.1 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. return InterlockedIncrement(&_cRef);
  54. }
  55. STDMETHODIMP_ (ULONG) CRunnableTask::Release()
  56. {
  57. AssertMsg( 0 != _cRef, TEXT("RefCount problem.") );
  58. ULONG cRef = InterlockedDecrement(&_cRef);
  59. if ( 0 == cRef )
  60. {
  61. delete this;
  62. }
  63. return cRef;
  64. }
  65. /*----------------------------------------------------------
  66. Purpose: IRunnableTask::Run method
  67. This does a lot of the state-related work, and then
  68. calls the derived-class's RunRT() method.
  69. */
  70. STDMETHODIMP CRunnableTask::Run(void)
  71. {
  72. HRESULT hr = E_FAIL;
  73. // Are we already running?
  74. if (_lState == IRTIR_TASK_RUNNING)
  75. {
  76. // Yes; nothing to do
  77. hr = S_FALSE;
  78. }
  79. else if ( _lState == IRTIR_TASK_PENDING )
  80. {
  81. hr = E_FAIL;
  82. }
  83. else if ( _lState == IRTIR_TASK_NOT_RUNNING )
  84. {
  85. // Say we're running
  86. LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_RUNNING);
  87. if ( lRes == IRTIR_TASK_PENDING )
  88. {
  89. _lState = IRTIR_TASK_FINISHED;
  90. return NOERROR;
  91. }
  92. if (_lState == IRTIR_TASK_RUNNING)
  93. {
  94. // Prepare to run
  95. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): initialize to run", _dwTaskID); )
  96. hr = RunInitRT();
  97. ASSERT(E_PENDING != hr);
  98. }
  99. if (SUCCEEDED(hr))
  100. {
  101. if (_lState == IRTIR_TASK_RUNNING)
  102. {
  103. // Continue to do the work
  104. hr = InternalResumeRT();
  105. }
  106. else if (_lState == IRTIR_TASK_SUSPENDED)
  107. {
  108. // it is possible that RunInitRT took a little longer to complete and our state changed
  109. // from running to suspended with _hDone signaled, which would cause us to not call
  110. // internal resume. We simulate internal resume here
  111. if (_hDone)
  112. ResetEvent(_hDone);
  113. hr = E_PENDING;
  114. }
  115. }
  116. if (FAILED(hr) && E_PENDING != hr)
  117. {
  118. DEBUG_CODE( TraceMsg(TF_WARNING, "CRunnableTask (%#lx): task failed to run: %#lx", _dwTaskID, hr); )
  119. }
  120. // Are we finished?
  121. if (_lState != IRTIR_TASK_SUSPENDED || hr != E_PENDING)
  122. {
  123. // Yes
  124. _lState = IRTIR_TASK_FINISHED;
  125. }
  126. }
  127. return hr;
  128. }
  129. /*----------------------------------------------------------
  130. Purpose: IRunnableTask::Kill method
  131. */
  132. STDMETHODIMP CRunnableTask::Kill(BOOL fWait)
  133. {
  134. if ( !(_dwFlags & RTF_SUPPORTKILLSUSPEND) )
  135. return E_NOTIMPL;
  136. if (_lState != IRTIR_TASK_RUNNING)
  137. return S_FALSE;
  138. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): killing task", _dwTaskID); )
  139. LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_PENDING);
  140. if (lRes == IRTIR_TASK_FINISHED)
  141. {
  142. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): task already finished", _dwTaskID); )
  143. _lState = lRes;
  144. }
  145. else if (_hDone)
  146. {
  147. // signal the event it is likely to be waiting on
  148. SetEvent(_hDone);
  149. }
  150. return KillRT(fWait);
  151. }
  152. /*----------------------------------------------------------
  153. Purpose: IRunnableTask::Suspend method
  154. */
  155. STDMETHODIMP CRunnableTask::Suspend( void )
  156. {
  157. if ( !(_dwFlags & RTF_SUPPORTKILLSUSPEND) )
  158. return E_NOTIMPL;
  159. if (_lState != IRTIR_TASK_RUNNING)
  160. return E_FAIL;
  161. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): suspending task", _dwTaskID); )
  162. LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_SUSPENDED);
  163. if (IRTIR_TASK_FINISHED == lRes)
  164. {
  165. // we finished before we could suspend
  166. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): task already finished", _dwTaskID); )
  167. _lState = lRes;
  168. return NOERROR;
  169. }
  170. if (_hDone)
  171. SetEvent(_hDone);
  172. return SuspendRT();
  173. }
  174. /*----------------------------------------------------------
  175. Purpose: IRunnableTask::Resume method
  176. */
  177. STDMETHODIMP CRunnableTask::Resume(void)
  178. {
  179. if (_lState != IRTIR_TASK_SUSPENDED)
  180. return E_FAIL;
  181. DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): resuming task", _dwTaskID); )
  182. _lState = IRTIR_TASK_RUNNING;
  183. if (_hDone)
  184. ResetEvent(_hDone);
  185. return ResumeRT();
  186. }
  187. /*----------------------------------------------------------
  188. Purpose: IRunnableTask::IsRunning method
  189. */
  190. STDMETHODIMP_( ULONG ) CRunnableTask:: IsRunning ( void )
  191. {
  192. return _lState;
  193. }