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.

434 lines
14 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ThreadPool.h
  6. * Content: Functions to manage a thread pool
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 03/01/99 jtk Derived from Utils.h
  12. ***************************************************************************/
  13. #ifndef __THREAD_POOL_H__
  14. #define __THREAD_POOL_H__
  15. //**********************************************************************
  16. // Constant definitions
  17. //**********************************************************************
  18. //
  19. // max handles that can be waited on for Win9x
  20. //
  21. #define MAX_WIN9X_HANDLE_COUNT 64
  22. //
  23. // job definitions
  24. //
  25. typedef enum _JOB_TYPE
  26. {
  27. JOB_UNINITIALIZED, // uninitialized value
  28. JOB_DELAYED_COMMAND, // callback provided
  29. JOB_REFRESH_TIMER_JOBS, // revisit timer jobs
  30. } JOB_TYPE;
  31. //**********************************************************************
  32. // Macro definitions
  33. //**********************************************************************
  34. //**********************************************************************
  35. // Function prototypes
  36. //**********************************************************************
  37. typedef void JOB_FUNCTION( THREAD_POOL_JOB *const pJobInfo );
  38. typedef void TIMER_EVENT_CALLBACK( void *const pContext );
  39. typedef void TIMER_EVENT_COMPLETE( const HRESULT hCompletionCode, void *const pContext );
  40. typedef void DIALOG_FUNCTION( void *const pDialogContext );
  41. //
  42. // functions for managing the job pool
  43. //
  44. BOOL ThreadPoolJob_Alloc( void *pvItem, void* pvContext );
  45. void ThreadPoolJob_Get( void *pvItem, void* pvContext );
  46. void ThreadPoolJob_Release( void *pvItem );
  47. //
  48. // functions for managing the timer data pool
  49. //
  50. BOOL ModemTimerEntry_Alloc( void *pvItem, void* pvContext );
  51. void ModemTimerEntry_Get( void *pvItem, void* pvContext );
  52. void ModemTimerEntry_Release( void *pvItem );
  53. void ModemTimerEntry_Dealloc( void *pvItem );
  54. //**********************************************************************
  55. // Structure definitions
  56. //**********************************************************************
  57. //
  58. // forward class and structure references
  59. //
  60. class CDataPort;
  61. class CModemThreadPool;
  62. typedef struct _THREAD_POOL_JOB THREAD_POOL_JOB;
  63. typedef struct _WIN9X_CORE_DATA WIN9X_CORE_DATA;
  64. typedef struct _TIMER_OPERATION_ENTRY
  65. {
  66. CBilink Linkage; // list links
  67. void *pContext; // user context passed back in timer events
  68. //
  69. // timer information
  70. //
  71. UINT_PTR uRetryCount; // number of times to retry this event
  72. BOOL fRetryForever; // Boolean for retrying forever
  73. DWORD dwRetryInterval; // time between enums (milliseconds)
  74. DWORD dwIdleTimeout; // time at which the command sits idle after all retrys are complete
  75. BOOL fIdleWaitForever; // Boolean for waiting forever in idle state
  76. DWORD dwNextRetryTime; // time at which this event will fire next (milliseconds)
  77. TIMER_EVENT_CALLBACK *pTimerCallback; // callback for when this event fires
  78. TIMER_EVENT_COMPLETE *pTimerComplete; // callback for when this event is complete
  79. #undef DPF_MODNAME
  80. #define DPF_MODNAME "_TIMER_OPERATION_ENTRY::TimerOperationFromLinkage"
  81. static _TIMER_OPERATION_ENTRY *TimerOperationFromLinkage( CBilink *const pLinkage )
  82. {
  83. DNASSERT( pLinkage != NULL );
  84. DBG_CASSERT( OFFSETOF( _TIMER_OPERATION_ENTRY, Linkage ) == 0 );
  85. return reinterpret_cast<_TIMER_OPERATION_ENTRY*>( pLinkage );
  86. }
  87. } TIMER_OPERATION_ENTRY;
  88. //**********************************************************************
  89. // Variable definitions
  90. //**********************************************************************
  91. //**********************************************************************
  92. // Class prototypes
  93. //**********************************************************************
  94. //
  95. // class for thread pool
  96. //
  97. class CModemThreadPool
  98. {
  99. public:
  100. void Lock( void ) { DNEnterCriticalSection( &m_Lock ); }
  101. void Unlock( void ) { DNLeaveCriticalSection( &m_Lock ); }
  102. void LockReadData( void ) { DNEnterCriticalSection( &m_IODataLock ); }
  103. void UnlockReadData( void ) { DNLeaveCriticalSection( &m_IODataLock ); }
  104. void LockWriteData( void ) { DNEnterCriticalSection( &m_IODataLock ); }
  105. void UnlockWriteData( void ) { DNLeaveCriticalSection( &m_IODataLock ); }
  106. #undef DPF_MODNAME
  107. #define DPF_MODNAME "CModemThreadPool::AddRef"
  108. void AddRef( void )
  109. {
  110. DNASSERT( m_iRefCount != 0 );
  111. DNInterlockedIncrement( &m_iRefCount );
  112. }
  113. #undef DPF_MODNAME
  114. #define DPF_MODNAME "CModemThreadPool::DecRef"
  115. void DecRef( void )
  116. {
  117. DNASSERT( m_iRefCount != 0 );
  118. if ( DNInterlockedDecrement( &m_iRefCount ) == 0 )
  119. {
  120. ReturnSelfToPool();
  121. }
  122. }
  123. static BOOL PoolAllocFunction( void* pvItem, void* pvContext );
  124. static void PoolInitFunction( void* pvItem, void* pvContext );
  125. static void PoolDeallocFunction( void* pvItem );
  126. BOOL Initialize( void );
  127. void Deinitialize( void );
  128. #ifdef WINNT
  129. #undef DPF_MODNAME
  130. #define DPF_MODNAME "CModemThreadPool::GetIOCompletionPort"
  131. HANDLE GetIOCompletionPort( void ) const
  132. {
  133. DNASSERT( m_hIOCompletionPort != NULL );
  134. return m_hIOCompletionPort;
  135. }
  136. #endif // WINNT
  137. //
  138. // functions for handling I/O data
  139. //
  140. CModemReadIOData *CreateReadIOData( void );
  141. void ReturnReadIOData( CModemReadIOData *const pReadIOData );
  142. CModemWriteIOData *CreateWriteIOData( void );
  143. void ReturnWriteIOData( CModemWriteIOData *const pWriteData );
  144. #ifdef WIN95
  145. #undef DPF_MODNAME
  146. #define DPF_MODNAME "CModemThreadPool::ReinsertInReadList"
  147. void ReinsertInReadList( CModemReadIOData *const pReadIOData )
  148. {
  149. //
  150. // Win9x operations are removed from the active list when they
  151. // complete and need to be readded if they're going to be reattempted.
  152. // WinNT doesn't remove items from the list until they're processed.
  153. //
  154. DNASSERT( pReadIOData != NULL );
  155. DNASSERT( pReadIOData->m_OutstandingReadListLinkage.IsEmpty() != FALSE );
  156. LockReadData();
  157. pReadIOData->m_OutstandingReadListLinkage.InsertBefore( &m_OutstandingReadList );
  158. UnlockReadData();
  159. }
  160. #endif // WIN95
  161. //
  162. // TAPI functions
  163. //
  164. const TAPI_INFO *GetTAPIInfo( void ) const { return &m_TAPIInfo; }
  165. BOOL TAPIAvailable( void ) const { return m_fTAPIAvailable; }
  166. HRESULT SubmitDelayedCommand( JOB_FUNCTION *const pFunction,
  167. JOB_FUNCTION *const pCancelFunction,
  168. void *const pContext );
  169. HRESULT SubmitTimerJob( const UINT_PTR uRetryCount,
  170. const BOOL fRetryForever,
  171. const DWORD dwRetryInterval,
  172. const BOOL fIdleWaitForever,
  173. const DWORD dwIdleTimeout,
  174. TIMER_EVENT_CALLBACK *const pTimerCallbackFunction,
  175. TIMER_EVENT_COMPLETE *const pTimerCompleteFunction,
  176. void *const pContext );
  177. BOOL StopTimerJob( void *const pContext, const HRESULT hCommandResult );
  178. //
  179. // thread functions
  180. //
  181. HRESULT SpawnDialogThread( DIALOG_FUNCTION *const pDialogFunction, void *const pDialogContext );
  182. LONG GetIntendedThreadCount( void ) const { return m_iIntendedThreadCount; }
  183. void SetIntendedThreadCount( const LONG iIntendedThreadCount ) { m_iIntendedThreadCount = iIntendedThreadCount; }
  184. LONG ThreadCount( void ) const { return m_iTotalThreadCount; }
  185. #ifdef WINNT
  186. LONG NTCompletionThreadCount( void ) const { return m_iNTCompletionThreadCount; }
  187. #endif // WINNT
  188. void IncrementActiveThreadCount( void ) { DNInterlockedIncrement( const_cast<LONG*>( &m_iTotalThreadCount ) ); }
  189. void DecrementActiveThreadCount( void ) { DNInterlockedDecrement( const_cast<LONG*>( &m_iTotalThreadCount ) ); }
  190. #ifdef WINNT
  191. void IncrementActiveNTCompletionThreadCount( void )
  192. {
  193. IncrementActiveThreadCount();
  194. DNInterlockedIncrement( const_cast<LONG*>( &m_iNTCompletionThreadCount ) );
  195. }
  196. void DecrementActiveNTCompletionThreadCount( void )
  197. {
  198. DNInterlockedDecrement( const_cast<LONG*>( &m_iNTCompletionThreadCount ) );
  199. DecrementActiveThreadCount();
  200. }
  201. #endif // WINNT
  202. HRESULT GetIOThreadCount( LONG *const piThreadCount );
  203. HRESULT SetIOThreadCount( const LONG iMaxThreadCount );
  204. BOOL IsThreadCountReductionAllowed( void ) const { return m_fAllowThreadCountReduction; }
  205. HRESULT PreventThreadPoolReduction( void );
  206. //
  207. // data port handle functions
  208. //
  209. HRESULT CreateDataPortHandle( CDataPort *const pDataPort );
  210. void CloseDataPortHandle( CDataPort *const pDataPort );
  211. CDataPort *DataPortFromHandle( const DPNHANDLE hDataPort );
  212. protected:
  213. private:
  214. BYTE m_Sig[4]; // debugging signature ('THPL')
  215. volatile LONG m_iRefCount;
  216. #ifndef DPNBUILD_ONLYONETHREAD
  217. DNCRITICAL_SECTION m_Lock; // local lock
  218. #endif // !DPNBUILD_ONLYONETHREAD
  219. volatile LONG m_iTotalThreadCount; // number of active threads
  220. #ifdef WINNT
  221. volatile LONG m_iNTCompletionThreadCount; // count of NT I/O completion threads
  222. HANDLE m_hIOCompletionPort; // I/O completion port for NT
  223. #endif // WINNT
  224. BOOL m_fAllowThreadCountReduction; // Boolean indicating that the thread count is locked from being reduced
  225. LONG m_iIntendedThreadCount; // how many threads will be started
  226. DNHANDLE m_hStopAllThreads; // handle used to stop all non-I/O completion threads
  227. #ifdef WIN95
  228. DNHANDLE m_hSendComplete; // send complete on a data port
  229. DNHANDLE m_hReceiveComplete; // receive complete on a data port
  230. DNHANDLE m_hTAPIEvent; // handle to be used for TAPI messages, this handle is not closed on exit
  231. DNHANDLE m_hFakeTAPIEvent; // Fake TAPI event so the Win9x threads can always wait on a fixed
  232. // number of events. If TAPI cannot be initialzed, this event needs to be
  233. // created and copied to m_hTAPIEvent (though it will never be signalled)
  234. #endif // WIN95
  235. //
  236. // Handle table to prevent TAPI messages from going to CModemPorts when
  237. // they're no longer in use.
  238. //
  239. CHandleTable m_DataPortHandleTable;
  240. //
  241. // list of pending network operations, it doesn't really matter if they're
  242. // reads or writes, they're just pending. Since serial isn't under extreme
  243. // loads, share one lock for all of the data
  244. //
  245. #ifndef DPNBUILD_ONLYONETHREAD
  246. DNCRITICAL_SECTION m_IODataLock; // lock for all read data
  247. #endif // !DPNBUILD_ONLYONETHREAD
  248. CBilink m_OutstandingReadList; // list of outstanding reads
  249. CBilink m_OutstandingWriteList; // list of outstanding writes
  250. //
  251. // The Job data lock covers all items through and including m_fNTTimerThreadRunning
  252. //
  253. #ifndef DPNBUILD_ONLYONETHREAD
  254. DNCRITICAL_SECTION m_JobDataLock; // lock for job queue/pool
  255. #endif // !DPNBUILD_ONLYONETHREAD
  256. CJobQueue m_JobQueue; // job queue
  257. //
  258. // Data used by the the timer thread. This data is protected by m_TimerDataLock.
  259. // This data is cleaned by the timer thread. Since only one timer thread
  260. // is allowed to run at any given time, the status of the NT timer thread
  261. // can be determined by m_fNTEnumThreadRunning. Win9x doesn't have a timer
  262. // thread, the main thread loop is timed.
  263. //
  264. #ifndef DPNBUILD_ONLYONETHREAD
  265. DNCRITICAL_SECTION m_TimerDataLock;
  266. #endif // !DPNBUILD_ONLYONETHREAD
  267. CBilink m_TimerJobList;
  268. #ifdef WINNT
  269. BOOL m_fNTTimerThreadRunning;
  270. #endif // WINNT
  271. //
  272. // TAPI information. This is required to be in the thread pool because
  273. // it's needed for thread initialzation.
  274. //
  275. BOOL m_fTAPIAvailable;
  276. TAPI_INFO m_TAPIInfo;
  277. struct
  278. {
  279. BOOL fTAPILoaded : 1;
  280. BOOL fLockInitialized : 1;
  281. BOOL fIODataLockInitialized : 1;
  282. BOOL fJobDataLockInitialized : 1;
  283. BOOL fTimerDataLockInitialized : 1;
  284. BOOL fDataPortHandleTableInitialized :1 ;
  285. BOOL fJobQueueInitialized : 1;
  286. } m_InitFlags;
  287. void LockJobData( void ) { DNEnterCriticalSection( &m_JobDataLock ); }
  288. void UnlockJobData( void ) { DNLeaveCriticalSection( &m_JobDataLock ); }
  289. void LockTimerData( void ) { DNEnterCriticalSection( &m_TimerDataLock ); }
  290. void UnlockTimerData( void ) { DNLeaveCriticalSection( &m_TimerDataLock ); }
  291. #ifdef WIN95
  292. #undef DPF_MODNAME
  293. #define DPF_MODNAME "CModemThreadPool::GetSendCompleteEvent"
  294. DNHANDLE GetSendCompleteEvent( void ) const
  295. {
  296. DNASSERT( m_hSendComplete != NULL );
  297. return m_hSendComplete;
  298. }
  299. #endif // WIN95
  300. #ifdef WIN95
  301. #undef DPF_MODNAME
  302. #define DPF_MODNAME "CModemThreadPool::GetReceiveCompleteEvent"
  303. DNHANDLE GetReceiveCompleteEvent( void ) const
  304. {
  305. DNASSERT( m_hReceiveComplete != NULL );
  306. return m_hReceiveComplete;
  307. }
  308. #endif // WIN95
  309. #ifdef WIN95
  310. #undef DPF_MODNAME
  311. #define DPF_MODNAME "CModemThreadPool::GetTAPIMessageEvent"
  312. DNHANDLE GetTAPIMessageEvent( void ) const
  313. {
  314. DNASSERT( m_hTAPIEvent != NULL );
  315. return m_hTAPIEvent;
  316. }
  317. #endif // WIN95
  318. #ifdef WINNT
  319. HRESULT WinNTInit( void );
  320. #else // WIN95
  321. HRESULT Win9xInit( void );
  322. #endif // WINNT
  323. BOOL ProcessTimerJobs( const CBilink *const pJobList, DWORD *const pdwNextJobTime);
  324. BOOL ProcessTimedOperation( TIMER_OPERATION_ENTRY *const pJob,
  325. const DWORD dwCurrentTime,
  326. DWORD *const pdwNextJobTime );
  327. #ifdef WINNT
  328. HRESULT StartNTTimerThread( void );
  329. void WakeNTTimerThread( void );
  330. #endif // WINNT
  331. void RemoveTimerOperationEntry( TIMER_OPERATION_ENTRY *const pTimerOperationData, const HRESULT hReturnCode );
  332. #ifdef WIN95
  333. void CompleteOutstandingSends( const DNHANDLE hSendCompleteEvent );
  334. void CompleteOutstandingReceives( const DNHANDLE hReceiveCompleteEvent );
  335. static DWORD WINAPI PrimaryWin9xThread( void *pParam );
  336. #endif // WIN95
  337. #ifdef WINNT
  338. static DWORD WINAPI WinNTIOCompletionThread( void *pParam );
  339. static DWORD WINAPI WinNTTimerThread( void *pParam );
  340. #endif // WINNT
  341. static DWORD WINAPI DialogThreadProc( void *pParam );
  342. HRESULT SubmitWorkItem( THREAD_POOL_JOB *const pJob );
  343. THREAD_POOL_JOB *GetWorkItem( void );
  344. #ifdef WIN95
  345. void ProcessWin9xEvents( WIN9X_CORE_DATA *const pCoreData );
  346. void ProcessWin9xJob( WIN9X_CORE_DATA *const pCoreData );
  347. #endif // WIN95
  348. void ProcessTapiEvent( void );
  349. #ifdef WINNT
  350. void StartNTCompletionThread( void );
  351. #endif // WINNT
  352. void StopAllThreads( void );
  353. // void CancelOutstandingJobs( void );
  354. void CancelOutstandingIO( void );
  355. void ReturnSelfToPool( void );
  356. //
  357. // prevent unwarranted copies
  358. //
  359. CModemThreadPool( const CModemThreadPool & );
  360. CModemThreadPool& operator=( const CModemThreadPool & );
  361. };
  362. #undef DPF_MODNAME
  363. #endif // __THREAD_POOL_H__