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.

185 lines
4.3 KiB

  1. /*---------------------------------------------------------------------------
  2. File: TPooledDispatch.cpp
  3. Comments: Implementation of thread pool.
  4. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  5. Proprietary and confidential to Mission Critical Software, Inc.
  6. REVISION LOG ENTRY
  7. Revision By: Christy Boles
  8. Revised on 02/22/99 11:48:28
  9. ---------------------------------------------------------------------------
  10. */
  11. #ifdef USE_STDAFX
  12. #include "StdAfx.h"
  13. #else
  14. #include <windows.h>
  15. #endif
  16. #include "Common.hpp"
  17. #include "UString.hpp"
  18. #include "Tnode.hpp"
  19. #include "TPool.h"
  20. // maximum number of jobs allowed
  21. #define MAX_COUNT 5000000
  22. // executes a job from the thread pool
  23. int
  24. Job::Run()
  25. {
  26. MCSASSERT(m_pStartRoutine);
  27. m_Status = JobStatusRunning;
  28. m_ThreadID = GetCurrentThreadId();
  29. m_timeStarted = GetTickCount();
  30. m_result = (m_pStartRoutine)(m_pArgs);
  31. m_timeEnded = GetTickCount();
  32. m_Status = JobStatusFinished;
  33. return m_result;
  34. }
  35. // Thread entry point function used by all threads in the job pool
  36. // waits for a job and then executes it
  37. DWORD __stdcall
  38. ThreadEntryPoint(
  39. void * arg // in - pointer to job pool
  40. )
  41. {
  42. MCSASSERT(arg);
  43. TJobDispatcher * pPool = (TJobDispatcher *)arg;
  44. DWORD result = 0;
  45. BOOL bAbort = FALSE;
  46. do
  47. {
  48. if ( ! pPool->SignalForJob() )
  49. {
  50. // Now there should be a job waiting for us!
  51. Job * pJob = pPool->GetAvailableJob();
  52. if ( pJob )
  53. {
  54. result = pJob->Run();
  55. }
  56. else
  57. {
  58. bAbort = TRUE;
  59. }
  60. }
  61. else
  62. {
  63. result = (int)GetLastError();
  64. bAbort = TRUE;
  65. }
  66. }
  67. while ( ! bAbort );
  68. pPool->ThreadFinished();
  69. return result;
  70. }
  71. void
  72. TJobDispatcher::InitThreadPool(
  73. DWORD nThreads // in - number of threads to use
  74. )
  75. {
  76. BOOL bExisted;
  77. DWORD rc;
  78. DWORD ThreadID;
  79. HANDLE hThread;
  80. rc = m_sem.Create(NULL,0,MAX_COUNT, &bExisted);
  81. if ( ! rc && ! bExisted )
  82. {
  83. m_numThreads = nThreads;
  84. m_numActiveThreads = m_numThreads;
  85. // Construct the threads
  86. for ( UINT i = 0 ; i < nThreads ; i++ )
  87. {
  88. hThread = CreateThread(NULL,0,&ThreadEntryPoint,this,0,&ThreadID);
  89. if(hThread)
  90. {
  91. CloseHandle(hThread);
  92. }
  93. }
  94. }
  95. }
  96. DWORD // ret- OS return code
  97. TJobDispatcher::SignalForJob()
  98. {
  99. return m_sem.WaitSingle();
  100. }
  101. Job *
  102. TJobDispatcher::GetAvailableJob()
  103. {
  104. Job * pJob = NULL;
  105. if ( ! m_Aborting )
  106. {
  107. // get the first job from the 'waiting' list
  108. pJob = m_JobsWaiting.GetFirstJob();
  109. // and put it in the 'in progress' list
  110. if ( pJob )
  111. {
  112. m_JobsInProgress.InsertBottom(pJob);
  113. }
  114. else
  115. {
  116. MCSASSERT(m_JobsWaiting.Count() == 0);
  117. }
  118. }
  119. return pJob;
  120. }
  121. // Causes threads to stop when they finish their current job
  122. // any jobs that are waiting will not be executed.
  123. void
  124. TJobDispatcher::ShutdownThreads()
  125. {
  126. m_Aborting = TRUE;
  127. m_sem.Release(m_numThreads);
  128. // wait until all of our threads have exited, so we don't delete the thread pool out from under them.
  129. while ( m_numActiveThreads > 0 )
  130. {
  131. Sleep(100);
  132. }
  133. }
  134. // This function returns when all jobs are completed
  135. void TJobDispatcher::WaitForCompletion()
  136. {
  137. while ( UnfinishedJobs() )
  138. {
  139. Sleep(1000);
  140. }
  141. }
  142. // This functions returns the number of jobs that have not yet completed
  143. int
  144. TJobDispatcher::UnfinishedJobs()
  145. {
  146. int nUnfinished = 0;
  147. TNodeListEnum e;
  148. Job * j;
  149. nUnfinished += m_JobsWaiting.Count();
  150. for ( j = (Job*)e.OpenFirst(&m_JobsInProgress) ; j ; j = (Job*)e.Next() )
  151. {
  152. if ( j->GetStatus() != Job::JobStatusFinished )
  153. nUnfinished++;
  154. }
  155. return nUnfinished;
  156. }