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.

273 lines
5.9 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1997, Microsoft Corporation
  4. //
  5. // File: thrdpool.cpp
  6. //
  7. // Contents: implementation of thrdpool library
  8. //
  9. // Description: See header file.
  10. //
  11. // Functions:
  12. //
  13. // History: 03/15/97 Rajeev Rajan (rajeevr) Created
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include <windows.h>
  17. #include <thrdpool.h>
  18. #include <dbgtrace.h>
  19. LONG CWorkerThread::m_lInitCount = -1 ;
  20. HANDLE CWorkerThread::m_hCompletionPort = NULL ;
  21. BOOL
  22. CWorkerThread::InitClass( DWORD dwConcurrency )
  23. {
  24. TraceFunctEnter("CWorkerThread::InitClass");
  25. if( InterlockedIncrement( &m_lInitCount ) == 0 )
  26. {
  27. //
  28. // called for the first time - go ahead with initialization
  29. //
  30. m_hCompletionPort = CreateIoCompletionPort(
  31. INVALID_HANDLE_VALUE,
  32. NULL,
  33. 0,
  34. dwConcurrency
  35. );
  36. if( !m_hCompletionPort ) {
  37. ErrorTrace(0, "Failed to create completion port: GetLastError is %d", GetLastError());
  38. return FALSE ;
  39. }
  40. } else
  41. {
  42. //
  43. // bogus Init or already called
  44. //
  45. InterlockedDecrement( &m_lInitCount );
  46. return FALSE ;
  47. }
  48. DebugTrace(0,"Created completion port 0x%x", m_hCompletionPort);
  49. TraceFunctLeave();
  50. return TRUE ;
  51. }
  52. BOOL
  53. CWorkerThread::TermClass()
  54. {
  55. TraceFunctEnter("CWorkerThread::TermClass");
  56. if( InterlockedDecrement( &m_lInitCount ) < 0 )
  57. {
  58. //
  59. // Init has been called so go ahead with termination
  60. //
  61. _ASSERT( m_hCompletionPort );
  62. _VERIFY( CloseHandle( m_hCompletionPort ) );
  63. return TRUE ;
  64. }
  65. return FALSE ;
  66. }
  67. CWorkerThread::CWorkerThread() : m_hThread(NULL), m_hShutdownEvent( NULL )
  68. {
  69. DWORD dwThreadId;
  70. TraceFunctEnter("CWorkerThread::CWorkerThread");
  71. //
  72. // create shutdown event
  73. //
  74. if( !(m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL) ) ) {
  75. ErrorTrace(0,"Failed to create shutdown event");
  76. _ASSERT( FALSE );
  77. return;
  78. }
  79. //
  80. // create worker thread
  81. //
  82. if (!(m_hThread = ::CreateThread(
  83. NULL,
  84. 0,
  85. ThreadDispatcher,
  86. this,
  87. CREATE_SUSPENDED,
  88. &dwThreadId))) {
  89. ErrorTrace(0,"Failed to create thread: error: %d", GetLastError());
  90. _ASSERT( FALSE );
  91. }
  92. else
  93. {
  94. _VERIFY( ResumeThread( m_hThread ) != 0xFFFFFFFF );
  95. }
  96. TraceFunctLeave();
  97. return;
  98. }
  99. CWorkerThread::~CWorkerThread()
  100. {
  101. TraceFunctEnter("CWorkerThread::~CWorkerThread");
  102. _ASSERT( m_hCompletionPort );
  103. _ASSERT( m_hThread );
  104. _ASSERT( m_hShutdownEvent );
  105. //
  106. // signal worker thread to shutdown
  107. // this depends on derived class completion routines
  108. // checking this event - if they dont, we will block
  109. // till the thread finishes.
  110. //
  111. _VERIFY( SetEvent( m_hShutdownEvent ) );
  112. //
  113. // post a null termination packet
  114. //
  115. if( !PostWork( NULL ) ) {
  116. ErrorTrace(0,"Error terminating worker thread");
  117. _ASSERT( FALSE );
  118. }
  119. //
  120. // wait for worker thread to terminate
  121. //
  122. DWORD dwWait = WaitForSingleObject(m_hThread, INFINITE);
  123. if(WAIT_OBJECT_0 != dwWait) {
  124. ErrorTrace(0,"WFSO: returned %d", dwWait);
  125. _ASSERT( FALSE );
  126. }
  127. _VERIFY( CloseHandle(m_hThread) );
  128. _VERIFY( CloseHandle(m_hShutdownEvent) );
  129. m_hThread = NULL;
  130. m_hShutdownEvent = NULL;
  131. }
  132. DWORD __stdcall CWorkerThread::ThreadDispatcher(PVOID pvWorkerThread)
  133. {
  134. //
  135. // get pointer to this CWorkerThread object
  136. //
  137. CWorkerThread *pWorkerThread = (CWorkerThread *) pvWorkerThread;
  138. //
  139. // call GetQueuedCompletionStatus() to get work completion
  140. //
  141. pWorkerThread->GetWorkCompletion();
  142. return 0;
  143. }
  144. VOID CWorkerThread::GetWorkCompletion(VOID)
  145. {
  146. DWORD dwBytesTransferred;
  147. DWORD_PTR dwCompletionKey;
  148. DWORD dwWait;
  149. LPOVERLAPPED lpo;
  150. LPWorkContextEnv lpWCE;
  151. PVOID pvWorkContext;
  152. TraceFunctEnter("CWorkerThread::GetWorkCompletion");
  153. _ASSERT( m_hThread );
  154. _ASSERT( m_hCompletionPort );
  155. do
  156. {
  157. //
  158. // wait for work items to be queued
  159. //
  160. if( !GetQueuedCompletionStatus(
  161. m_hCompletionPort,
  162. &dwBytesTransferred,
  163. &dwCompletionKey,
  164. &lpo,
  165. INFINITE // wait timeout
  166. ) )
  167. {
  168. ErrorTrace(0,"GetQueuedCompletionStatus() failed: error: %d", GetLastError());
  169. break ;
  170. }
  171. //
  172. // get a hold of the work context envelope and work context
  173. //
  174. lpWCE = (LPWorkContextEnv) lpo;
  175. pvWorkContext = lpWCE->pvWorkContext;
  176. //
  177. // check for termination packet
  178. //
  179. if( pvWorkContext == NULL ) {
  180. DebugTrace(0,"Received termination packet - bailing");
  181. delete lpWCE;
  182. lpWCE = NULL;
  183. break;
  184. }
  185. //
  186. // check for termination signal
  187. //
  188. dwWait = WaitForSingleObject( m_hShutdownEvent, 0 );
  189. //
  190. // call derived class method to process work completion
  191. //
  192. if( WAIT_TIMEOUT == dwWait ) {
  193. DebugTrace(0,"Calling WorkCompletion() routine");
  194. WorkCompletion( pvWorkContext );
  195. }
  196. //
  197. // destroy the WorkContextEnv object allocated before PostQueuedCompletionStatus()
  198. //
  199. delete lpWCE;
  200. lpWCE = NULL;
  201. } while( TRUE );
  202. return;
  203. }
  204. BOOL CWorkerThread::PostWork(PVOID pvWorkerContext)
  205. {
  206. TraceFunctEnter("CWorkerThread::PostWork");
  207. _ASSERT( m_hThread );
  208. _ASSERT( m_hCompletionPort );
  209. //
  210. // allocate a WorkContextEnv blob - this is destroyed after GetQueuedCompletionStatus()
  211. // completes ! We may want to have a pool of such blobs instead of hitting the heap !!
  212. //
  213. LPWorkContextEnv lpWCE = new WorkContextEnv;
  214. if( !lpWCE ) {
  215. ErrorTrace(0,"Failed to allocate memory");
  216. return FALSE ;
  217. }
  218. ZeroMemory( lpWCE, sizeof(WorkContextEnv) );
  219. lpWCE->pvWorkContext = pvWorkerContext;
  220. if( !PostQueuedCompletionStatus(
  221. m_hCompletionPort,
  222. 0,
  223. 0,
  224. (LPOVERLAPPED)lpWCE
  225. ) )
  226. {
  227. ErrorTrace(0,"PostQCompletionStatus() failed: error: %d", GetLastError());
  228. return FALSE ;
  229. }
  230. return TRUE;
  231. }