Source code of Windows XP (NT5)
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.

471 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. StatusAllowOperation,
  46. StatusAllowOperation,
  47. },
  48. // For ZoneLevelMedium:
  49. { StatusRejectOperation,
  50. StatusBlockOperation, // Block Read
  51. StatusAllowOperation,
  52. StatusAllowOperation,
  53. StatusAllowOperation,
  54. StatusAllowOperation
  55. },
  56. // For ZoneLevelHigh
  57. { StatusRejectOperation,
  58. StatusRejectOperation, // Reject Read
  59. StatusAllowOperation, // Allow Writes
  60. StatusBlockOperation, // Block TransmitFile
  61. StatusBlockOperation, // Block TransmitFileAndRecv
  62. StatusAllowOperation // Allow SendAndRecv
  63. }
  64. };
  65. #define ATQ_BW_INFO_SIGNATURE ( (DWORD) 'BQTA')
  66. #define ATQ_BW_INFO_SIGNATURE_FREE ( (DWORD) 'BQTX')
  67. #define ATQ_BW_INFO_MAX_DESC 32
  68. /*++
  69. class BANDWIDTH_INFO
  70. This class encapsulates all the statistics and state used in the
  71. implementation of bandwidth throttling.
  72. --*/
  73. class BANDWIDTH_INFO
  74. {
  75. private:
  76. DWORD _Signature;
  77. LONG _cReference;
  78. BOOL _fIsFreed;
  79. BOOL _fPersistent;
  80. // statistics
  81. DWORD _cCurrentBlockedRequests;
  82. DWORD _cTotalBlockedRequests;
  83. DWORD _cTotalAllowedRequests;
  84. DWORD _cTotalRejectedRequests;
  85. DWORD _dwMeasuredBw;
  86. // bandwidth status members
  87. BANDWIDTH_LEVELS _bandwidth;
  88. LARGE_INTEGER _rgBytesXfered[ ATQ_HISTOGRAM_SIZE ];
  89. LARGE_INTEGER * _pBytesXferCur;
  90. LARGE_INTEGER _cbXfered;
  91. OPERATION_STATUS * _pStatus;
  92. BOOL _fEnabled;
  93. // list of blocked context manipulation
  94. CRITICAL_SECTION _csPrivateLock;
  95. LIST_ENTRY _BlockedListHead;
  96. DWORD _cMaxBlockedList;
  97. // user friendly description of this descriptor. Useful for debugging
  98. #if DBG
  99. CHAR _achDescription[ ATQ_BW_INFO_MAX_DESC ];
  100. #endif
  101. // private members shared by all BANDWIDTH_INFO objects
  102. static CRITICAL_SECTION sm_csSharedLock;
  103. static LIST_ENTRY sm_BornListHead;
  104. static LIST_ENTRY sm_ActiveListHead;
  105. static DWORD sm_cBornList;
  106. static DWORD sm_cActiveList;
  107. static ALLOC_CACHE_HANDLER * sm_pachBWInfos;
  108. static BOOL sm_fGlobalEnabled;
  109. static BOOL sm_fGlobalActive;
  110. static DWORD sm_cNonInfinite;
  111. // private member functions
  112. VOID Initialize( IN BOOL fPersistent );
  113. VOID Terminate( VOID );
  114. BOOL UnblockRequest( IN OUT PATQ_CONT pAtqContext );
  115. BOOL UpdateBandwidth( VOID );
  116. VOID Lock( VOID )
  117. {
  118. EnterCriticalSection( &_csPrivateLock );
  119. }
  120. VOID Unlock( VOID )
  121. {
  122. LeaveCriticalSection( &_csPrivateLock );
  123. }
  124. static VOID SharedLock( VOID )
  125. {
  126. EnterCriticalSection( &sm_csSharedLock );
  127. }
  128. static VOID SharedUnlock( VOID )
  129. {
  130. LeaveCriticalSection( &sm_csSharedLock );
  131. }
  132. VOID RemoveFromActiveList( VOID )
  133. // Assume caller has acquired shared lock!
  134. {
  135. sm_cActiveList--;
  136. if ( !sm_cActiveList )
  137. {
  138. sm_fGlobalActive = FALSE;
  139. }
  140. #ifndef _NO_TRACING_
  141. CHKINFO(( DBG_CONTEXT,
  142. "Removed %p (%s) from active bandwidth info list (list size = %d)\n",
  143. this,
  144. _achDescription,
  145. sm_cActiveList ));
  146. #else
  147. ATQ_PRINTF(( DBG_CONTEXT,
  148. "Removed %p (%s) from active bandwidth info list (list size = %d)\n",
  149. this,
  150. _achDescription,
  151. sm_cActiveList ));
  152. #endif
  153. RemoveEntryList( &_ActiveListEntry );
  154. _fMemberOfActiveList = FALSE;
  155. _ActiveListEntry.Flink = NULL;
  156. }
  157. VOID RemoveFromBornList( VOID )
  158. {
  159. SharedLock();
  160. sm_cBornList--;
  161. #ifndef _NO_TRACING_
  162. CHKINFO(( DBG_CONTEXT,
  163. "Removed %p (%s) from born bandwidth info list (list size = %d)\n",
  164. this,
  165. _achDescription,
  166. sm_cBornList ));
  167. #else
  168. ATQ_PRINTF(( DBG_CONTEXT,
  169. "Removed %p (%s) from born bandwidth info list (list size = %d)\n",
  170. this,
  171. _achDescription,
  172. sm_cBornList ));
  173. #endif
  174. RemoveEntryList( &_BornListEntry );
  175. _BornListEntry.Flink = NULL;
  176. // Now remove from the active list
  177. if ( _fMemberOfActiveList )
  178. {
  179. RemoveFromActiveList();
  180. }
  181. SharedUnlock();
  182. }
  183. public:
  184. LIST_ENTRY _BornListEntry;
  185. LIST_ENTRY _ActiveListEntry;
  186. BOOL _fMemberOfActiveList;
  187. static DWORD sm_cSamplesForTimeout;
  188. // public member functions
  189. VOID Reference( VOID )
  190. {
  191. InterlockedIncrement( &_cReference );
  192. }
  193. VOID Dereference( VOID )
  194. {
  195. if ( !_fPersistent && !InterlockedDecrement( &_cReference ) )
  196. {
  197. delete this;
  198. }
  199. }
  200. OPERATION_STATUS QueryStatus( ATQ_OPERATION operation ) const
  201. {
  202. return _pStatus[ operation ];
  203. }
  204. BOOL IsFreed( VOID )
  205. {
  206. return _fIsFreed;
  207. }
  208. VOID IncTotalBlockedRequests( VOID )
  209. {
  210. INC_ATQ_COUNTER( _cTotalBlockedRequests );
  211. }
  212. DWORD QueryTotalBlockedRequests( VOID ) const
  213. {
  214. return _cTotalBlockedRequests;
  215. }
  216. VOID IncTotalAllowedRequests( VOID )
  217. {
  218. INC_ATQ_COUNTER( _cTotalAllowedRequests );
  219. }
  220. DWORD QueryTotalAllowedRequests( VOID ) const
  221. {
  222. return _cTotalAllowedRequests;
  223. }
  224. VOID IncTotalRejectedRequests( VOID )
  225. {
  226. INC_ATQ_COUNTER( _cTotalRejectedRequests );
  227. }
  228. DWORD QueryTotalRejectedRequests( VOID ) const
  229. {
  230. return _cTotalRejectedRequests;
  231. }
  232. VOID IncCurrentBlockedRequests( VOID )
  233. {
  234. INC_ATQ_COUNTER( _cCurrentBlockedRequests );
  235. }
  236. DWORD QueryCurrentBlockedRequests( VOID ) const
  237. {
  238. return _cCurrentBlockedRequests;
  239. }
  240. VOID DecCurrentBlockedRequests( VOID )
  241. {
  242. DEC_ATQ_COUNTER( _cCurrentBlockedRequests );
  243. }
  244. DWORD QueryMeasuredBw( VOID ) const
  245. {
  246. return _dwMeasuredBw;
  247. }
  248. BOOL Enabled( VOID ) const
  249. {
  250. return _fEnabled;
  251. }
  252. DWORD QuerySignature( VOID ) const
  253. {
  254. return _Signature;
  255. }
  256. DWORD QueryMaxBlockedSize( VOID ) const
  257. {
  258. return _cMaxBlockedList;
  259. }
  260. VOID SetMaxBlockedSize( DWORD Size )
  261. {
  262. _cMaxBlockedList = Size;
  263. }
  264. VOID AddToActiveList( VOID )
  265. {
  266. if ( _fEnabled && !_fMemberOfActiveList )
  267. {
  268. SharedLock();
  269. if ( _fEnabled && !_fMemberOfActiveList )
  270. {
  271. sm_cActiveList++;
  272. #ifndef _NO_TRACING_
  273. CHKINFO(( DBG_CONTEXT,
  274. "Added %p (%s) to active bandwidth info list (list size = %d)\n",
  275. this,
  276. _achDescription,
  277. sm_cActiveList ));
  278. #else
  279. ATQ_PRINTF(( DBG_CONTEXT,
  280. "Added %p (%s) to active bandwidth info list (list size = %d)\n",
  281. this,
  282. _achDescription,
  283. sm_cActiveList ));
  284. #endif
  285. InsertTailList( &sm_ActiveListHead, &_ActiveListEntry );
  286. _fMemberOfActiveList = TRUE;
  287. sm_fGlobalActive = TRUE;
  288. }
  289. SharedUnlock();
  290. }
  291. }
  292. VOID AddToBornList( VOID )
  293. {
  294. SharedLock();
  295. sm_cBornList++;
  296. InsertTailList( &sm_BornListHead, &_BornListEntry );
  297. SharedUnlock();
  298. }
  299. BOOL UpdateBytesXfered( IN PATQ_CONT pAtqContext,
  300. IN DWORD cbIo )
  301. {
  302. if ( _fEnabled )
  303. {
  304. Lock();
  305. _pBytesXferCur->QuadPart = _pBytesXferCur->QuadPart + cbIo;
  306. Unlock();
  307. }
  308. return TRUE;
  309. }
  310. CHAR * QueryDescription( VOID ) const
  311. {
  312. // :(
  313. #if DBG
  314. return (CHAR*) _achDescription;
  315. #else
  316. return NULL;
  317. #endif
  318. }
  319. VOID SetDescription( CHAR * pszDescription )
  320. {
  321. #if DBG
  322. Lock();
  323. strncpy( _achDescription,
  324. pszDescription ? pszDescription : "Unknown",
  325. sizeof( _achDescription ) );
  326. Unlock();
  327. #endif
  328. }
  329. BANDWIDTH_INFO( IN BOOL fPersistent )
  330. {
  331. Initialize( fPersistent );
  332. }
  333. ~BANDWIDTH_INFO( VOID )
  334. {
  335. Terminate();
  336. }
  337. BOOL PrepareToFree( VOID );
  338. BOOL RemoveFromBlockedList( IN PATQ_CONT patqContext );
  339. BOOL BlockRequest( IN OUT PATQ_CONT patqContext );
  340. DWORD SetBandwidthLevel( IN DWORD Data );
  341. BOOL CheckAndUnblockRequests( VOID );
  342. DWORD SetMaxBlockedListSize( IN DWORD Data );
  343. DWORD QueryBandwidthLevel( VOID );
  344. BOOL ClearStatistics( VOID );
  345. BOOL GetStatistics( OUT ATQ_STATISTICS * patqStats );
  346. static BOOL GlobalActive( VOID )
  347. {
  348. return sm_fGlobalActive;
  349. }
  350. static BOOL GlobalEnabled( VOID )
  351. {
  352. return sm_fGlobalEnabled;
  353. }
  354. static BOOL AbwInitialize( VOID );
  355. static BOOL AbwTerminate( VOID );
  356. static BOOL UpdateAllBandwidths( VOID );
  357. void * operator new( size_t s )
  358. {
  359. ATQ_ASSERT( s == sizeof( BANDWIDTH_INFO ));
  360. // allocate from allocation cache.
  361. ATQ_ASSERT( sm_pachBWInfos != NULL );
  362. return (sm_pachBWInfos->Alloc());
  363. }
  364. void operator delete( void * pBandwidthInfo )
  365. {
  366. ATQ_ASSERT( pBandwidthInfo != NULL );
  367. // free to the allocation pool
  368. ATQ_ASSERT( NULL != sm_pachBWInfos );
  369. ATQ_REQUIRE( sm_pachBWInfos->Free( pBandwidthInfo ) );
  370. return;
  371. }
  372. };
  373. typedef BANDWIDTH_INFO * PBANDWIDTH_INFO;