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.

463 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name :
  4. abw.hxx
  5. Abstract:
  6. Declares constants, types and functions for bandwidth throttling.
  7. Author:
  8. Bilal Alam ( t-bilala ) 13-March-1997
  9. Environment:
  10. User Mode -- Win32
  11. Project:
  12. Internet Services Asynchronous Thread Queue Library
  13. Revision History:
  14. --*/
  15. typedef struct _BANDWIDTH_LEVELS {
  16. DWORD dwSpecifiedLevel;
  17. DWORD dwLowThreshold; // uses 0.90 * bwSpecifiedLevel
  18. DWORD dwHighThreshold; // uses 1.10 * bwSpecifiedLevel
  19. } BANDWIDTH_LEVELS;
  20. # define ATQ_LOW_BAND_THRESHOLD(bw) (bw.dwLowThreshold)
  21. # define ATQ_HIGH_BAND_THRESHOLD(bw) (bw.dwHighThreshold)
  22. # define CIRCULAR_INCREMENT( sm_pB, sm_rgB, size) \
  23. (sm_pB) = ((((sm_pB) + 1) < (sm_rgB)+(size)) ? (sm_pB)+1 : (sm_rgB))
  24. typedef enum {
  25. ZoneLevelLow = 0, // if MeasuredBw < Bandwidth specified
  26. ZoneLevelMedium, // if MeasuredBw approxEquals Bandwidth specified
  27. ZoneLevelHigh, // if MeasuredBw > Bandwidth specified
  28. ZoneLevelMax // just a boundary element
  29. } ZoneLevel;
  30. /*++
  31. The following array specifies the status of operations for different
  32. operations in different zones of the measured bandwidth.
  33. We split the range of bandwidth into three zones as specified in
  34. the type ZoneLevel. Depending upon the zone of operation, differet
  35. operations are enabled/disabled. Priority is given to minimize the amount
  36. of CPU work that needs to be redone when an operation is to be rejected.
  37. We block operations on which considerable amount of CPU is spent earlier.
  38. --*/
  39. static OPERATION_STATUS sm_rgStatus[ZoneLevelMax][AtqIoMaxOp] = {
  40. // For ZoneLevelLow: Allow All operations
  41. { StatusRejectOperation,
  42. StatusAllowOperation,
  43. StatusAllowOperation,
  44. StatusAllowOperation
  45. },
  46. // For ZoneLevelMedium:
  47. { StatusRejectOperation,
  48. StatusBlockOperation, // Block Read
  49. StatusAllowOperation,
  50. StatusAllowOperation
  51. },
  52. // For ZoneLevelHigh
  53. { StatusRejectOperation,
  54. StatusRejectOperation, // Reject Read
  55. StatusAllowOperation, // Allow Writes
  56. StatusBlockOperation // Block TransmitFile
  57. }
  58. };
  59. #define ATQ_BW_INFO_SIGNATURE ( (DWORD) 'BQTA')
  60. #define ATQ_BW_INFO_SIGNATURE_FREE ( (DWORD) 'BQTX')
  61. #define ATQ_BW_INFO_MAX_DESC 32
  62. /*++
  63. class BANDWIDTH_INFO
  64. This class encapsulates all the statistics and state used in the
  65. implementation of bandwidth throttling.
  66. --*/
  67. class BANDWIDTH_INFO
  68. {
  69. private:
  70. DWORD _Signature;
  71. LONG _cReference;
  72. BOOL _fIsFreed;
  73. BOOL _fPersistent;
  74. // statistics
  75. DWORD _cCurrentBlockedRequests;
  76. DWORD _cTotalBlockedRequests;
  77. DWORD _cTotalAllowedRequests;
  78. DWORD _cTotalRejectedRequests;
  79. DWORD _dwMeasuredBw;
  80. // bandwidth status members
  81. BANDWIDTH_LEVELS _bandwidth;
  82. LARGE_INTEGER _rgBytesXfered[ ATQ_HISTOGRAM_SIZE ];
  83. LARGE_INTEGER * _pBytesXferCur;
  84. LARGE_INTEGER _cbXfered;
  85. OPERATION_STATUS * _pStatus;
  86. BOOL _fEnabled;
  87. // list of blocked context manipulation
  88. CRITICAL_SECTION _csPrivateLock;
  89. LIST_ENTRY _BlockedListHead;
  90. DWORD _cMaxBlockedList;
  91. // user friendly description of this descriptor. Useful for debugging
  92. CHAR _achDescription[ ATQ_BW_INFO_MAX_DESC ];
  93. // private members shared by all BANDWIDTH_INFO objects
  94. static CRITICAL_SECTION sm_csSharedLock;
  95. static LIST_ENTRY sm_BornListHead;
  96. static LIST_ENTRY sm_ActiveListHead;
  97. static DWORD sm_cBornList;
  98. static DWORD sm_cActiveList;
  99. static ALLOC_CACHE_HANDLER * sm_pachBWInfos;
  100. static BOOL sm_fGlobalEnabled;
  101. static BOOL sm_fGlobalActive;
  102. static DWORD sm_cNonInfinite;
  103. // private member functions
  104. VOID Initialize( IN BOOL fPersistent );
  105. VOID Terminate( VOID );
  106. BOOL UnblockRequest( IN OUT PATQ_CONT pAtqContext );
  107. BOOL UpdateBandwidth( VOID );
  108. VOID Lock( VOID )
  109. {
  110. EnterCriticalSection( &_csPrivateLock );
  111. }
  112. VOID Unlock( VOID )
  113. {
  114. LeaveCriticalSection( &_csPrivateLock );
  115. }
  116. static VOID SharedLock( VOID )
  117. {
  118. EnterCriticalSection( &sm_csSharedLock );
  119. }
  120. static VOID SharedUnlock( VOID )
  121. {
  122. LeaveCriticalSection( &sm_csSharedLock );
  123. }
  124. VOID RemoveFromActiveList( VOID )
  125. // Assume caller has acquired shared lock!
  126. {
  127. sm_cActiveList--;
  128. if ( !sm_cActiveList )
  129. {
  130. sm_fGlobalActive = FALSE;
  131. }
  132. #ifndef _NO_TRACING_
  133. CHKINFO(( DBG_CONTEXT,
  134. "Removed %p (%s) from active bandwidth info list (list size = %d)\n",
  135. this,
  136. _achDescription,
  137. sm_cActiveList ));
  138. #else
  139. ATQ_PRINTF(( DBG_CONTEXT,
  140. "Removed %p (%s) from active bandwidth info list (list size = %d)\n",
  141. this,
  142. _achDescription,
  143. sm_cActiveList ));
  144. #endif
  145. RemoveEntryList( &_ActiveListEntry );
  146. _fMemberOfActiveList = FALSE;
  147. _ActiveListEntry.Flink = NULL;
  148. }
  149. VOID RemoveFromBornList( VOID )
  150. {
  151. SharedLock();
  152. sm_cBornList--;
  153. #ifndef _NO_TRACING_
  154. CHKINFO(( DBG_CONTEXT,
  155. "Removed %p (%s) from born bandwidth info list (list size = %d)\n",
  156. this,
  157. _achDescription,
  158. sm_cBornList ));
  159. #else
  160. ATQ_PRINTF(( DBG_CONTEXT,
  161. "Removed %p (%s) from born bandwidth info list (list size = %d)\n",
  162. this,
  163. _achDescription,
  164. sm_cBornList ));
  165. #endif
  166. RemoveEntryList( &_BornListEntry );
  167. _BornListEntry.Flink = NULL;
  168. // Now remove from the active list
  169. if ( _fMemberOfActiveList )
  170. {
  171. RemoveFromActiveList();
  172. }
  173. SharedUnlock();
  174. }
  175. public:
  176. LIST_ENTRY _BornListEntry;
  177. LIST_ENTRY _ActiveListEntry;
  178. BOOL _fMemberOfActiveList;
  179. static DWORD sm_cSamplesForTimeout;
  180. // public member functions
  181. VOID Reference( VOID )
  182. {
  183. InterlockedIncrement( &_cReference );
  184. }
  185. VOID Dereference( VOID )
  186. {
  187. if ( !_fPersistent && !InterlockedDecrement( &_cReference ) )
  188. {
  189. delete this;
  190. }
  191. }
  192. OPERATION_STATUS QueryStatus( ATQ_OPERATION operation ) const
  193. {
  194. return _pStatus[ operation ];
  195. }
  196. BOOL IsFreed( VOID )
  197. {
  198. return _fIsFreed;
  199. }
  200. VOID IncTotalBlockedRequests( VOID )
  201. {
  202. INC_ATQ_COUNTER( _cTotalBlockedRequests );
  203. }
  204. DWORD QueryTotalBlockedRequests( VOID ) const
  205. {
  206. return _cTotalBlockedRequests;
  207. }
  208. VOID IncTotalAllowedRequests( VOID )
  209. {
  210. INC_ATQ_COUNTER( _cTotalAllowedRequests );
  211. }
  212. DWORD QueryTotalAllowedRequests( VOID ) const
  213. {
  214. return _cTotalAllowedRequests;
  215. }
  216. VOID IncTotalRejectedRequests( VOID )
  217. {
  218. INC_ATQ_COUNTER( _cTotalRejectedRequests );
  219. }
  220. DWORD QueryTotalRejectedRequests( VOID ) const
  221. {
  222. return _cTotalRejectedRequests;
  223. }
  224. VOID IncCurrentBlockedRequests( VOID )
  225. {
  226. INC_ATQ_COUNTER( _cCurrentBlockedRequests );
  227. }
  228. DWORD QueryCurrentBlockedRequests( VOID ) const
  229. {
  230. return _cCurrentBlockedRequests;
  231. }
  232. VOID DecCurrentBlockedRequests( VOID )
  233. {
  234. DEC_ATQ_COUNTER( _cCurrentBlockedRequests );
  235. }
  236. DWORD QueryMeasuredBw( VOID ) const
  237. {
  238. return _dwMeasuredBw;
  239. }
  240. BOOL Enabled( VOID ) const
  241. {
  242. return _fEnabled;
  243. }
  244. DWORD QuerySignature( VOID ) const
  245. {
  246. return _Signature;
  247. }
  248. DWORD QueryMaxBlockedSize( VOID ) const
  249. {
  250. return _cMaxBlockedList;
  251. }
  252. VOID SetMaxBlockedSize( DWORD Size )
  253. {
  254. _cMaxBlockedList = Size;
  255. }
  256. VOID AddToActiveList( VOID )
  257. {
  258. if ( _fEnabled && !_fMemberOfActiveList )
  259. {
  260. SharedLock();
  261. if ( _fEnabled && !_fMemberOfActiveList )
  262. {
  263. sm_cActiveList++;
  264. #ifndef _NO_TRACING_
  265. CHKINFO(( DBG_CONTEXT,
  266. "Added %p (%s) to active bandwidth info list (list size = %d)\n",
  267. this,
  268. _achDescription,
  269. sm_cActiveList ));
  270. #else
  271. ATQ_PRINTF(( DBG_CONTEXT,
  272. "Added %p (%s) to active bandwidth info list (list size = %d)\n",
  273. this,
  274. _achDescription,
  275. sm_cActiveList ));
  276. #endif
  277. InsertTailList( &sm_ActiveListHead, &_ActiveListEntry );
  278. _fMemberOfActiveList = TRUE;
  279. sm_fGlobalActive = TRUE;
  280. }
  281. SharedUnlock();
  282. }
  283. }
  284. VOID AddToBornList( VOID )
  285. {
  286. SharedLock();
  287. sm_cBornList++;
  288. InsertTailList( &sm_BornListHead, &_BornListEntry );
  289. SharedUnlock();
  290. }
  291. BOOL UpdateBytesXfered( IN PATQ_CONT pAtqContext,
  292. IN DWORD cbIo )
  293. {
  294. if ( _fEnabled )
  295. {
  296. Lock();
  297. _pBytesXferCur->QuadPart = _pBytesXferCur->QuadPart + cbIo;
  298. Unlock();
  299. }
  300. return TRUE;
  301. }
  302. CHAR * QueryDescription( VOID ) const
  303. {
  304. // :(
  305. #if DBG
  306. return (CHAR*) _achDescription;
  307. #else
  308. return NULL;
  309. #endif
  310. }
  311. VOID SetDescription( CHAR * pszDescription )
  312. {
  313. #if DBG
  314. Lock();
  315. strncpy( _achDescription,
  316. pszDescription ? pszDescription : "Unknown",
  317. sizeof( _achDescription ) );
  318. Unlock();
  319. #endif
  320. }
  321. BANDWIDTH_INFO( IN BOOL fPersistent )
  322. {
  323. Initialize( fPersistent );
  324. }
  325. ~BANDWIDTH_INFO( VOID )
  326. {
  327. Terminate();
  328. }
  329. BOOL PrepareToFree( VOID );
  330. BOOL RemoveFromBlockedList( IN PATQ_CONT patqContext );
  331. BOOL BlockRequest( IN OUT PATQ_CONT patqContext );
  332. DWORD SetBandwidthLevel( IN DWORD Data );
  333. BOOL CheckAndUnblockRequests( VOID );
  334. DWORD SetMaxBlockedListSize( IN DWORD Data );
  335. DWORD QueryBandwidthLevel( VOID );
  336. BOOL ClearStatistics( VOID );
  337. BOOL GetStatistics( OUT ATQ_STATISTICS * patqStats );
  338. static BOOL GlobalActive( VOID )
  339. {
  340. return sm_fGlobalActive;
  341. }
  342. static BOOL GlobalEnabled( VOID )
  343. {
  344. return sm_fGlobalEnabled;
  345. }
  346. static BOOL AbwInitialize( VOID );
  347. static BOOL AbwTerminate( VOID );
  348. static BOOL UpdateAllBandwidths( VOID );
  349. void * operator new( size_t s )
  350. {
  351. ATQ_ASSERT( s == sizeof( BANDWIDTH_INFO ));
  352. // allocate from allocation cache.
  353. ATQ_ASSERT( sm_pachBWInfos != NULL );
  354. return (sm_pachBWInfos->Alloc());
  355. }
  356. void operator delete( void * pBandwidthInfo )
  357. {
  358. ATQ_ASSERT( pBandwidthInfo != NULL );
  359. // free to the allocation pool
  360. ATQ_ASSERT( NULL != sm_pachBWInfos );
  361. ATQ_REQUIRE( sm_pachBWInfos->Free( pBandwidthInfo ) );
  362. return;
  363. }
  364. };
  365. typedef BANDWIDTH_INFO * PBANDWIDTH_INFO;