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.

1208 lines
32 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name :
  4. abw2.cxx
  5. Abstract:
  6. This module implements functions required for bandwidth throttling
  7. of network usage by ATQ module.
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 1-June-1995
  10. Bilal Alam ( t-bilala ) 7-March-1997
  11. Environment:
  12. User Mode -- Win32
  13. Project:
  14. Internet Services Asynchronous Thread Queue DLL
  15. --*/
  16. #include "isatq.hxx"
  17. //
  18. // Global variables
  19. //
  20. extern PBANDWIDTH_INFO g_pBandwidthInfo;
  21. //
  22. // Bandwidth Info shared variables
  23. //
  24. CRITICAL_SECTION BANDWIDTH_INFO::sm_csSharedLock;
  25. LIST_ENTRY BANDWIDTH_INFO::sm_BornListHead;
  26. LIST_ENTRY BANDWIDTH_INFO::sm_ActiveListHead;
  27. DWORD BANDWIDTH_INFO::sm_cBornList;
  28. DWORD BANDWIDTH_INFO::sm_cActiveList;
  29. ALLOC_CACHE_HANDLER* BANDWIDTH_INFO::sm_pachBWInfos;
  30. BOOL BANDWIDTH_INFO::sm_fGlobalEnabled;
  31. BOOL BANDWIDTH_INFO::sm_fGlobalActive;
  32. DWORD BANDWIDTH_INFO::sm_cNonInfinite;
  33. DWORD BANDWIDTH_INFO::sm_cSamplesForTimeout;
  34. //
  35. // BANDWIDTH_INFO methods
  36. //
  37. VOID
  38. BANDWIDTH_INFO::Initialize(
  39. IN BOOL fPersistent
  40. )
  41. /*++
  42. Initialize bandwidth info object. This is a pseudo-constructor for the
  43. class.
  44. Arguments:
  45. fPersistent - TRUE if this object is destroyed explicitly
  46. FALSE if destroyed when refcount hits 0
  47. Returns:
  48. None
  49. --*/
  50. {
  51. _fMemberOfActiveList = FALSE;
  52. _bandwidth.dwSpecifiedLevel = INFINITE;
  53. _bandwidth.dwLowThreshold = INFINITE;
  54. _bandwidth.dwHighThreshold = INFINITE;
  55. _cMaxBlockedList = INFINITE;
  56. _fEnabled = FALSE;
  57. _Signature = ATQ_BW_INFO_SIGNATURE;
  58. _fIsFreed = FALSE;
  59. _fPersistent = fPersistent;
  60. _cReference = 1;
  61. INITIALIZE_CRITICAL_SECTION( &_csPrivateLock );
  62. InitializeListHead( &_BlockedListHead );
  63. ZeroMemory( _rgBytesXfered, sizeof( _rgBytesXfered ) );
  64. _pBytesXferCur = _rgBytesXfered; // points to start of array
  65. _cbXfered.QuadPart = 0;
  66. _pStatus = &sm_rgStatus[ ZoneLevelLow ][ 0 ];
  67. ClearStatistics();
  68. AddToBornList();
  69. SetDescription( "Default" );
  70. }
  71. VOID
  72. BANDWIDTH_INFO::Terminate( VOID )
  73. /*++
  74. Destroys bandwidth info object. This is a pseudo-destructor.
  75. Arguments:
  76. None
  77. Returns:
  78. None
  79. --*/
  80. {
  81. Lock();
  82. // first prevent any new requests from getting blocked
  83. InterlockedExchangePointer( (PVOID *) &_pStatus,
  84. (PVOID) &sm_rgStatus[ZoneLevelLow][0] );
  85. // disable the descriptor
  86. InterlockedExchange( (LPLONG) &_fEnabled, FALSE );
  87. // now remove any blocked requests
  88. ATQ_REQUIRE( CheckAndUnblockRequests() );
  89. ATQ_ASSERT( _cCurrentBlockedRequests == 0 );
  90. ATQ_ASSERT( IsListEmpty( &_BlockedListHead ) );
  91. Unlock();
  92. DeleteCriticalSection( &_csPrivateLock );
  93. // remove self from shared bandwidth info list
  94. SharedLock();
  95. RemoveFromBornList();
  96. SharedUnlock();
  97. _Signature = ATQ_BW_INFO_SIGNATURE_FREE;
  98. }
  99. BOOL
  100. BANDWIDTH_INFO::PrepareToFree( VOID )
  101. {
  102. InterlockedExchange( (LPLONG) &_fIsFreed, TRUE );
  103. Dereference();
  104. return TRUE;
  105. }
  106. BOOL
  107. BANDWIDTH_INFO::BlockRequest(
  108. IN OUT PATQ_CONT pAtqContext
  109. )
  110. /*++
  111. Block this request on the queue of requests waiting to be processed.
  112. Arguments:
  113. pAtqContext pointer to ATQ context information for request that needs
  114. to be blocked.
  115. Returns:
  116. TRUE on success. FALSE if there are any errors.
  117. (Use GetLastError() for details)
  118. --*/
  119. {
  120. BOOL fRet = TRUE;
  121. ATQ_ASSERT( pAtqContext != NULL);
  122. ATQ_ASSERT( pAtqContext->Signature == ATQ_CONTEXT_SIGNATURE );
  123. ATQ_ASSERT( IsValidAtqOp( pAtqContext->arInfo.atqOp ) );
  124. Lock();
  125. if ( _cCurrentBlockedRequests == _cMaxBlockedList )
  126. {
  127. fRet = FALSE;
  128. }
  129. else
  130. {
  131. pAtqContext->SetFlag( ACF_BLOCKED );
  132. InsertTailList( &_BlockedListHead, &pAtqContext->BlockedListEntry );
  133. IncCurrentBlockedRequests();
  134. }
  135. Unlock();
  136. return fRet;
  137. }
  138. BOOL
  139. BANDWIDTH_INFO::RemoveFromBlockedList(
  140. IN PATQ_CONT pAtqContext
  141. )
  142. /*++
  143. This function forcibly removes an ATQ context from blocked list of requests.
  144. Argument:
  145. pAtqContext pointer to ATQ context whose request is in blocked list.
  146. Returns:
  147. TRUE on success and FALSE if there is any error.
  148. --*/
  149. {
  150. if ( !pAtqContext->IsBlocked() ) {
  151. // some other thread just removed this request from waiting list.
  152. return TRUE;
  153. }
  154. Lock();
  155. RemoveEntryList(&pAtqContext->BlockedListEntry);
  156. DecCurrentBlockedRequests();
  157. pAtqContext->ResetFlag( ACF_BLOCKED);
  158. Unlock();
  159. //
  160. // On such a forcible removal, we may have to make a callback indicating
  161. // failure. Ignored! To be done by the caller of this API.
  162. //
  163. return TRUE;
  164. }
  165. BOOL
  166. BANDWIDTH_INFO::UnblockRequest(
  167. IN OUT PATQ_CONT pAtqContext
  168. )
  169. /*++
  170. Unblocks this request from the queue of requests waiting to be processed.
  171. Call this function only when
  172. _pStatus[pAtqContext->atqOp] != StatusBlockOperation.
  173. First, this function removes the request from queue of requests and processes
  174. it according to status and operation to be performed.
  175. If the status is AllowRequest ==> this function restarts the operation.
  176. If the status is reject operation ==> rejects operation and invokes
  177. call back function indicating the error status.
  178. Call this function after lock()ing
  179. Arguments:
  180. pAtqContext pointer to ATQ context information for request that needs
  181. to be unblocked.
  182. Returns:
  183. TRUE on success. FALSE if there are any errors.
  184. (Use GetLastError() for details)
  185. --*/
  186. {
  187. BOOL fRet = FALSE;
  188. ATQ_ASSERT( pAtqContext != NULL);
  189. ATQ_ASSERT( pAtqContext->Signature == ATQ_CONTEXT_SIGNATURE );
  190. // Remove the request from the blocked list entry
  191. RemoveEntryList( &pAtqContext->BlockedListEntry);
  192. DecCurrentBlockedRequests();
  193. pAtqContext->ResetFlag( ACF_BLOCKED );
  194. // Check and re enable the operation of pAtqContext
  195. switch ( _pStatus[ pAtqContext->arInfo.atqOp ] ) {
  196. case StatusAllowOperation:
  197. IncTotalAllowedRequests();
  198. switch ( pAtqContext->arInfo.atqOp) {
  199. case AtqIoRead:
  200. {
  201. DWORD cbRead; // Discard after calling ReadFile()
  202. DWORD dwFlags = 0;
  203. // assume that this is a socket operation!
  204. if ( pAtqContext->arInfo.uop.opReadWrite.dwBufferCount > 1) {
  205. ATQ_ASSERT( NULL !=
  206. pAtqContext->arInfo.uop.opReadWrite.pBufAll);
  207. fRet =
  208. ((WSARecv( HANDLE_TO_SOCKET(pAtqContext->hAsyncIO),
  209. pAtqContext->arInfo.uop.opReadWrite.pBufAll,
  210. pAtqContext->arInfo.uop.opReadWrite.dwBufferCount,
  211. &cbRead,
  212. &dwFlags,
  213. pAtqContext->arInfo.lpOverlapped,
  214. NULL
  215. ) == 0)||
  216. (WSAGetLastError() == WSA_IO_PENDING)
  217. );
  218. // free up the socket buffers
  219. ::LocalFree( pAtqContext->arInfo.uop.opReadWrite.pBufAll);
  220. pAtqContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  221. } else {
  222. WSABUF wsaBuf =
  223. { pAtqContext->arInfo.uop.opReadWrite.buf1.len,
  224. pAtqContext->arInfo.uop.opReadWrite.buf1.buf
  225. };
  226. fRet = (( WSARecv( HANDLE_TO_SOCKET(pAtqContext->hAsyncIO),
  227. &wsaBuf,
  228. 1,
  229. &cbRead,
  230. &dwFlags,
  231. pAtqContext->arInfo.lpOverlapped,
  232. NULL
  233. ) == 0)||
  234. (WSAGetLastError() == WSA_IO_PENDING)
  235. );
  236. }
  237. break;
  238. }
  239. case AtqIoWrite:
  240. {
  241. DWORD cbWrite; // Discard after calling WriteFile()
  242. // assume that this is a socket operation!
  243. if ( pAtqContext->arInfo.uop.opReadWrite.dwBufferCount > 1) {
  244. ATQ_ASSERT( NULL !=
  245. pAtqContext->arInfo.uop.opReadWrite.pBufAll);
  246. fRet =
  247. ((WSASend( HANDLE_TO_SOCKET(pAtqContext->hAsyncIO),
  248. pAtqContext->arInfo.uop.opReadWrite.pBufAll,
  249. pAtqContext->arInfo.uop.opReadWrite.dwBufferCount,
  250. &cbWrite,
  251. 0,
  252. pAtqContext->arInfo.lpOverlapped,
  253. NULL
  254. ) == 0)||
  255. (WSAGetLastError() == WSA_IO_PENDING)
  256. );
  257. // free up the socket buffers
  258. ::LocalFree( pAtqContext->arInfo.uop.opReadWrite.pBufAll);
  259. pAtqContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  260. } else {
  261. WSABUF wsaBuf =
  262. { pAtqContext->arInfo.uop.opReadWrite.buf1.len,
  263. pAtqContext->arInfo.uop.opReadWrite.buf1.buf
  264. };
  265. fRet = (( WSASend( HANDLE_TO_SOCKET(pAtqContext->hAsyncIO),
  266. &wsaBuf,
  267. 1,
  268. &cbWrite,
  269. 0,
  270. pAtqContext->arInfo.lpOverlapped,
  271. NULL
  272. ) == 0)||
  273. (WSAGetLastError() == WSA_IO_PENDING)
  274. );
  275. }
  276. break;
  277. }
  278. case AtqIoXmitFile:
  279. {
  280. fRet = g_pfnTransmitFile( HANDLE_TO_SOCKET(pAtqContext->hAsyncIO),
  281. pAtqContext->arInfo.uop.opXmit.hFile,
  282. pAtqContext->arInfo.uop.opXmit.
  283. dwBytesInFile,
  284. 0,
  285. pAtqContext->arInfo.lpOverlapped,
  286. pAtqContext->arInfo.uop.
  287. opXmit.lpXmitBuffers,
  288. pAtqContext->arInfo.uop.
  289. opXmit.dwFlags );
  290. if ( !fRet && (GetLastError() == ERROR_IO_PENDING) ) {
  291. fRet = TRUE;
  292. }
  293. break;
  294. }
  295. case AtqIoXmitFileRecv:
  296. {
  297. DWORD cbRead;
  298. // assume that this is a socket operation!
  299. if ( pAtqContext->arInfo.uop.opXmitRecv.dwBufferCount > 1) {
  300. ATQ_ASSERT( NULL !=
  301. pAtqContext->arInfo.uop.opXmitRecv.pBufAll);
  302. fRet = I_AtqTransmitFileAndRecv
  303. ( (PATQ_CONTEXT) pAtqContext,
  304. pAtqContext->arInfo.uop.opXmitRecv.hFile,
  305. pAtqContext->arInfo.uop.opXmitRecv.dwBytesInFile,
  306. pAtqContext->arInfo.uop.opXmitRecv.lpXmitBuffers,
  307. pAtqContext->arInfo.uop.opXmitRecv.dwTFFlags,
  308. pAtqContext->arInfo.uop.opXmitRecv.pBufAll,
  309. pAtqContext->arInfo.uop.opXmitRecv.dwBufferCount
  310. );
  311. // free up the socket buffers
  312. ::LocalFree( pAtqContext->arInfo.uop.opXmitRecv.pBufAll);
  313. pAtqContext->arInfo.uop.opXmitRecv.pBufAll = NULL;
  314. }
  315. else
  316. {
  317. WSABUF wsaBuf =
  318. { pAtqContext->arInfo.uop.opXmitRecv.buf1.len,
  319. pAtqContext->arInfo.uop.opXmitRecv.buf1.buf
  320. };
  321. fRet = I_AtqTransmitFileAndRecv
  322. ( (PATQ_CONTEXT) pAtqContext,
  323. pAtqContext->arInfo.uop.opXmitRecv.hFile,
  324. pAtqContext->arInfo.uop.opXmitRecv.dwBytesInFile,
  325. pAtqContext->arInfo.uop.opXmitRecv.lpXmitBuffers,
  326. pAtqContext->arInfo.uop.opXmitRecv.dwTFFlags,
  327. &wsaBuf,
  328. 1 );
  329. }
  330. if ( !fRet && GetLastError() == ERROR_IO_PENDING )
  331. {
  332. fRet = TRUE;
  333. }
  334. break;
  335. }
  336. case AtqIoSendRecv:
  337. {
  338. WSABUF wsaSendBuf =
  339. { pAtqContext->arInfo.uop.opSendRecv.sendbuf1.len,
  340. pAtqContext->arInfo.uop.opSendRecv.sendbuf1.buf
  341. };
  342. WSABUF wsaRecvBuf =
  343. {
  344. pAtqContext->arInfo.uop.opSendRecv.recvbuf1.len,
  345. pAtqContext->arInfo.uop.opSendRecv.recvbuf1.buf
  346. };
  347. LPWSABUF pSendBuf = &wsaSendBuf;
  348. LPWSABUF pRecvBuf = &wsaRecvBuf;
  349. if ( pAtqContext->arInfo.uop.opSendRecv.dwSendBufferCount > 1 )
  350. {
  351. pSendBuf = pAtqContext->arInfo.uop.opSendRecv.pSendBufAll;
  352. }
  353. if ( pAtqContext->arInfo.uop.opSendRecv.dwRecvBufferCount > 1 )
  354. {
  355. pRecvBuf = pAtqContext->arInfo.uop.opSendRecv.pRecvBufAll;
  356. }
  357. ATQ_ASSERT( pSendBuf != NULL );
  358. ATQ_ASSERT( pRecvBuf != NULL );
  359. fRet = I_AtqSendAndRecv
  360. ( (PATQ_CONTEXT) pAtqContext,
  361. pSendBuf,
  362. pAtqContext->arInfo.uop.opSendRecv.
  363. dwSendBufferCount,
  364. pRecvBuf,
  365. pAtqContext->arInfo.uop.opSendRecv.
  366. dwRecvBufferCount );
  367. if ( pAtqContext->arInfo.uop.opSendRecv.pSendBufAll != NULL )
  368. {
  369. ::LocalFree( pAtqContext->arInfo.uop.opSendRecv.pSendBufAll );
  370. }
  371. if ( pAtqContext->arInfo.uop.opSendRecv.pRecvBufAll != NULL )
  372. {
  373. ::LocalFree( pAtqContext->arInfo.uop.opSendRecv.pSendBufAll );
  374. }
  375. if ( !fRet && (GetLastError() == ERROR_IO_PENDING ) ) {
  376. fRet = TRUE;
  377. }
  378. break;
  379. }
  380. default:
  381. ATQ_ASSERT( FALSE);
  382. break;
  383. } // switch
  384. pAtqContext->arInfo.atqOp = AtqIoNone; // reset since operation done.
  385. break;
  386. case StatusRejectOperation:
  387. IncTotalRejectedRequests();
  388. if ( ((pAtqContext->arInfo.atqOp == AtqIoRead) ||
  389. (pAtqContext->arInfo.atqOp == AtqIoRead)) &&
  390. (pAtqContext->arInfo.uop.opReadWrite.pBufAll != NULL)
  391. ) {
  392. ::LocalFree( pAtqContext->arInfo.uop.opReadWrite.pBufAll);
  393. pAtqContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  394. }
  395. pAtqContext->arInfo.atqOp = AtqIoNone; // reset since op rejected.
  396. SetLastError( ERROR_NETWORK_BUSY);
  397. fRet = FALSE;
  398. break;
  399. case StatusBlockOperation:
  400. // do nothing. we cannot unblock
  401. ATQ_ASSERT(FALSE);
  402. return (TRUE);
  403. default:
  404. ATQ_ASSERT( FALSE);
  405. break;
  406. } // switch
  407. if (!fRet) {
  408. // Call the completion function to signify the error in operation.
  409. //
  410. // Reset the timeout value so requests don't
  411. // timeout multiple times
  412. //
  413. InterlockedExchange(
  414. (LPLONG ) &pAtqContext->NextTimeout,
  415. ATQ_INFINITE
  416. );
  417. InterlockedDecrement( &pAtqContext->m_nIO);
  418. pAtqContext->IOCompletion( 0,
  419. GetLastError(),
  420. pAtqContext->arInfo.lpOverlapped );
  421. } // on failure.
  422. return (fRet);
  423. }
  424. BOOL
  425. BANDWIDTH_INFO::CheckAndUnblockRequests( VOID )
  426. /*++
  427. Checks the list of blocked requests and identifies all operations
  428. that needs to be unblocked. This function unblocks those requests and
  429. removes them from blocked list.
  430. Always call this function after lock()ing
  431. Returns:
  432. TRUE on success and FALSE on failure.
  433. --*/
  434. {
  435. BOOL fRet = TRUE;
  436. //
  437. // If the list is not empty, then check and process blocked requests.
  438. //
  439. if ( !IsListEmpty( &_BlockedListHead ) ) {
  440. PLIST_ENTRY pentry;
  441. //
  442. // Scan the blocked requests list looking for pending requests
  443. // that needs to be unblocked and unblock these requests.
  444. //
  445. for (pentry = _BlockedListHead.Flink;
  446. pentry != &_BlockedListHead;
  447. pentry = pentry->Flink )
  448. {
  449. PATQ_CONT pContext = CONTAINING_RECORD(pentry,
  450. ATQ_CONTEXT,
  451. BlockedListEntry );
  452. if ( pContext->Signature != ATQ_CONTEXT_SIGNATURE)
  453. {
  454. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  455. fRet = FALSE;
  456. break;
  457. }
  458. if ( !pContext->IsBlocked()) {
  459. // This should not happen.
  460. ATQ_ASSERT( !pContext->IsBlocked());
  461. fRet = FALSE;
  462. continue;
  463. }
  464. //
  465. // Check to see if the status for operation has changed.
  466. // If so, unblock the request.
  467. //
  468. if ( _pStatus[pContext->arInfo.atqOp] !=
  469. StatusBlockOperation) {
  470. fRet &= UnblockRequest( pContext );
  471. }
  472. } // scan list
  473. }
  474. return (fRet);
  475. }
  476. BOOL
  477. BANDWIDTH_INFO::UpdateBandwidth(
  478. VOID
  479. )
  480. /*++
  481. This function updates the current bandwidth value using the histogram
  482. of bytes transferred.
  483. The histogram maintains a history of bytes transferred over different sample
  484. periods of a single minute. Each entry in the histogram corresponds to one
  485. interval of sample. The sum of all entries gives the total bytes transferred
  486. in a single minute. We divide this measure by 60 to obtain the count of
  487. bytes transferred over a second. This update bandwidth is used to
  488. reevalute the tuner of bandwidth throttle based on our throttling policy
  489. (specified in throttling algorithm). The updated action information is
  490. used by subsequent requests.
  491. In addition the _pcbXfered pointer is advanced forward using the
  492. histogram entries as a circular buffer, to obtain the count of bytes
  493. for next interval.
  494. Arguments:
  495. pdwPrivateBw - Filled with bandwidth for this descriptor
  496. Returns:
  497. TRUE on success. FALSE otherwise.
  498. Note:
  499. It is recommended that this function be called as infrequently as
  500. possible, using reasonable sample intervals.
  501. --*/
  502. {
  503. BOOL fRet = TRUE;
  504. ZoneLevel zonelevel;
  505. Lock();
  506. // accumulate current byte count to global counter, to minimize computation
  507. _cbXfered.QuadPart = _cbXfered.QuadPart + _pBytesXferCur->QuadPart;
  508. //
  509. // Current n/ws support a max of 1 to 100 MB/s. We can represent
  510. // 4GB/s in a DWORD. Hence the cast is used. This may need revision later.
  511. // Better yet, later we should store bandwidth as KB/seconds.
  512. //
  513. _dwMeasuredBw = (DWORD ) (_cbXfered.QuadPart/ATQ_AVERAGING_PERIOD);
  514. CIRCULAR_INCREMENT( _pBytesXferCur, _rgBytesXfered, ATQ_HISTOGRAM_SIZE);
  515. // Adjust the global cumulative bytes sent after increment.
  516. _cbXfered .QuadPart = _cbXfered.QuadPart - _pBytesXferCur->QuadPart;
  517. // Reset the counter to start with the new counter value.
  518. _pBytesXferCur->QuadPart = 0;
  519. //
  520. // update the operation status depending upon the bandwidth comparisons.
  521. // we use band/zone calculations to split the result into 3 zones.
  522. // Depending upon the zone we update the global status pointer to
  523. // appropriate row.
  524. //
  525. if ( _dwMeasuredBw < ATQ_LOW_BAND_THRESHOLD(_bandwidth)) {
  526. //
  527. // Lower zone. Modify the pointer to OPERATION_STATUS accordingly.
  528. //
  529. zonelevel = ZoneLevelLow;
  530. } else if ( _dwMeasuredBw > ATQ_HIGH_BAND_THRESHOLD(_bandwidth)) {
  531. //
  532. // Higher zone. Modify the pointer to OPERATION_STATUS accordingly.
  533. //
  534. zonelevel = ZoneLevelHigh;
  535. } else {
  536. zonelevel = ZoneLevelMedium;
  537. }
  538. /*++
  539. Above calculation can be implemented as:
  540. zonelevel = (( sm_dwMeasuredBw > ATQ_LOW_BAND_THRESHOLD( sm_bandwidth)) +
  541. ( sm_dwMeasuredBw > ATQ_HIGH_BAND_THRESHOLD( sm_bandwidth)));
  542. This is based on implicit dependence of ordering of ZoneLevel entries.
  543. So avoided for present now.
  544. --*/
  545. if ( _pStatus != &sm_rgStatus[zonelevel][0]) {
  546. // Status needs to be changed.
  547. _pStatus = &sm_rgStatus[zonelevel][0];
  548. // Examine and reenable blocked operations if any.
  549. fRet &= CheckAndUnblockRequests();
  550. }
  551. // remove the bandwidth info object from the list if it is
  552. // "inactive" (bandwidth = 0)
  553. if ( !_dwMeasuredBw )
  554. {
  555. // there should be no requests in the blocked queue!
  556. ATQ_ASSERT( _cCurrentBlockedRequests == 0 );
  557. RemoveFromActiveList();
  558. }
  559. Unlock();
  560. return fRet;
  561. }
  562. DWORD
  563. BANDWIDTH_INFO::SetBandwidthLevel(
  564. IN DWORD Data
  565. )
  566. /*++
  567. Sets the bandwidth threshold
  568. Arguments:
  569. Data - Bandwidth threshold
  570. Returns:
  571. Old bandwidth threshold (DWORD)
  572. --*/
  573. {
  574. DWORD dwOldVal;
  575. INT iListDelta = 0;
  576. Lock();
  577. dwOldVal = _bandwidth.dwSpecifiedLevel;
  578. if ( Data != INFINITE) {
  579. DWORD dwTemp;
  580. _bandwidth.dwSpecifiedLevel = ATQ_ROUNDUP_BANDWIDTH( Data );
  581. dwTemp = ( Data *9)/10; //low threshold = 0.9*specified
  582. _bandwidth.dwLowThreshold = ATQ_ROUNDUP_BANDWIDTH( dwTemp);
  583. dwTemp = ( Data *11)/10; //high threshold= 1.1*specified
  584. _bandwidth.dwHighThreshold = ATQ_ROUNDUP_BANDWIDTH( dwTemp);
  585. _fEnabled = TRUE;
  586. // we should recheck the throttling and blocked requests
  587. // Will be done when the next timeout occurs in the ATQ Timeout Thread
  588. if ( dwOldVal == INFINITE )
  589. {
  590. iListDelta = 1;
  591. }
  592. } else {
  593. _bandwidth.dwSpecifiedLevel = INFINITE;
  594. _bandwidth.dwLowThreshold = INFINITE;
  595. _bandwidth.dwHighThreshold = INFINITE;
  596. _fEnabled = FALSE;
  597. // enable all operations, since we are in low zone
  598. _pStatus = &sm_rgStatus[ZoneLevelLow][0];
  599. // we should recheck and enable all blocked requests.
  600. if ( _cCurrentBlockedRequests > 0) {
  601. ATQ_REQUIRE( CheckAndUnblockRequests());
  602. }
  603. if ( dwOldVal != INFINITE )
  604. {
  605. iListDelta = -1;
  606. }
  607. }
  608. Unlock();
  609. // update the static counter of how many non-infinite throttles we have
  610. if ( iListDelta )
  611. {
  612. SharedLock();
  613. if ( iListDelta > 0 )
  614. {
  615. sm_cNonInfinite++;
  616. }
  617. else
  618. {
  619. sm_cNonInfinite--;
  620. }
  621. sm_fGlobalEnabled = !!sm_cNonInfinite;
  622. SharedUnlock();
  623. }
  624. return dwOldVal;
  625. }
  626. DWORD
  627. BANDWIDTH_INFO::SetMaxBlockedListSize(
  628. IN DWORD cMaxSize
  629. )
  630. /*++
  631. Sets the maximum size of blocked request list
  632. Arguments:
  633. cMaxSize - maximum size of list
  634. Returns:
  635. Old max size (DWORD)
  636. --*/
  637. {
  638. DWORD cOldMax;
  639. Lock();
  640. cOldMax = _cMaxBlockedList;
  641. _cMaxBlockedList = cMaxSize;
  642. Unlock();
  643. return cOldMax;
  644. }
  645. DWORD
  646. BANDWIDTH_INFO::QueryBandwidthLevel( VOID )
  647. /*++
  648. Retrieve the current bandwidth level
  649. Arguments:
  650. None
  651. Returns:
  652. Set Bandwidth level (DWORD)
  653. --*/
  654. {
  655. DWORD dwBw;
  656. Lock();
  657. dwBw = _bandwidth.dwSpecifiedLevel;
  658. Unlock();
  659. return dwBw;
  660. }
  661. BOOL
  662. BANDWIDTH_INFO::ClearStatistics( VOID )
  663. {
  664. Lock();
  665. _cTotalAllowedRequests = 0;
  666. _cTotalBlockedRequests = 0;
  667. _cTotalRejectedRequests = 0;
  668. Unlock();
  669. return TRUE;
  670. }
  671. BOOL
  672. BANDWIDTH_INFO::GetStatistics( OUT ATQ_STATISTICS * pAtqStats )
  673. {
  674. ATQ_ASSERT( pAtqStats != NULL );
  675. pAtqStats->cRejectedRequests = _cTotalRejectedRequests;
  676. pAtqStats->cBlockedRequests = _cTotalBlockedRequests;
  677. pAtqStats->cAllowedRequests = _cTotalAllowedRequests;
  678. pAtqStats->cCurrentBlockedRequests = _cCurrentBlockedRequests;
  679. pAtqStats->MeasuredBandwidth = _dwMeasuredBw;
  680. return TRUE;
  681. }
  682. BOOL
  683. BANDWIDTH_INFO::UpdateAllBandwidths( VOID )
  684. {
  685. PLIST_ENTRY pEntry;
  686. BOOL fRet = TRUE;
  687. DWORD dwCounter = 0;
  688. SharedLock();
  689. for ( pEntry = sm_ActiveListHead.Flink;
  690. pEntry != &sm_ActiveListHead; )
  691. {
  692. BANDWIDTH_INFO *pBandwidthInfo = CONTAINING_RECORD( pEntry,
  693. BANDWIDTH_INFO,
  694. _ActiveListEntry );
  695. ATQ_ASSERT( pBandwidthInfo != NULL );
  696. // we might be deleting this entry from the list. Grab the next
  697. // link now before we do so the traversal can happen smoothly
  698. pEntry = pEntry->Flink;
  699. if ( !pBandwidthInfo->Enabled() )
  700. {
  701. continue;
  702. }
  703. if ( !pBandwidthInfo->UpdateBandwidth() )
  704. {
  705. fRet = FALSE;
  706. break;
  707. }
  708. #ifndef _NO_TRACING_
  709. CHKINFO(( DBG_CONTEXT, "pBWInfo = %p (%s), Bandwidth = %u, Threshold = %d\n",
  710. pBandwidthInfo,
  711. pBandwidthInfo->_achDescription,
  712. pBandwidthInfo->QueryMeasuredBw(),
  713. pBandwidthInfo->QueryBandwidthLevel() ) );
  714. #else
  715. ATQ_PRINTF(( DBG_CONTEXT, "pBWInfo = %p (%s), Bandwidth = %u, Threshold = %d\n",
  716. pBandwidthInfo,
  717. pBandwidthInfo->_achDescription,
  718. pBandwidthInfo->QueryMeasuredBw(),
  719. pBandwidthInfo->QueryBandwidthLevel() ) );
  720. #endif
  721. }
  722. SharedUnlock();
  723. return fRet;
  724. }
  725. BOOL
  726. BANDWIDTH_INFO::AbwInitialize( VOID )
  727. {
  728. ALLOC_CACHE_CONFIGURATION acConfig = { 1, 10, sizeof(BANDWIDTH_INFO)};
  729. ATQ_ASSERT( sm_pachBWInfos == NULL );
  730. sm_pachBWInfos = new ALLOC_CACHE_HANDLER( "BandwidthInfos",
  731. &acConfig );
  732. if ( sm_pachBWInfos == NULL )
  733. {
  734. return FALSE;
  735. }
  736. InitializeListHead( &sm_ActiveListHead );
  737. InitializeListHead( &sm_BornListHead );
  738. INITIALIZE_CRITICAL_SECTION( &sm_csSharedLock );
  739. sm_cActiveList = 0;
  740. sm_cBornList = 0;
  741. sm_fGlobalEnabled = FALSE;
  742. sm_fGlobalActive = FALSE;
  743. sm_cNonInfinite = 0;
  744. sm_cSamplesForTimeout = 1;
  745. g_pBandwidthInfo = new BANDWIDTH_INFO( TRUE );
  746. if ( !g_pBandwidthInfo )
  747. {
  748. return FALSE;
  749. }
  750. return TRUE;
  751. }
  752. BOOL
  753. BANDWIDTH_INFO::AbwTerminate( VOID )
  754. {
  755. PBANDWIDTH_INFO pBandwidthInfo;
  756. ATQ_PRINTF(( DBG_CONTEXT,
  757. "AbwTerminate() called. Born List Size = %d\n",
  758. sm_cBornList ));
  759. SharedLock();
  760. while( !IsListEmpty( &sm_BornListHead ) )
  761. {
  762. pBandwidthInfo = CONTAINING_RECORD( sm_BornListHead.Flink,
  763. BANDWIDTH_INFO,
  764. _BornListEntry );
  765. ATQ_ASSERT( pBandwidthInfo != NULL );
  766. delete pBandwidthInfo;
  767. }
  768. ATQ_ASSERT( sm_cBornList == 0 );
  769. ATQ_ASSERT( sm_cActiveList == 0 );
  770. ATQ_ASSERT( IsListEmpty( &sm_BornListHead ) );
  771. ATQ_ASSERT( IsListEmpty( &sm_ActiveListHead ) );
  772. SharedUnlock();
  773. DeleteCriticalSection( &sm_csSharedLock );
  774. if ( sm_pachBWInfos != NULL )
  775. {
  776. delete sm_pachBWInfos;
  777. sm_pachBWInfos = NULL;
  778. }
  779. return TRUE;
  780. }
  781. PVOID
  782. AtqCreateBandwidthInfo( VOID )
  783. /*++
  784. Routine Description:
  785. Allocate a bandwidth throttling descriptor
  786. Arguments:
  787. none
  788. Return Value:
  789. If successful, pointer to allocated descriptor. Otherwise NULL.
  790. --*/
  791. {
  792. PBANDWIDTH_INFO pBandwidthInfo;
  793. pBandwidthInfo = new BANDWIDTH_INFO( FALSE );
  794. if ( pBandwidthInfo == NULL )
  795. {
  796. return NULL;
  797. }
  798. else
  799. {
  800. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  801. return pBandwidthInfo;
  802. }
  803. }
  804. BOOL
  805. AtqFreeBandwidthInfo(
  806. IN PVOID pvBandwidthInfo
  807. )
  808. /*++
  809. Routine Description:
  810. Free bandwidth throttling descriptor
  811. Arguments:
  812. pBandwidthInfo - Descriptor to destroy
  813. Return Value:
  814. TRUE If successful, else FALSE.
  815. --*/
  816. {
  817. PBANDWIDTH_INFO pBandwidthInfo = (PBANDWIDTH_INFO) pvBandwidthInfo;
  818. ATQ_ASSERT( pBandwidthInfo );
  819. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  820. return pBandwidthInfo->PrepareToFree();
  821. }
  822. ULONG_PTR
  823. AtqBandwidthSetInfo(
  824. IN PVOID pvBandwidthInfo,
  825. IN ATQ_BANDWIDTH_INFO BwInfo,
  826. IN ULONG_PTR Data
  827. )
  828. /*++
  829. Routine Description:
  830. Set member of bandwidth descriptor
  831. Arguments:
  832. pBandwidthInfo - Descriptor to change
  833. BwInfo - Value of descriptor to set
  834. Data - Data to set to
  835. Return Value:
  836. Previous value of descriptor
  837. --*/
  838. {
  839. ULONG_PTR oldVal = 0;
  840. PBANDWIDTH_INFO pBandwidthInfo = (PBANDWIDTH_INFO) pvBandwidthInfo;
  841. ATQ_ASSERT( pBandwidthInfo );
  842. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  843. if ( pBandwidthInfo &&
  844. pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE )
  845. {
  846. switch ( BwInfo )
  847. {
  848. case ATQ_BW_BANDWIDTH_LEVEL:
  849. oldVal = (ULONG_PTR)pBandwidthInfo->QueryBandwidthLevel();
  850. pBandwidthInfo->SetBandwidthLevel( (DWORD) Data );
  851. break;
  852. case ATQ_BW_MAX_BLOCKED:
  853. oldVal = (ULONG_PTR)pBandwidthInfo->QueryMaxBlockedSize();
  854. pBandwidthInfo->SetMaxBlockedListSize( (DWORD) Data );
  855. break;
  856. case ATQ_BW_DESCRIPTION:
  857. oldVal = (ULONG_PTR)Data;
  858. pBandwidthInfo->SetDescription( (CHAR*) Data );
  859. break;
  860. default:
  861. SetLastError( ERROR_INVALID_PARAMETER );
  862. ATQ_ASSERT( FALSE );
  863. break;
  864. }
  865. }
  866. else
  867. {
  868. SetLastError( ERROR_INVALID_PARAMETER );
  869. }
  870. return oldVal;
  871. }
  872. BOOL
  873. AtqBandwidthGetInfo(
  874. IN PVOID pvBandwidthInfo,
  875. IN ATQ_BANDWIDTH_INFO BwInfo,
  876. OUT ULONG_PTR * pData
  877. )
  878. /*++
  879. Routine Description:
  880. Get member of bandwidth descriptor
  881. Arguments:
  882. pvBandwidthInfo - Descriptor to change
  883. BwInfo - Value of descriptor to set
  884. pData - Output here
  885. Return Value:
  886. TRUE if successful, FALSE otherwise
  887. --*/
  888. {
  889. BOOL fRet = TRUE;
  890. PBANDWIDTH_INFO pBandwidthInfo = (PBANDWIDTH_INFO) pvBandwidthInfo;
  891. ATQ_ASSERT( pBandwidthInfo );
  892. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  893. ATQ_ASSERT( pData );
  894. if ( pBandwidthInfo &&
  895. pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE &&
  896. pData )
  897. {
  898. switch ( BwInfo )
  899. {
  900. case ATQ_BW_BANDWIDTH_LEVEL:
  901. *pData = (ULONG_PTR)pBandwidthInfo->QueryBandwidthLevel();
  902. break;
  903. case ATQ_BW_MAX_BLOCKED:
  904. *pData = (ULONG_PTR)pBandwidthInfo->QueryMaxBlockedSize();
  905. break;
  906. case ATQ_BW_STATISTICS:
  907. fRet = pBandwidthInfo->GetStatistics( (ATQ_STATISTICS*) pData );
  908. break;
  909. case ATQ_BW_DESCRIPTION:
  910. *pData = (ULONG_PTR)pBandwidthInfo->QueryDescription();
  911. break;
  912. default:
  913. SetLastError( ERROR_INVALID_PARAMETER );
  914. ATQ_ASSERT( FALSE );
  915. fRet = FALSE;
  916. break;
  917. }
  918. }
  919. else
  920. {
  921. SetLastError( ERROR_INVALID_PARAMETER );
  922. fRet = FALSE;
  923. }
  924. return fRet;
  925. }