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.

1109 lines
30 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. default:
  296. ATQ_ASSERT( FALSE);
  297. break;
  298. } // switch
  299. pAtqContext->arInfo.atqOp = AtqIoNone; // reset since operation done.
  300. break;
  301. case StatusRejectOperation:
  302. IncTotalRejectedRequests();
  303. if ( ((pAtqContext->arInfo.atqOp == AtqIoRead) ||
  304. (pAtqContext->arInfo.atqOp == AtqIoRead)) &&
  305. (pAtqContext->arInfo.uop.opReadWrite.pBufAll != NULL)
  306. ) {
  307. ::LocalFree( pAtqContext->arInfo.uop.opReadWrite.pBufAll);
  308. pAtqContext->arInfo.uop.opReadWrite.pBufAll = NULL;
  309. }
  310. pAtqContext->arInfo.atqOp = AtqIoNone; // reset since op rejected.
  311. SetLastError( ERROR_NETWORK_BUSY);
  312. fRet = FALSE;
  313. break;
  314. case StatusBlockOperation:
  315. // do nothing. we cannot unblock
  316. ATQ_ASSERT(FALSE);
  317. return (TRUE);
  318. default:
  319. ATQ_ASSERT( FALSE);
  320. break;
  321. } // switch
  322. if (!fRet) {
  323. // Call the completion function to signify the error in operation.
  324. //
  325. // Reset the timeout value so requests don't
  326. // timeout multiple times
  327. //
  328. InterlockedExchange(
  329. (LPLONG ) &pAtqContext->NextTimeout,
  330. ATQ_INFINITE
  331. );
  332. InterlockedDecrement( &pAtqContext->m_nIO);
  333. pAtqContext->IOCompletion( 0,
  334. GetLastError(),
  335. pAtqContext->arInfo.lpOverlapped );
  336. } // on failure.
  337. return (fRet);
  338. }
  339. BOOL
  340. BANDWIDTH_INFO::CheckAndUnblockRequests( VOID )
  341. /*++
  342. Checks the list of blocked requests and identifies all operations
  343. that needs to be unblocked. This function unblocks those requests and
  344. removes them from blocked list.
  345. Always call this function after lock()ing
  346. Returns:
  347. TRUE on success and FALSE on failure.
  348. --*/
  349. {
  350. BOOL fRet = TRUE;
  351. //
  352. // If the list is not empty, then check and process blocked requests.
  353. //
  354. if ( !IsListEmpty( &_BlockedListHead ) ) {
  355. PLIST_ENTRY pentry;
  356. //
  357. // Scan the blocked requests list looking for pending requests
  358. // that needs to be unblocked and unblock these requests.
  359. //
  360. for (pentry = _BlockedListHead.Flink;
  361. pentry != &_BlockedListHead;
  362. pentry = pentry->Flink )
  363. {
  364. PATQ_CONT pContext = CONTAINING_RECORD(pentry,
  365. ATQ_CONTEXT,
  366. BlockedListEntry );
  367. if ( pContext->Signature != ATQ_CONTEXT_SIGNATURE)
  368. {
  369. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  370. fRet = FALSE;
  371. break;
  372. }
  373. if ( !pContext->IsBlocked()) {
  374. // This should not happen.
  375. ATQ_ASSERT( !pContext->IsBlocked());
  376. fRet = FALSE;
  377. continue;
  378. }
  379. //
  380. // Check to see if the status for operation has changed.
  381. // If so, unblock the request.
  382. //
  383. if ( _pStatus[pContext->arInfo.atqOp] !=
  384. StatusBlockOperation) {
  385. fRet &= UnblockRequest( pContext );
  386. }
  387. } // scan list
  388. }
  389. return (fRet);
  390. }
  391. BOOL
  392. BANDWIDTH_INFO::UpdateBandwidth(
  393. VOID
  394. )
  395. /*++
  396. This function updates the current bandwidth value using the histogram
  397. of bytes transferred.
  398. The histogram maintains a history of bytes transferred over different sample
  399. periods of a single minute. Each entry in the histogram corresponds to one
  400. interval of sample. The sum of all entries gives the total bytes transferred
  401. in a single minute. We divide this measure by 60 to obtain the count of
  402. bytes transferred over a second. This update bandwidth is used to
  403. reevalute the tuner of bandwidth throttle based on our throttling policy
  404. (specified in throttling algorithm). The updated action information is
  405. used by subsequent requests.
  406. In addition the _pcbXfered pointer is advanced forward using the
  407. histogram entries as a circular buffer, to obtain the count of bytes
  408. for next interval.
  409. Arguments:
  410. pdwPrivateBw - Filled with bandwidth for this descriptor
  411. Returns:
  412. TRUE on success. FALSE otherwise.
  413. Note:
  414. It is recommended that this function be called as infrequently as
  415. possible, using reasonable sample intervals.
  416. --*/
  417. {
  418. BOOL fRet = TRUE;
  419. ZoneLevel zonelevel;
  420. Lock();
  421. // accumulate current byte count to global counter, to minimize computation
  422. _cbXfered.QuadPart = _cbXfered.QuadPart + _pBytesXferCur->QuadPart;
  423. //
  424. // Current n/ws support a max of 1 to 100 MB/s. We can represent
  425. // 4GB/s in a DWORD. Hence the cast is used. This may need revision later.
  426. // Better yet, later we should store bandwidth as KB/seconds.
  427. //
  428. _dwMeasuredBw = (DWORD ) (_cbXfered.QuadPart/ATQ_AVERAGING_PERIOD);
  429. CIRCULAR_INCREMENT( _pBytesXferCur, _rgBytesXfered, ATQ_HISTOGRAM_SIZE);
  430. // Adjust the global cumulative bytes sent after increment.
  431. _cbXfered .QuadPart = _cbXfered.QuadPart - _pBytesXferCur->QuadPart;
  432. // Reset the counter to start with the new counter value.
  433. _pBytesXferCur->QuadPart = 0;
  434. //
  435. // update the operation status depending upon the bandwidth comparisons.
  436. // we use band/zone calculations to split the result into 3 zones.
  437. // Depending upon the zone we update the global status pointer to
  438. // appropriate row.
  439. //
  440. if ( _dwMeasuredBw < ATQ_LOW_BAND_THRESHOLD(_bandwidth)) {
  441. //
  442. // Lower zone. Modify the pointer to OPERATION_STATUS accordingly.
  443. //
  444. zonelevel = ZoneLevelLow;
  445. } else if ( _dwMeasuredBw > ATQ_HIGH_BAND_THRESHOLD(_bandwidth)) {
  446. //
  447. // Higher zone. Modify the pointer to OPERATION_STATUS accordingly.
  448. //
  449. zonelevel = ZoneLevelHigh;
  450. } else {
  451. zonelevel = ZoneLevelMedium;
  452. }
  453. /*++
  454. Above calculation can be implemented as:
  455. zonelevel = (( sm_dwMeasuredBw > ATQ_LOW_BAND_THRESHOLD( sm_bandwidth)) +
  456. ( sm_dwMeasuredBw > ATQ_HIGH_BAND_THRESHOLD( sm_bandwidth)));
  457. This is based on implicit dependence of ordering of ZoneLevel entries.
  458. So avoided for present now.
  459. --*/
  460. if ( _pStatus != &sm_rgStatus[zonelevel][0]) {
  461. // Status needs to be changed.
  462. _pStatus = &sm_rgStatus[zonelevel][0];
  463. // Examine and reenable blocked operations if any.
  464. fRet &= CheckAndUnblockRequests();
  465. }
  466. // remove the bandwidth info object from the list if it is
  467. // "inactive" (bandwidth = 0)
  468. if ( !_dwMeasuredBw )
  469. {
  470. // there should be no requests in the blocked queue!
  471. ATQ_ASSERT( _cCurrentBlockedRequests == 0 );
  472. RemoveFromActiveList();
  473. }
  474. Unlock();
  475. return fRet;
  476. }
  477. DWORD
  478. BANDWIDTH_INFO::SetBandwidthLevel(
  479. IN DWORD Data
  480. )
  481. /*++
  482. Sets the bandwidth threshold
  483. Arguments:
  484. Data - Bandwidth threshold
  485. Returns:
  486. Old bandwidth threshold (DWORD)
  487. --*/
  488. {
  489. DWORD dwOldVal;
  490. INT iListDelta = 0;
  491. Lock();
  492. dwOldVal = _bandwidth.dwSpecifiedLevel;
  493. if ( Data != INFINITE) {
  494. DWORD dwTemp;
  495. _bandwidth.dwSpecifiedLevel = ATQ_ROUNDUP_BANDWIDTH( Data );
  496. dwTemp = ( Data *9)/10; //low threshold = 0.9*specified
  497. _bandwidth.dwLowThreshold = ATQ_ROUNDUP_BANDWIDTH( dwTemp);
  498. dwTemp = ( Data *11)/10; //high threshold= 1.1*specified
  499. _bandwidth.dwHighThreshold = ATQ_ROUNDUP_BANDWIDTH( dwTemp);
  500. _fEnabled = TRUE;
  501. // we should recheck the throttling and blocked requests
  502. // Will be done when the next timeout occurs in the ATQ Timeout Thread
  503. if ( dwOldVal == INFINITE )
  504. {
  505. iListDelta = 1;
  506. }
  507. } else {
  508. _bandwidth.dwSpecifiedLevel = INFINITE;
  509. _bandwidth.dwLowThreshold = INFINITE;
  510. _bandwidth.dwHighThreshold = INFINITE;
  511. _fEnabled = FALSE;
  512. // enable all operations, since we are in low zone
  513. _pStatus = &sm_rgStatus[ZoneLevelLow][0];
  514. // we should recheck and enable all blocked requests.
  515. if ( _cCurrentBlockedRequests > 0) {
  516. ATQ_REQUIRE( CheckAndUnblockRequests());
  517. }
  518. if ( dwOldVal != INFINITE )
  519. {
  520. iListDelta = -1;
  521. }
  522. }
  523. Unlock();
  524. // update the static counter of how many non-infinite throttles we have
  525. if ( iListDelta )
  526. {
  527. SharedLock();
  528. if ( iListDelta > 0 )
  529. {
  530. sm_cNonInfinite++;
  531. }
  532. else
  533. {
  534. sm_cNonInfinite--;
  535. }
  536. sm_fGlobalEnabled = !!sm_cNonInfinite;
  537. SharedUnlock();
  538. }
  539. return dwOldVal;
  540. }
  541. DWORD
  542. BANDWIDTH_INFO::SetMaxBlockedListSize(
  543. IN DWORD cMaxSize
  544. )
  545. /*++
  546. Sets the maximum size of blocked request list
  547. Arguments:
  548. cMaxSize - maximum size of list
  549. Returns:
  550. Old max size (DWORD)
  551. --*/
  552. {
  553. DWORD cOldMax;
  554. Lock();
  555. cOldMax = _cMaxBlockedList;
  556. _cMaxBlockedList = cMaxSize;
  557. Unlock();
  558. return cOldMax;
  559. }
  560. DWORD
  561. BANDWIDTH_INFO::QueryBandwidthLevel( VOID )
  562. /*++
  563. Retrieve the current bandwidth level
  564. Arguments:
  565. None
  566. Returns:
  567. Set Bandwidth level (DWORD)
  568. --*/
  569. {
  570. DWORD dwBw;
  571. Lock();
  572. dwBw = _bandwidth.dwSpecifiedLevel;
  573. Unlock();
  574. return dwBw;
  575. }
  576. BOOL
  577. BANDWIDTH_INFO::ClearStatistics( VOID )
  578. {
  579. Lock();
  580. _cTotalAllowedRequests = 0;
  581. _cTotalBlockedRequests = 0;
  582. _cTotalRejectedRequests = 0;
  583. Unlock();
  584. return TRUE;
  585. }
  586. BOOL
  587. BANDWIDTH_INFO::GetStatistics( OUT ATQ_STATISTICS * pAtqStats )
  588. {
  589. ATQ_ASSERT( pAtqStats != NULL );
  590. pAtqStats->cRejectedRequests = _cTotalRejectedRequests;
  591. pAtqStats->cBlockedRequests = _cTotalBlockedRequests;
  592. pAtqStats->cAllowedRequests = _cTotalAllowedRequests;
  593. pAtqStats->cCurrentBlockedRequests = _cCurrentBlockedRequests;
  594. pAtqStats->MeasuredBandwidth = _dwMeasuredBw;
  595. return TRUE;
  596. }
  597. BOOL
  598. BANDWIDTH_INFO::UpdateAllBandwidths( VOID )
  599. {
  600. PLIST_ENTRY pEntry;
  601. BOOL fRet = TRUE;
  602. DWORD dwCounter = 0;
  603. SharedLock();
  604. for ( pEntry = sm_ActiveListHead.Flink;
  605. pEntry != &sm_ActiveListHead; )
  606. {
  607. BANDWIDTH_INFO *pBandwidthInfo = CONTAINING_RECORD( pEntry,
  608. BANDWIDTH_INFO,
  609. _ActiveListEntry );
  610. ATQ_ASSERT( pBandwidthInfo != NULL );
  611. // we might be deleting this entry from the list. Grab the next
  612. // link now before we do so the traversal can happen smoothly
  613. pEntry = pEntry->Flink;
  614. if ( !pBandwidthInfo->Enabled() )
  615. {
  616. continue;
  617. }
  618. if ( !pBandwidthInfo->UpdateBandwidth() )
  619. {
  620. fRet = FALSE;
  621. break;
  622. }
  623. #ifndef _NO_TRACING_
  624. CHKINFO(( DBG_CONTEXT, "pBWInfo = %p (%s), Bandwidth = %u, Threshold = %d\n",
  625. pBandwidthInfo,
  626. pBandwidthInfo->_achDescription,
  627. pBandwidthInfo->QueryMeasuredBw(),
  628. pBandwidthInfo->QueryBandwidthLevel() ) );
  629. #else
  630. ATQ_PRINTF(( DBG_CONTEXT, "pBWInfo = %p (%s), Bandwidth = %u, Threshold = %d\n",
  631. pBandwidthInfo,
  632. pBandwidthInfo->_achDescription,
  633. pBandwidthInfo->QueryMeasuredBw(),
  634. pBandwidthInfo->QueryBandwidthLevel() ) );
  635. #endif
  636. }
  637. SharedUnlock();
  638. return fRet;
  639. }
  640. BOOL
  641. BANDWIDTH_INFO::AbwInitialize( VOID )
  642. {
  643. ALLOC_CACHE_CONFIGURATION acConfig = { 1, 10, sizeof(BANDWIDTH_INFO)};
  644. ATQ_ASSERT( sm_pachBWInfos == NULL );
  645. sm_pachBWInfos = new ALLOC_CACHE_HANDLER( "BandwidthInfos",
  646. &acConfig );
  647. if ( sm_pachBWInfos == NULL )
  648. {
  649. return FALSE;
  650. }
  651. InitializeListHead( &sm_ActiveListHead );
  652. InitializeListHead( &sm_BornListHead );
  653. INITIALIZE_CRITICAL_SECTION( &sm_csSharedLock );
  654. sm_cActiveList = 0;
  655. sm_cBornList = 0;
  656. sm_fGlobalEnabled = FALSE;
  657. sm_fGlobalActive = FALSE;
  658. sm_cNonInfinite = 0;
  659. sm_cSamplesForTimeout = 1;
  660. g_pBandwidthInfo = new BANDWIDTH_INFO( TRUE );
  661. if ( !g_pBandwidthInfo )
  662. {
  663. return FALSE;
  664. }
  665. return TRUE;
  666. }
  667. BOOL
  668. BANDWIDTH_INFO::AbwTerminate( VOID )
  669. {
  670. PBANDWIDTH_INFO pBandwidthInfo;
  671. ATQ_PRINTF(( DBG_CONTEXT,
  672. "AbwTerminate() called. Born List Size = %d\n",
  673. sm_cBornList ));
  674. SharedLock();
  675. while( !IsListEmpty( &sm_BornListHead ) )
  676. {
  677. pBandwidthInfo = CONTAINING_RECORD( sm_BornListHead.Flink,
  678. BANDWIDTH_INFO,
  679. _BornListEntry );
  680. ATQ_ASSERT( pBandwidthInfo != NULL );
  681. delete pBandwidthInfo;
  682. }
  683. ATQ_ASSERT( sm_cBornList == 0 );
  684. ATQ_ASSERT( sm_cActiveList == 0 );
  685. ATQ_ASSERT( IsListEmpty( &sm_BornListHead ) );
  686. ATQ_ASSERT( IsListEmpty( &sm_ActiveListHead ) );
  687. SharedUnlock();
  688. DeleteCriticalSection( &sm_csSharedLock );
  689. if ( sm_pachBWInfos != NULL )
  690. {
  691. delete sm_pachBWInfos;
  692. sm_pachBWInfos = NULL;
  693. }
  694. return TRUE;
  695. }
  696. PVOID
  697. AtqCreateBandwidthInfo( VOID )
  698. /*++
  699. Routine Description:
  700. Allocate a bandwidth throttling descriptor
  701. Arguments:
  702. none
  703. Return Value:
  704. If successful, pointer to allocated descriptor. Otherwise NULL.
  705. --*/
  706. {
  707. PBANDWIDTH_INFO pBandwidthInfo;
  708. pBandwidthInfo = new BANDWIDTH_INFO( FALSE );
  709. if ( pBandwidthInfo == NULL )
  710. {
  711. return NULL;
  712. }
  713. else
  714. {
  715. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  716. return pBandwidthInfo;
  717. }
  718. }
  719. BOOL
  720. AtqFreeBandwidthInfo(
  721. IN PVOID pvBandwidthInfo
  722. )
  723. /*++
  724. Routine Description:
  725. Free bandwidth throttling descriptor
  726. Arguments:
  727. pBandwidthInfo - Descriptor to destroy
  728. Return Value:
  729. TRUE If successful, else FALSE.
  730. --*/
  731. {
  732. PBANDWIDTH_INFO pBandwidthInfo = (PBANDWIDTH_INFO) pvBandwidthInfo;
  733. ATQ_ASSERT( pBandwidthInfo );
  734. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  735. return pBandwidthInfo->PrepareToFree();
  736. }
  737. ULONG_PTR
  738. AtqBandwidthSetInfo(
  739. IN PVOID pvBandwidthInfo,
  740. IN ATQ_BANDWIDTH_INFO BwInfo,
  741. IN ULONG_PTR Data
  742. )
  743. /*++
  744. Routine Description:
  745. Set member of bandwidth descriptor
  746. Arguments:
  747. pBandwidthInfo - Descriptor to change
  748. BwInfo - Value of descriptor to set
  749. Data - Data to set to
  750. Return Value:
  751. Previous value of descriptor
  752. --*/
  753. {
  754. ULONG_PTR oldVal = 0;
  755. PBANDWIDTH_INFO pBandwidthInfo = (PBANDWIDTH_INFO) pvBandwidthInfo;
  756. ATQ_ASSERT( pBandwidthInfo );
  757. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  758. if ( pBandwidthInfo &&
  759. pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE )
  760. {
  761. switch ( BwInfo )
  762. {
  763. case ATQ_BW_BANDWIDTH_LEVEL:
  764. oldVal = (ULONG_PTR)pBandwidthInfo->QueryBandwidthLevel();
  765. pBandwidthInfo->SetBandwidthLevel( (DWORD) Data );
  766. break;
  767. case ATQ_BW_MAX_BLOCKED:
  768. oldVal = (ULONG_PTR)pBandwidthInfo->QueryMaxBlockedSize();
  769. pBandwidthInfo->SetMaxBlockedListSize( (DWORD) Data );
  770. break;
  771. case ATQ_BW_DESCRIPTION:
  772. oldVal = (ULONG_PTR)Data;
  773. pBandwidthInfo->SetDescription( (CHAR*) Data );
  774. break;
  775. default:
  776. SetLastError( ERROR_INVALID_PARAMETER );
  777. ATQ_ASSERT( FALSE );
  778. break;
  779. }
  780. }
  781. else
  782. {
  783. SetLastError( ERROR_INVALID_PARAMETER );
  784. }
  785. return oldVal;
  786. }
  787. BOOL
  788. AtqBandwidthGetInfo(
  789. IN PVOID pvBandwidthInfo,
  790. IN ATQ_BANDWIDTH_INFO BwInfo,
  791. OUT ULONG_PTR * pData
  792. )
  793. /*++
  794. Routine Description:
  795. Get member of bandwidth descriptor
  796. Arguments:
  797. pvBandwidthInfo - Descriptor to change
  798. BwInfo - Value of descriptor to set
  799. pData - Output here
  800. Return Value:
  801. TRUE if successful, FALSE otherwise
  802. --*/
  803. {
  804. BOOL fRet = TRUE;
  805. PBANDWIDTH_INFO pBandwidthInfo = (PBANDWIDTH_INFO) pvBandwidthInfo;
  806. ATQ_ASSERT( pBandwidthInfo );
  807. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  808. ATQ_ASSERT( pData );
  809. if ( pBandwidthInfo &&
  810. pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE &&
  811. pData )
  812. {
  813. switch ( BwInfo )
  814. {
  815. case ATQ_BW_BANDWIDTH_LEVEL:
  816. *pData = (ULONG_PTR)pBandwidthInfo->QueryBandwidthLevel();
  817. break;
  818. case ATQ_BW_MAX_BLOCKED:
  819. *pData = (ULONG_PTR)pBandwidthInfo->QueryMaxBlockedSize();
  820. break;
  821. case ATQ_BW_STATISTICS:
  822. fRet = pBandwidthInfo->GetStatistics( (ATQ_STATISTICS*) pData );
  823. break;
  824. case ATQ_BW_DESCRIPTION:
  825. *pData = (ULONG_PTR)pBandwidthInfo->QueryDescription();
  826. break;
  827. default:
  828. SetLastError( ERROR_INVALID_PARAMETER );
  829. ATQ_ASSERT( FALSE );
  830. fRet = FALSE;
  831. break;
  832. }
  833. }
  834. else
  835. {
  836. SetLastError( ERROR_INVALID_PARAMETER );
  837. fRet = FALSE;
  838. }
  839. return fRet;
  840. }