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.

1088 lines
37 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1998-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: EndPt.cpp
  6. * Content: This file contains EndPoint management routines.
  7. * An End Point is a DirectNet instance that we know about and may communicate
  8. * with. An End Point Descriptor (EPD) tracks each known End Point and was mapped
  9. * onto an hEndPoint by a hash table. Now, the SP maintains the mapping and hands
  10. * us our EPD address as a context with each indication ReceiveEvent.
  11. *
  12. * In addition to EndPoint creation and destruction, this file contains routines
  13. * which handle link tuning. This is described in detailed comments below.
  14. *
  15. * History:
  16. * Date By Reason
  17. * ==== == ======
  18. * 11/06/98 ejs Created
  19. * 07/01/2000 masonb Assumed Ownership
  20. * 13/06/2002 simonpow MANBUG #56703 Capped burst gap growth
  21. *
  22. ****************************************************************************/
  23. #include "dnproti.h"
  24. VOID RunAdaptiveAlg(PEPD, DWORD);
  25. VOID ThrottleBack(PEPD, DWORD);
  26. /*
  27. ** Crack EndPoint Descriptor
  28. **
  29. */
  30. #undef DPF_MODNAME
  31. #define DPF_MODNAME "DNPCrackEndPointDescriptor"
  32. HRESULT
  33. DNPCrackEndPointDescriptor(HANDLE hProtocolData, HANDLE hEndPoint, PSPGETADDRESSINFODATA pSPData)
  34. {
  35. ProtocolData* pPData;
  36. PEPD pEPD;
  37. PSPD pSPD;
  38. HRESULT hr;
  39. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hEndPoint[%p], pSPData[%p]", hProtocolData, hEndPoint, pSPData);
  40. pPData = (ProtocolData*)hProtocolData;
  41. ASSERT_PPD(pPData);
  42. pEPD = (PEPD) hEndPoint;
  43. ASSERT_EPD(pEPD);
  44. LOCK_EPD(pEPD, "LOCK (Crack EPD)");
  45. Lock(&pEPD->EPLock);
  46. if(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED)
  47. {
  48. pSPD = pEPD->pSPD;
  49. ASSERT_SPD(pSPD);
  50. pSPData->hEndpoint = pEPD->hEndPt;
  51. Unlock(&pEPD->EPLock);
  52. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  53. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->GetAddressInfo, pSPD[%p]", pEPD, pSPD);
  54. hr = IDP8ServiceProvider_GetAddressInfo(pSPD->IISPIntf, pSPData);
  55. Lock(&pEPD->EPLock);
  56. }
  57. else
  58. {
  59. hr = DPNERR_INVALIDENDPOINT;
  60. }
  61. RELEASE_EPD(pEPD, "UNLOCK (Crack EPD)"); // releases EPLock
  62. DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x], pEPD[%p]", hr, pEPD);
  63. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  64. return hr;
  65. }
  66. #ifndef DPNBUILD_NOMULTICAST
  67. /*
  68. ** Get an EndPoint context from an Address
  69. */
  70. #undef DPF_MODNAME
  71. #define DPF_MODNAME "DNPGetEndPointContextFromAddress"
  72. HRESULT
  73. DNPGetEndPointContextFromAddress(HANDLE hProtocolData, HANDLE hSPHandle, IDirectPlay8Address* paEndpointAddress, IDirectPlay8Address* paDeviceAddress, VOID** ppvContext)
  74. {
  75. ProtocolData* pPData;
  76. PSPD pSPD;
  77. PEPD pEPD;
  78. HRESULT hr;
  79. SPGETENDPOINTBYADDRESSDATA spdata;
  80. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hSPHandle[%p], paEndpointAddress[%p], paDeviceAddress[%p], ppvContext[%p]", hProtocolData, hSPHandle, paEndpointAddress, paDeviceAddress, ppvContext);
  81. pPData = (ProtocolData*)hProtocolData;
  82. ASSERT_PPD(pPData);
  83. pSPD = (PSPD)hSPHandle;
  84. ASSERT_SPD(pSPD);
  85. //
  86. // Set up to get endpoint
  87. //
  88. memset(&spdata,0,sizeof(SPGETENDPOINTBYADDRESSDATA));
  89. spdata.pAddressHost = paEndpointAddress;
  90. spdata.pAddressDeviceInfo = paDeviceAddress;
  91. //
  92. // Get endpoint from SP
  93. //
  94. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  95. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->GetEndpointByAddress, pSPD[%p]", pSPD);
  96. hr = IDP8ServiceProvider_GetEndpointByAddress(pSPD->IISPIntf, &spdata);
  97. //
  98. // Get context from endpoint
  99. if (hr == DPN_OK)
  100. {
  101. pEPD = (PEPD)spdata.pvEndpointContext;
  102. ASSERT_EPD(pEPD);
  103. Lock(&pEPD->EPLock);
  104. *ppvContext = pEPD->Context;
  105. Unlock(&pEPD->EPLock);
  106. }
  107. DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x]", hr);
  108. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  109. return hr;
  110. }
  111. #endif // ! DPNBUILD_NOMULTICAST
  112. /*
  113. ** INTERNAL - EndPoint management functions
  114. */
  115. /*
  116. ** New End Point
  117. **
  118. ** Everytime a packet is indicated with an address that we dont recognize we will allocate
  119. ** an EPD for it and add it to our tables. It is a higher layer's responsibility to tell
  120. ** us when it no longer wants to talk to the EP so that we can clear it out of our
  121. ** (and the SP's) table.
  122. **
  123. */
  124. #undef DPF_MODNAME
  125. #define DPF_MODNAME "NewEndPoint"
  126. PEPD NewEndPoint(PSPD pSPD, HANDLE hEP)
  127. {
  128. PEPD pEPD;
  129. if((pEPD = (PEPD)POOLALLOC(MEMID_EPD, &EPDPool)) == NULL)
  130. {
  131. DPFX(DPFPREP,0, "Failed to allocate new EPD");
  132. return NULL;
  133. }
  134. ASSERT(hEP != INVALID_HANDLE_VALUE);
  135. pEPD->hEndPt = hEP; // Record ID in structure
  136. pEPD->pSPD = pSPD;
  137. pEPD->bNextMsgID = 0;
  138. pEPD->uiRTT = 0;
  139. pEPD->uiBytesAcked = 0;
  140. pEPD->ullCurrentLocalSecret=0;
  141. pEPD->ullCurrentRemoteSecret=0;
  142. pEPD->ullOldLocalSecret=0;
  143. pEPD->ullOldRemoteSecret=0;
  144. pEPD->ullLocalSecretModifier=0;
  145. pEPD->ullRemoteSecretModifier=0;
  146. pEPD->byLocalSecretModifierSeqNum=0;
  147. pEPD->byRemoteSecretModifierSeqNum=0;
  148. pEPD->uiQueuedMessageCount = 0;
  149. #ifdef DBG
  150. pEPD->bLastDataSeq = 0xFF;
  151. #endif // DBG
  152. // We track a byte-window and a frame-window separately.
  153. // We start a byte window that is set to half the maximum frame size * the frame window
  154. pEPD->uiWindowF = pSPD->pPData->dwInitialFrameWindowSize;
  155. pEPD->uiWindowBIndex = pSPD->pPData->dwInitialFrameWindowSize/2;
  156. pEPD->uiWindowB = pEPD->uiWindowBIndex*pSPD->uiFrameLength;
  157. pEPD->uiUnackedFrames = 0; // outstanding frame count
  158. pEPD->uiUnackedBytes = 0; // outstanding byte count
  159. pEPD->uiBurstGap = 0; // For now assume we dont need a burst gap
  160. pEPD->dwSessID = 0;
  161. // ReceiveComplete flag prevents received data from being indicated to core until after new connection is indicated
  162. // Initialize state
  163. pEPD->ulEPFlags = EPFLAGS_END_POINT_IN_USE | EPFLAGS_STATE_DORMANT | EPFLAGS_IN_RECEIVE_COMPLETE; // Initialize state
  164. pEPD->ulEPFlags2 = 0;
  165. ASSERT(pEPD->lRefCnt == 0); // WE NOW HAVE A -1 BASED REFCNT INSTEAD OF ZERO BASED (FOR EPDs)
  166. pEPD->SendTimer = 0; // Timer for next send-burst opportunity
  167. pEPD->RetryTimer = 0; // window to receive Ack
  168. pEPD->LinkTimer = 0;
  169. pEPD->DelayedAckTimer = 0; // wait for piggyback opportunity before sending Ack
  170. pEPD->DelayedMaskTimer = 0; // wait for piggyback opportunity before sending Mask frame
  171. pEPD->BGTimer = 0; // Periodic background timer
  172. pEPD->uiCompleteMsgCount = 0;
  173. LOCK_EPD(pEPD, "SP reference"); // We will not remove this reference until the SP tells us to go away.
  174. Lock(&pSPD->SPLock);
  175. pEPD->blActiveLinkage.InsertAfter( &pSPD->blEPDActiveList); // Place this guy in active list
  176. Unlock(&pSPD->SPLock);
  177. return pEPD;
  178. }
  179. /*
  180. ** Initial Link Parameters
  181. **
  182. ** we have kept a checkpoint structure matching everying frame we sent in the Connect
  183. ** handshake so that we can match a response to a specific frame or retry. This allows us
  184. ** to measure a single sample Round Trip Time (RTT), which we will use below to generate
  185. ** initial values for our link-state variables.
  186. **
  187. */
  188. #undef DPF_MODNAME
  189. #define DPF_MODNAME "InitLinkParameters"
  190. VOID InitLinkParameters(PEPD pEPD, UINT uiRTT, DWORD tNow)
  191. {
  192. PSPD pSPD = pEPD->pSPD;
  193. DWORD dwTimerInterval;
  194. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  195. if(uiRTT == 0)
  196. {
  197. uiRTT = 1;
  198. }
  199. pEPD->uiRTT = uiRTT; // we know the base RTT
  200. pEPD->fpRTT = TO_FP(uiRTT); // 16.16 fixed point version
  201. pEPD->uiDropCount = 0;
  202. pEPD->dwDropBitMask = 0;
  203. pEPD->uiThrottleEvents = 0; // Count times we throttle-back for all reasons
  204. #ifdef DBG
  205. pEPD->uiTotalThrottleEvents = 0;
  206. #endif // DBG
  207. pEPD->uiBurstGap = 0; // For now assume we dont need a burst gap
  208. pEPD->uiMsgSentHigh = 0;
  209. pEPD->uiMsgSentNorm = 0;
  210. pEPD->uiMsgSentLow = 0;
  211. pEPD->uiMsgTOHigh = 0;
  212. pEPD->uiMsgTONorm = 0;
  213. pEPD->uiMsgTOLow = 0;
  214. pEPD->uiMessagesReceived = 0;
  215. pEPD->uiGuaranteedFramesSent = 0;
  216. pEPD->uiGuaranteedBytesSent = 0;
  217. pEPD->uiDatagramFramesSent = 0;
  218. pEPD->uiDatagramBytesSent = 0;
  219. pEPD->uiGuaranteedFramesReceived = 0;
  220. pEPD->uiGuaranteedBytesReceived = 0;
  221. pEPD->uiDatagramFramesReceived = 0;
  222. pEPD->uiDatagramBytesReceived = 0;
  223. pEPD->uiGuaranteedFramesDropped = 0;
  224. pEPD->uiGuaranteedBytesDropped = 0;
  225. pEPD->uiDatagramFramesDropped = 0;
  226. pEPD->uiDatagramBytesDropped = 0;
  227. pEPD->uiGoodBurstGap = 0; // No Known Good Gap!
  228. pEPD->uiGoodRTT = 60000; // We need this to initially be artificially high
  229. pEPD->uiGoodWindowF = (pEPD->pSPD->pPData->dwInitialFrameWindowSize*3)/4;
  230. pEPD->uiGoodWindowBI = pEPD->uiGoodWindowF;
  231. pEPD->iBurstCredit = 0;
  232. pEPD->tLastDelta = tNow;
  233. pEPD->uiWindowFilled = 0;
  234. pEPD->tLastThruPutSample = tNow;
  235. pEPD->uiLastBytesAcked = 0;
  236. pEPD->uiPeriodAcksBytes = 0;
  237. pEPD->uiPeriodXmitTime = 0;
  238. pEPD->uiPeriodRateB = 0;
  239. pEPD->uiPeakRateB = 0;
  240. pEPD->uiLastRateB = 0;
  241. pEPD->ulReceiveMask = 0;
  242. pEPD->ulReceiveMask2 = 0;
  243. pEPD->tReceiveMaskDelta = 0;
  244. pEPD->ulSendMask = 0;
  245. pEPD->ulSendMask2 = 0;
  246. pEPD->Context = NULL;
  247. DPFX(DPFPREP,7, "CONNECTION ESTABLISHED pEPD = 0x%p RTT = %dms, BurstGap=%dms", pEPD, pEPD->uiRTT, pEPD->uiBurstGap);
  248. // We set the IdleThreshhold very low to generate a little bit of traffic for initial link tuning in case the
  249. // application doesnt do any right away
  250. // pEPD->ulEPFlags |= EPFLAGS_USE_POLL_DELAY; // always assume balanced traffic at start-up
  251. pEPD->uiAdaptAlgCount = 4; // start running adpt alg fairly often
  252. // Calc a retry timeout value based upon the measured RTT (2.5 * RTT) + MAX_DELAY
  253. pEPD->uiRetryTimeout = ((pEPD->uiRTT + (pEPD->uiRTT >> 2)) * 2) + DELAYED_ACK_TIMEOUT;
  254. // don't want to get more aggressive because we drop a frame.
  255. if(pEPD->uiRetryTimeout < pEPD->uiBurstGap)
  256. {
  257. pEPD->uiRetryTimeout = pEPD->uiBurstGap;
  258. }
  259. pEPD->uiUserFrameLength = pEPD->pSPD->uiUserFrameLength;
  260. if(pEPD->BGTimer == 0)
  261. {
  262. if (pEPD->pSPD->pPData->tIdleThreshhold > ENDPOINT_BACKGROUND_INTERVAL)
  263. {
  264. dwTimerInterval = ENDPOINT_BACKGROUND_INTERVAL;
  265. }
  266. else
  267. {
  268. dwTimerInterval = pEPD->pSPD->pPData->tIdleThreshhold;
  269. }
  270. DPFX(DPFPREP,7, "(%p) Setting Endpoint Background Timer for %u ms", pEPD, dwTimerInterval);
  271. ScheduleProtocolTimer(pSPD, dwTimerInterval, 1000, EndPointBackgroundProcess,
  272. (PVOID) pEPD, &pEPD->BGTimer, &pEPD->BGTimerUnique);
  273. LOCK_EPD(pEPD, "LOCK (BG Timer)"); // create reference for this timer
  274. }
  275. }
  276. /****************
  277. *
  278. * Link Tuning
  279. *
  280. * Here are current ideas about link tuning. Idea is to track Round Trip Time of key-frames and throttle
  281. * based upon changes in this measured RTT when possible. This would benefit us in determining link saturation
  282. * before packet loss occurs, instead of waiting for the inevitable packet loss before throttling back.
  283. *
  284. * On high-speed media, the average RTT is small compared to the standard deviations making it hard to
  285. * predict anything useful from them. In these cases, we must look at packet drops. Except for one exception:
  286. * We will look for large spikes in RTT and we will respond to these with an immediate, temporary throttle back.
  287. * This will allow a bottle-neck to clear hopefully without packet-loss. So far, I have not been able to verfify
  288. * any benefit from this behavior on reliable links. It is more likely to be beneficial with datagram traffic
  289. * where send windows do not limit write-ahead.
  290. *
  291. * I would like to take a measurement of the through-put acheived compared to the transmission rate, but I
  292. * havent yet come up with a good way to measure this. What I do calculate is packet acknowledgement rate, which
  293. * can be calculated without any additional input from the remote side. We will store AckRates acheived at the
  294. * previous transmission rate, so we can look for improvements in Acks as we increase Transmissions. When we
  295. * no longer detect AckRate improvements then we assume we have plateaued and we stop trying to increase the rate.
  296. *
  297. * TRANSMISSION RATE
  298. *
  299. * Transmission rate is controlled by two distinct parameters: Insertion Rate and Window Size. Where a
  300. * conventional protocol would dump a window full of packets onto the wire in one burst, we would like to
  301. * spread the packet insertions out over the full RTT so that the window never completely fills and hence
  302. * blocks the link from transmitting. This has a wide array of potential benefits: Causes less congestions
  303. * throughout the network path; Allows more balanced access to the wire to all Endpoints (especially on
  304. * slower media); Allows MUCH more accurate measurements to be made of trasmission times when packets
  305. * spend less time enqueued locally; Allows retry timers to be set much lower giving us quicker error
  306. * recovery (because there is less queue time fudged into the timer); Allows recovery to be made more
  307. * quickly when we don't have a lot of data enqueued in SP (both our own data and other Endpoint's data).
  308. * ...And I am sure there are more.
  309. *
  310. * So, we would like to trickle out packets just fast enough to fill the window as the next ACK is received.
  311. * We will grow the window fairly liberally and let the burst rate increase more cautiously.
  312. *
  313. * On high-speed media the insertion time becomes fairly small (near zero) and we are less likely to queue
  314. * up large quantities of data. Therefore we may allow insertion rate to go max and use the window alone to
  315. * control flow. I will experiment with this more.
  316. *
  317. ******************/
  318. #define RTT_SLOW_WEIGHT 8 // fpRTT gain = 1/8
  319. #define THROTTLE_EVENT_THRESHOLD 20
  320. /*
  321. ** Update Endpoint
  322. **
  323. ** We will let the sliding window control the flow
  324. ** and increase the window as long as through-put continues to increase and frames continue to get delivered without
  325. ** excessive droppage.
  326. **
  327. ** We still calculate RTT for the purpose of determining RetryTimer values. For cases with large RTTs we may still
  328. ** implement an inter-packet gap, but we will try to make it an aggressive gap (conservatively small) because we would
  329. ** rather feed the pipe too quickly than artificially add latency by letting the pipe go idle with data ready to be sent.
  330. **
  331. ** ** CALLED WITH EPD STATELOCK HELD **
  332. */
  333. #undef DPF_MODNAME
  334. #define DPF_MODNAME "UpdateEndPoint"
  335. VOID UpdateEndPoint(PEPD pEPD, UINT uiRTT, DWORD tNow)
  336. {
  337. UINT fpRTT;
  338. INT fpDiff;
  339. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  340. // Don't allow zero RTTs
  341. if(uiRTT == 0)
  342. {
  343. uiRTT = 1;
  344. }
  345. // Filter out HUGE samples, they often popup during debug sessions
  346. else if(uiRTT > (pEPD->uiRTT * 128))
  347. {
  348. DPFX(DPFPREP,7, "Tossing huge sample (%dms, base %dms)", uiRTT, pEPD->uiRTT);
  349. return;
  350. }
  351. // Perform next iteration of math on new RTT sample in 16.16 fixed point
  352. fpRTT = TO_FP(uiRTT); // Fixed point sample
  353. fpDiff = fpRTT - pEPD->fpRTT; // Current Delta (signed)
  354. pEPD->fpRTT = pEPD->fpRTT + (fpDiff / RTT_SLOW_WEIGHT); // .0625 weighted avg
  355. pEPD->uiRTT = FP_INT(pEPD->fpRTT); // Store integer portion
  356. // Calc a retry timeout value based upon the measured RTT (2.5 * RTT) + MAX_DELAY
  357. pEPD->uiRetryTimeout = ((pEPD->uiRTT + (pEPD->uiRTT >> 2)) * 2) + DELAYED_ACK_TIMEOUT;
  358. // don't want to get more aggressive because we drop a frame.
  359. if(pEPD->uiRetryTimeout < pEPD->uiBurstGap)
  360. {
  361. pEPD->uiRetryTimeout = pEPD->uiBurstGap;
  362. }
  363. DPFX(DPFPREP,7, "(%p) RTT SAMPLE: RTT = %d, Avg = %d <<<<", pEPD, uiRTT, FP_INT(pEPD->fpRTT));
  364. // If throttle is engaged we will see if we can release it yet
  365. if(pEPD->ulEPFlags & EPFLAGS_THROTTLED_BACK)
  366. {
  367. if((tNow - pEPD->tThrottleTime) > (pEPD->uiRTT * 8))
  368. {
  369. pEPD->ulEPFlags &= ~(EPFLAGS_THROTTLED_BACK);
  370. pEPD->uiDropCount = 0;
  371. pEPD->dwDropBitMask = 0;
  372. pEPD->uiBurstGap = pEPD->uiRestoreBurstGap;
  373. pEPD->uiWindowF = pEPD->uiRestoreWindowF;
  374. pEPD->uiWindowBIndex = pEPD->uiRestoreWindowBI;
  375. pEPD->uiWindowB = pEPD->uiWindowBIndex * pEPD->pSPD->uiFrameLength;
  376. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "** (%p) RECOVER FROM THROTTLE EVENT: Window(F:%d,B:%d); Gap=%d", pEPD, pEPD->uiWindowF, pEPD->uiWindowBIndex, pEPD->uiBurstGap);
  377. pEPD->tLastDelta = tNow; // Enforce waiting period after back-off before tuning up again
  378. }
  379. }
  380. // Throttle Event tracks how often a packet-drop has caused us to throttle back transmission rate. We will let this value
  381. // decay over time. If throttle events happen faster then the decay occurs then this value will grow un-bounded. This
  382. // growth is what causes a decrease in the actual send window/transmit rate that will persist beyond the throttle event.
  383. else if(pEPD->uiThrottleEvents)
  384. {
  385. pEPD->uiThrottleEvents--; // Let this decay...
  386. }
  387. if(--pEPD->uiAdaptAlgCount == 0)
  388. {
  389. RunAdaptiveAlg(pEPD, tNow);
  390. }
  391. }
  392. /*
  393. ** Grow Send Window
  394. **
  395. ** The two parallel send windows, frame-based and byte-based, can grow and shrink independently. In this
  396. ** routine we will grow one or both windows. We will grow each window providing that it has been filled in the
  397. ** last period, during which we have determined that thru-put has increased.
  398. */
  399. #undef DPF_MODNAME
  400. #define DPF_MODNAME "GrowSendWindow"
  401. BOOL
  402. GrowSendWindow(PEPD pEPD, DWORD tNow)
  403. {
  404. UINT delta = 0;
  405. pEPD->tLastDelta = tNow;
  406. // first store current good values for a restore
  407. pEPD->uiGoodWindowF = pEPD->uiWindowF;
  408. pEPD->uiGoodWindowBI = pEPD->uiWindowBIndex;
  409. pEPD->uiGoodRTT = pEPD->uiRTT;
  410. pEPD->uiGoodBurstGap = pEPD->uiBurstGap;
  411. if(pEPD->uiBurstGap)
  412. {
  413. // cut the burst gap by 25% if less than 3 ms go to 0.
  414. if(pEPD->uiBurstGap > 3)
  415. {
  416. pEPD->uiBurstGap -= pEPD->uiBurstGap >> 2;
  417. }
  418. else
  419. {
  420. pEPD->uiBurstGap = 0;
  421. }
  422. pEPD->uiLastRateB = pEPD->uiPeriodRateB;
  423. pEPD->uiPeriodAcksBytes = 0;
  424. pEPD->uiPeriodXmitTime = 0;
  425. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p), burst gap set to %d ms", pEPD, pEPD->uiBurstGap);
  426. }
  427. else
  428. {
  429. if((pEPD->ulEPFlags & EPFLAGS_FILLED_WINDOW_FRAME) && (pEPD->uiWindowF < MAX_RECEIVE_RANGE))
  430. {
  431. pEPD->uiWindowF++;
  432. delta = 1;
  433. }
  434. if((pEPD->ulEPFlags & EPFLAGS_FILLED_WINDOW_BYTE) && (pEPD->uiWindowBIndex < MAX_RECEIVE_RANGE))
  435. {
  436. pEPD->uiWindowBIndex++;
  437. pEPD->uiWindowB += pEPD->pSPD->uiFrameLength;
  438. delta = 1;
  439. }
  440. pEPD->ulEPFlags &= ~(EPFLAGS_FILLED_WINDOW_FRAME | EPFLAGS_FILLED_WINDOW_BYTE);
  441. pEPD->uiWindowFilled = 0;
  442. if(delta)
  443. {
  444. pEPD->uiLastRateB = pEPD->uiPeriodRateB;
  445. pEPD->uiPeriodAcksBytes = 0;
  446. pEPD->uiPeriodXmitTime = 0;
  447. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) ** GROW SEND WINDOW to %d frames and %d (%d) bytes", pEPD, pEPD->uiWindowF, pEPD->uiWindowB, pEPD->uiWindowBIndex);
  448. }
  449. else
  450. {
  451. // We get here if we have already max'd out the window
  452. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) GROW SEND WINDOW -- Nothing to grow. Transition to Stable!", pEPD);
  453. pEPD->ulEPFlags |= EPFLAGS_LINK_STABLE;
  454. return FALSE;
  455. }
  456. }
  457. return TRUE;
  458. }
  459. #undef DPF_MODNAME
  460. #define DPF_MODNAME "RunAdaptiveAlg"
  461. VOID
  462. RunAdaptiveAlg(PEPD pEPD, DWORD tNow)
  463. {
  464. LONG tDelta; // Time the link was transmitting since last run of AdaptAlg
  465. UINT uiBytesAcked;
  466. UINT uiNewSum;
  467. // Calculate the time during which this link was actually transmitting to make sure we have enough
  468. // data to run the Adaptive Alg. This is easy unless we are currently idle...
  469. tDelta = tNow - pEPD->tLastThruPutSample;
  470. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) Adaptive Alg tDelta = %d", pEPD, tDelta);
  471. // THIS PROBABLY IS UNNECESSARY NOW...
  472. if(tDelta <= 0)
  473. {
  474. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "DELAYING Adaptive Alg");
  475. pEPD->uiAdaptAlgCount = 4;
  476. return;
  477. }
  478. // Calculate current throughput acheived
  479. //
  480. // We will determine the amount of time the link was not idle and then number of bytes (& frames) which
  481. // were acknowleged by our partner.
  482. //
  483. // tDelta = Time since last calculation minus the time the link was idle.
  484. uiBytesAcked = pEPD->uiBytesAcked - pEPD->uiLastBytesAcked;
  485. uiNewSum = pEPD->uiPeriodAcksBytes + (uiBytesAcked * 256);
  486. if(uiNewSum < pEPD->uiPeriodAcksBytes)
  487. {
  488. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "THRUPUT is about to wrap. Correcting...");
  489. pEPD->uiPeriodAcksBytes /= 2;
  490. pEPD->uiPeriodXmitTime /= 2;
  491. pEPD->uiPeriodAcksBytes += (uiBytesAcked * 256);
  492. }
  493. else
  494. {
  495. pEPD->uiPeriodAcksBytes = uiNewSum;
  496. }
  497. pEPD->uiPeriodXmitTime += tDelta; // Track complete values for this period
  498. pEPD->tLastThruPutSample = tNow;
  499. pEPD->uiLastBytesAcked = pEPD->uiBytesAcked;
  500. pEPD->uiPeriodRateB = pEPD->uiPeriodAcksBytes / pEPD->uiPeriodXmitTime;
  501. if(pEPD->uiPeriodRateB > pEPD->uiPeakRateB)
  502. {
  503. pEPD->uiPeakRateB = pEPD->uiPeriodRateB; // Track the largest value we ever measure
  504. }
  505. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) PERIOD COUNT BYTES = %u, XmitTime = %u, Thruput=(%u bytes/s), RTT=%u, Window=(%u,%u)", pEPD, pEPD->uiPeriodAcksBytes, pEPD->uiPeriodXmitTime, pEPD->uiPeriodRateB * 4, pEPD->uiRTT, pEPD->uiWindowF, pEPD->uiWindowB);
  506. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  507. if (pEPD->ulEPFlags & EPFLAGS_LINK_FROZEN)
  508. {
  509. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) Test App requests that dynamic algorithm not be run, skipping", pEPD);
  510. pEPD->uiAdaptAlgCount = 32; // Make sure the throughput numbers get updated from time to time
  511. return;
  512. }
  513. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  514. if(pEPD->ulEPFlags & EPFLAGS_LINK_STABLE)
  515. {
  516. /* We are in a STABLE state, meaning we think we are transmitting at an optimal
  517. ** rate for the current network conditions. Conditions may change. If things slow down
  518. ** or grow congested a Backoff will trigger normally. Since conditions might also change
  519. ** for the better, we will still want to periodically probe higher rates, but much less
  520. ** often than when we are in DYNAMIC mode, which means we are searching for an optimal rate.
  521. */
  522. pEPD->uiAdaptAlgCount = 32; // tNow + (pEPD->uiRTT * 32) + 32;
  523. if((tNow - pEPD->tLastDelta) > INITIAL_STATIC_PERIOD)
  524. {
  525. if(pEPD->ulEPFlags & (EPFLAGS_FILLED_WINDOW_FRAME | EPFLAGS_FILLED_WINDOW_BYTE))
  526. {
  527. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) RETURNING LINK TO DYNAMIC MODE", pEPD);
  528. pEPD->ulEPFlags &= ~(EPFLAGS_LINK_STABLE);
  529. pEPD->uiPeriodAcksBytes = 0;
  530. pEPD->uiPeriodXmitTime = 0;
  531. pEPD->uiWindowFilled = 0;
  532. pEPD->ulEPFlags &= ~(EPFLAGS_FILLED_WINDOW_FRAME | EPFLAGS_FILLED_WINDOW_BYTE);
  533. pEPD->uiAdaptAlgCount = 12;
  534. }
  535. else
  536. {
  537. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) NO WINDOWS FILLED, Not returning to Dynamic Mode", pEPD);
  538. pEPD->tLastDelta = tNow;
  539. }
  540. }
  541. else
  542. {
  543. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) STILL IN STATIC PERIOD, time=%u, period=%u", pEPD, tNow - pEPD->tLastDelta, INITIAL_STATIC_PERIOD);
  544. }
  545. }
  546. // DYNAMIC STATE LINK
  547. else
  548. {
  549. pEPD->uiAdaptAlgCount = 8;
  550. // Possibly increase transmission rates. We will not do this if we have had a ThrottleEvent
  551. // in recent memory, or if we have not been actually transmitting for enough of the interval
  552. // to have collected worthwhile data
  553. //
  554. // Also, we dont want to even consider growing the send window unless we are consistantly
  555. // filling it. Since one job of the window is to prevent us from flooding the net during a backup,
  556. // we dont want to grow the window following each backup. The best way to distinguish between a
  557. // backup and too small of a window is that the small window should fill up regularly while the
  558. // backups should only occur intermittantly. The hard part is coming up with the actual test.
  559. // Truth is, we can be fairly lax about allowing growth because it will also have to meet the increased
  560. // bandwidth test before the larger window is accepted. So a crude rule would be to fix a number like 3.
  561. // Yes, crude but probably effective. Perhaps a more reasonable figure would be a ratio of the total
  562. // number of packets sent divided by the window size. I.e., if your window size is 10 frames then one
  563. // packet in ten should fill the window. Of course, this would have to be calculated in bytes...
  564. if((pEPD->uiWindowFilled > 12)&&(pEPD->uiThrottleEvents == 0))
  565. {
  566. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) DYNAMIC ALG: Window Fills: %d; B-Ack = (%x vs %x)", pEPD, pEPD->uiWindowFilled, pEPD->uiPeriodRateB, pEPD->uiLastRateB);
  567. pEPD->uiWindowFilled = 0;
  568. if (!(pEPD->ulEPFlags & EPFLAGS_TESTING_GROWTH))
  569. {
  570. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) GROWING WINDOW", pEPD);
  571. // In the case that GrowSendWindow doesn't grow anything because we are already max'd out
  572. // it will return FALSE, and it should have transitioned us to STABLE.
  573. if (GrowSendWindow(pEPD, tNow))
  574. {
  575. pEPD->ulEPFlags |= EPFLAGS_TESTING_GROWTH;
  576. }
  577. else
  578. {
  579. ASSERT(pEPD->ulEPFlags & EPFLAGS_LINK_STABLE);
  580. }
  581. return;
  582. }
  583. // GETTING HERE means that we have used our current transmit parameters long enough
  584. // to have an idea of their performance. We will now compare this to the performance
  585. // of the previous transmit parameters and we will either Revert to the previous set if
  586. // the perf is not improved, or else we will advance to faster parameters if we did see
  587. // a jump.
  588. // In order to keep higher transmit parameters we need to see an increase in throughput
  589. // with no corresponding rise in RTT. We will want to see this twice just to be sure
  590. // since the cost of incorrect growth is so high on a modem.
  591. if( (pEPD->uiPeriodRateB > pEPD->uiLastRateB) &&
  592. (pEPD->uiRTT <= (pEPD->uiGoodRTT + 10))
  593. )
  594. {
  595. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) Throughput increased after window growth, keeping new parameters", pEPD);
  596. pEPD->ulEPFlags &= ~(EPFLAGS_TESTING_GROWTH);
  597. pEPD->uiPeriodAcksBytes = 0;
  598. pEPD->uiPeriodXmitTime = 0;
  599. }
  600. else
  601. {
  602. // We did not see a thru-put improvement so we will back off the previous value
  603. // and transition the link to STABLE state.
  604. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) INSUFFICENT INCREASE IN THRUPUT, BACK OFF AND TRANSITION TO STABLE", pEPD);
  605. // Because we have over-transmitted for at least one period, we may have put excess data
  606. // on the link in a buffer. This will have the effect of gradually growing our RTT if we
  607. // don't bleed that data off which we will do here by backing off two steps where we
  608. // previously grew one step.
  609. if (pEPD->uiBurstGap != pEPD->uiGoodBurstGap)
  610. {
  611. // increase the burst gap by 25%, clipping it to the max retry interval/2
  612. pEPD->uiBurstGap = pEPD->uiGoodBurstGap + (pEPD->uiGoodBurstGap >> 2);
  613. DWORD dwMaxBurstGap=pEPD->pSPD->pPData->dwSendRetryIntervalLimit/2;
  614. if (pEPD->uiBurstGap>dwMaxBurstGap)
  615. {
  616. pEPD->uiBurstGap=dwMaxBurstGap;
  617. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) Clipped burst gap to value %u", pEPD, pEPD->uiBurstGap);
  618. }
  619. }
  620. if (pEPD->uiWindowF != pEPD->uiGoodWindowF)
  621. {
  622. if (pEPD->uiGoodWindowF > 2)
  623. {
  624. pEPD->uiWindowF = _MAX(pEPD->uiGoodWindowF - 1, 1);
  625. }
  626. else
  627. {
  628. pEPD->uiWindowF = pEPD->uiGoodWindowF;
  629. }
  630. }
  631. if (pEPD->uiWindowBIndex != pEPD->uiGoodWindowBI)
  632. {
  633. pEPD->uiWindowBIndex = _MAX(pEPD->uiGoodWindowBI - 1, 1);
  634. pEPD->uiWindowB = pEPD->uiWindowBIndex * pEPD->pSPD->uiFrameLength;
  635. }
  636. pEPD->ulEPFlags |= EPFLAGS_LINK_STABLE; // TRANSITION TO STABLE STATE
  637. pEPD->ulEPFlags &= ~(EPFLAGS_TESTING_GROWTH);
  638. pEPD->uiPeriodAcksBytes = 0;
  639. pEPD->uiPeriodXmitTime = 0;
  640. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) ** TUNING LINK: BurstGap=%d; FWindow=%d, BWindow=%d (%d)",pEPD, pEPD->uiBurstGap, pEPD->uiWindowF, pEPD->uiWindowB, pEPD->uiWindowBIndex);
  641. }
  642. }
  643. else
  644. {
  645. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) DYN ALG -- Not trying to increase: WindowFills = %d, ThrottleCount = %d", pEPD, pEPD->uiWindowFilled, pEPD->uiThrottleEvents);
  646. }
  647. } // END IF DYNAMIC STATE LINK
  648. }
  649. /*
  650. ** End Point Dropped Frame
  651. **
  652. ** We have two levels of Backoff. We have an immediate BackOff implemented
  653. ** upon first detection of a drop-event in order to relieve the congestion which
  654. ** caused the drop. An immediate backoff will resume transmitting at the original
  655. ** rate without going through slow-start again after the congestion event has passed.
  656. ** If we have multiple immediate-backoffs in a certain interval we will have a
  657. ** hard backoff which will not restore.
  658. **
  659. ** CALLED WITH EPD->SPLock held (and sometimes with StateLock held too)
  660. */
  661. #undef DPF_MODNAME
  662. #define DPF_MODNAME "EndPointDroppedFrame"
  663. VOID
  664. EndPointDroppedFrame(PEPD pEPD, DWORD tNow)
  665. {
  666. //
  667. // Don't change count if "expiring" drop rolls off
  668. //
  669. if (!(pEPD->dwDropBitMask & 0x80000000))
  670. {
  671. pEPD->uiDropCount++;
  672. }
  673. //
  674. // Adjust mask
  675. //
  676. pEPD->dwDropBitMask = (pEPD->dwDropBitMask << 1) + 1;
  677. DPFX(DPFPREP,7, "(%p) Drop Count %d, Drop Bit Mask 0x%lx", pEPD,pEPD->uiDropCount,pEPD->dwDropBitMask);
  678. //
  679. // Should we throttle ?
  680. //
  681. if (pEPD->uiDropCount > pEPD->pSPD->pPData->dwDropThreshold)
  682. {
  683. DPFX(DPFPREP,7, "(%p) THROTTLING BACK", pEPD);
  684. ThrottleBack(pEPD, tNow);
  685. //
  686. // Reset drop count
  687. //
  688. pEPD->dwDropBitMask = 0;
  689. pEPD->uiDropCount = 0;
  690. }
  691. }
  692. /*
  693. ** Throttle Back
  694. **
  695. ** We suspect network congestion due to dropped frames ((or a spike in latency)). We want
  696. ** to quickly scale back our transmit rate to releive the congestion and avoid further packet drops.
  697. ** This is a temporary backoff and we will resume our current transmit rate when the congestions
  698. ** clears.
  699. **
  700. ** If we find that we are throttling back frequently then we may conclude that our current xmit
  701. ** rate is higher then optimal and we will BackOff to a lower rate, and transition to a STABLE link
  702. ** state (if not already there) to indicate that we have plateaued.
  703. **
  704. ** A note on convergence. The ThrottleEvents variable is incremented 10 points each time a throttle
  705. ** event is triggered. This variable also decays slowly when the link is running without events. So if
  706. ** the variable grows faster then it decays we will eventually trigger a switch to STABLE state
  707. */
  708. #undef DPF_MODNAME
  709. #define DPF_MODNAME "ThrottleBack"
  710. VOID
  711. ThrottleBack(PEPD pEPD, DWORD tNow)
  712. {
  713. #ifndef DPNBUILD_NOPROTOCOLTESTITF
  714. if (pEPD->ulEPFlags & EPFLAGS_LINK_FROZEN)
  715. {
  716. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) Test App requests that throttle code not be run, skipping", pEPD);
  717. return;
  718. }
  719. #endif // !DPNBUILD_NOPROTOCOLTESTITF
  720. pEPD->ulEPFlags |= EPFLAGS_THROTTLED_BACK; // Set link to THROTTLED state
  721. pEPD->uiThrottleEvents += 10; // Count times we throttle-back for all reasons
  722. pEPD->tThrottleTime = tNow; // Remember time that throttle was engaged
  723. #ifdef DBG
  724. pEPD->uiTotalThrottleEvents++; // Count times we throttle-back for all reasons
  725. #endif // DBG
  726. pEPD->uiRestoreBurstGap = pEPD->uiBurstGap;
  727. pEPD->uiRestoreWindowF = pEPD->uiWindowF;
  728. pEPD->uiRestoreWindowBI = pEPD->uiWindowBIndex;
  729. if(pEPD->uiWindowF == 1)
  730. {
  731. if(pEPD->uiBurstGap == 0)
  732. {
  733. pEPD->uiBurstGap = _MAX(1,pEPD->uiRTT/2);
  734. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p), first burst gap, set to %d ms", pEPD, pEPD->uiBurstGap);
  735. }
  736. else
  737. {
  738. pEPD->uiBurstGap = pEPD->uiBurstGap*2;
  739. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p), burst gap doubled to %d ms", pEPD, pEPD->uiBurstGap);
  740. }
  741. pEPD->uiBurstGap = _MIN(pEPD->uiBurstGap, pEPD->pSPD->pPData->dwSendRetryIntervalLimit/2);
  742. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p), burst gap is now %d ms", pEPD, pEPD->uiBurstGap);
  743. }
  744. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) THROTTLE WINDOW from %d frames", pEPD, pEPD->uiWindowF);
  745. pEPD->uiWindowF = _MAX((UINT)(pEPD->uiWindowF * pEPD->pSPD->pPData->fThrottleRate), 1); // be sure window remains > 0.
  746. pEPD->uiWindowBIndex = _MAX((UINT)(pEPD->uiWindowBIndex * pEPD->pSPD->pPData->fThrottleRate), 1);
  747. pEPD->uiWindowB = pEPD->uiWindowBIndex * pEPD->pSPD->uiFrameLength;
  748. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) THROTTLE WINDOW to %d frames", pEPD, pEPD->uiWindowF);
  749. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) THROTTLE ENGAGED (%d): Backoff to Window=%d; Gap=%d", pEPD, pEPD->uiThrottleEvents, pEPD->uiWindowF, pEPD->uiBurstGap);
  750. if(pEPD->uiThrottleEvents > THROTTLE_EVENT_THRESHOLD)
  751. {
  752. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) ** DETECT TRANSMIT CEILING ** Reducing 'good' speed and marking link STABLE", pEPD);
  753. // We have already reduced our current transmit rates. Here we will reduce the "good" rates that
  754. // we will restore to when we clear the throttled state.
  755. pEPD->uiThrottleEvents = 0;
  756. pEPD->uiRestoreWindowF = _MAX((pEPD->uiRestoreWindowF - 1), 1);
  757. pEPD->uiRestoreWindowBI = _MAX((pEPD->uiRestoreWindowBI - 1), 1);
  758. if (pEPD->uiRestoreBurstGap)
  759. {
  760. UINT t;
  761. t=pEPD->uiRestoreBurstGap;
  762. pEPD->uiRestoreBurstGap = (t+1) + (t >> 2); // 1.25*pEPD->uiRestoreBurstGap
  763. }
  764. DPFX(DPFPREP,DPF_ADAPTIVE_LVL, "(%p) New Restore Values: Window=%d; Gap=%d", pEPD, pEPD->uiRestoreWindowF, pEPD->uiRestoreBurstGap);
  765. pEPD->ulEPFlags |= EPFLAGS_LINK_STABLE;
  766. pEPD->ulEPFlags &= ~(EPFLAGS_TESTING_GROWTH);
  767. }
  768. }
  769. /*
  770. ** EPD Pool Support Routines
  771. **
  772. ** These are the functions called by Fixed Pool Manager as it handles EPDs.
  773. */
  774. // Allocate is called when a new EPD is first created
  775. #define pELEMENT ((PEPD) pElement)
  776. #undef DPF_MODNAME
  777. #define DPF_MODNAME "EPD_Allocate"
  778. BOOL EPD_Allocate(PVOID pElement, PVOID pvContext)
  779. {
  780. DPFX(DPFPREP,7, "(%p) Allocating new EPD", pELEMENT);
  781. pELEMENT->blHighPriSendQ.Initialize(); // Can you beleive there are SIX send queues per Endpoint?
  782. pELEMENT->blNormPriSendQ.Initialize(); // Six send queues.
  783. pELEMENT->blLowPriSendQ.Initialize(); // Well, it beats sorting the sends into the queues upon submission.
  784. pELEMENT->blCompleteSendList.Initialize();
  785. pELEMENT->blSendWindow.Initialize();
  786. pELEMENT->blRetryQueue.Initialize();
  787. pELEMENT->blCompleteList.Initialize();
  788. pELEMENT->blOddFrameList.Initialize();
  789. pELEMENT->blChkPtQueue.Initialize();
  790. pELEMENT->blSPLinkage.Initialize();
  791. pELEMENT->blActiveLinkage.Initialize();
  792. if (DNInitializeCriticalSection(&pELEMENT->EPLock) == FALSE)
  793. {
  794. DPFX(DPFPREP, 0, "Failed to initialize endpoint CS");
  795. return FALSE;
  796. }
  797. DebugSetCriticalSectionRecursionCount(&pELEMENT->EPLock, 0);
  798. DebugSetCriticalSectionGroup(&pELEMENT->EPLock, &g_blProtocolCritSecsHeld);
  799. pELEMENT->Sign = EPD_SIGN;
  800. pELEMENT->pCurrentSend = NULL;
  801. pELEMENT->pCurrentFrame = NULL;
  802. pELEMENT->pCommand = NULL;
  803. pELEMENT->RetryTimer = 0;
  804. pELEMENT->LinkTimer = 0;
  805. pELEMENT->DelayedAckTimer = 0;
  806. pELEMENT->ulEPFlags = 0; // EPFLAGS_STATE_CLEAR - make this line show up in state searches
  807. pELEMENT->ulEPFlags2 = 0;
  808. return TRUE;
  809. }
  810. // Get is called each time an EPD is used
  811. #undef DPF_MODNAME
  812. #define DPF_MODNAME "EPD_Get"
  813. VOID EPD_Get(PVOID pElement, PVOID pvContext)
  814. {
  815. DPFX(DPFPREP,DPF_EP_REFCNT_FINAL_LVL, "CREATING EPD %p", pELEMENT);
  816. // NOTE: First sizeof(PVOID) bytes will have been overwritten by the pool code,
  817. // we must set them to acceptable values.
  818. pELEMENT->hEndPt = INVALID_HANDLE_VALUE;
  819. pELEMENT->lRefCnt = 0; // We are -1 based, so place the first reference on the endpoint
  820. pELEMENT->pNewMessage = NULL;
  821. pELEMENT->pNewTail = NULL;
  822. ASSERT_EPD(pELEMENT);
  823. }
  824. #undef DPF_MODNAME
  825. #define DPF_MODNAME "EPD_Release"
  826. VOID EPD_Release(PVOID pElement)
  827. {
  828. PCHKPT pCP;
  829. ASSERT_EPD(pELEMENT);
  830. DPFX(DPFPREP,DPF_EP_REFCNT_FINAL_LVL, "RELEASING EPD %p", pELEMENT);
  831. ASSERT((pELEMENT->ulEPFlags & EPFLAGS_LINKED_TO_LISTEN)==0);
  832. // Clear any checkpoints still waiting on EP
  833. while(!pELEMENT->blChkPtQueue.IsEmpty())
  834. {
  835. pCP = CONTAINING_OBJECT(pELEMENT->blChkPtQueue.GetNext(), CHKPT, blLinkage);
  836. pCP->blLinkage.RemoveFromList();
  837. ChkPtPool.Release(pCP);
  838. }
  839. // These lists should be empty before End Point is released...
  840. ASSERT(pELEMENT->blOddFrameList.IsEmpty());
  841. ASSERT(pELEMENT->blCompleteList.IsEmpty());
  842. ASSERT(pELEMENT->blHighPriSendQ.IsEmpty());
  843. ASSERT(pELEMENT->blNormPriSendQ.IsEmpty());
  844. ASSERT(pELEMENT->blLowPriSendQ.IsEmpty());
  845. ASSERT(pELEMENT->blCompleteSendList.IsEmpty());
  846. ASSERT(pELEMENT->blSendWindow.IsEmpty());
  847. ASSERT(pELEMENT->blRetryQueue.IsEmpty());
  848. ASSERT(pELEMENT->blActiveLinkage.IsEmpty());
  849. ASSERT(pELEMENT->blSPLinkage.IsEmpty());
  850. ASSERT(pELEMENT->blChkPtQueue.IsEmpty());
  851. ASSERT(pELEMENT->pCurrentSend == NULL);
  852. ASSERT(pELEMENT->pCurrentFrame == NULL);
  853. pELEMENT->ulEPFlags = 0; // EPFLAGS_STATE_CLEAR - make this line show up in state searches
  854. pELEMENT->ulEPFlags2 = 0;
  855. pELEMENT->pCommand = NULL;
  856. pELEMENT->Context = NULL;
  857. pELEMENT->hEndPt = INVALID_HANDLE_VALUE;
  858. }
  859. #undef DPF_MODNAME
  860. #define DPF_MODNAME "EPD_Free"
  861. VOID EPD_Free(PVOID pElement)
  862. {
  863. DNDeleteCriticalSection(&pELEMENT->EPLock);
  864. }
  865. #undef ELEMENT