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.

667 lines
20 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1998-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Send.cpp
  6. * Content: This file contains code which implements the front end of the
  7. * SendData API. It also contains code to Get and Release Message
  8. * Descriptors (MSD) with the FPM package.
  9. *
  10. * History:
  11. * Date By Reason
  12. * ==== == ======
  13. * 11/06/98 ejs Created
  14. * 07/01/2000 masonb Assumed Ownership
  15. *
  16. ****************************************************************************/
  17. #include "dnproti.h"
  18. /*
  19. ** Direct Net Protocol -- Send Data
  20. **
  21. ** Data is always address to a PlayerID, which is represented internally
  22. ** by an End Point Descriptor (EPD).
  23. **
  24. ** Data can be sent reliably or unreliably using the same API with the appropriate
  25. ** class of service flag set.
  26. **
  27. ** Sends are never delivered directly to the SP because there will always be
  28. ** a possibility that the thread might block. So to guarentee immediate return
  29. ** we will always queue the packet and submit it on our dedicated sending thread.
  30. */
  31. #if (DN_SENDFLAGS_SET_USER_FLAG - PACKET_COMMAND_USER_1)
  32. This will not compile. Flags must be equal
  33. #endif
  34. #if (DN_SENDFLAGS_SET_USER_FLAG_TWO - PACKET_COMMAND_USER_2)
  35. This will not compile. Flags must be equal
  36. #endif
  37. // locals
  38. VOID SendDatagram(PMSD, PEPD);
  39. VOID SendReliable(PMSD, PEPD);
  40. #undef DPF_MODNAME
  41. #define DPF_MODNAME "PROTOCOL"
  42. /*
  43. ** Send Data
  44. **
  45. ** This routine will initiate a data transfer with the specified endpoint. It will
  46. ** normally start the operation and then return immediately, returning a handle used to
  47. ** indicate completion of the operation at a later time.
  48. */
  49. #undef DPF_MODNAME
  50. #define DPF_MODNAME "DNPSendData"
  51. HRESULT
  52. DNPSendData(HANDLE hProtocolData, HANDLE hDestination, UINT uiBufferCount, PBUFFERDESC pBufferDesc, UINT uiTimeout, ULONG ulFlags, VOID* pvContext, HANDLE* phSendHandle)
  53. {
  54. HRESULT hr;
  55. ProtocolData* pPData;
  56. PEPD pEPD;
  57. PMSD pMSD;
  58. PFMD pFMD;
  59. UINT i;
  60. UINT Length = 0;
  61. PSPD pSPD;
  62. ULONG ulFrameFlags;
  63. BYTE bCommand;
  64. // Following variables are used for mapping buffers to frames
  65. PBUFFERDESC FromBuffer, ToBuffer;
  66. UINT TotalRemain, FromRemain, ToRemain, size;
  67. PCHAR FromPtr;
  68. #ifdef DBG
  69. INT FromBufferCount;
  70. #endif // DBG
  71. // End of variables for mapping frames
  72. #ifndef DPNBUILD_NOMULTICAST
  73. BOOL fMulticastSend;
  74. #endif // !DPNBUILD_NOMULTICAST
  75. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hDestination[%x], uiBufferCount[%x], pBufferDesc[%p], uiTimeout[%x], ulFlags[%x], pvContext[%p], phSendHandle[%p]", hProtocolData, hDestination, uiBufferCount, pBufferDesc, uiTimeout, ulFlags, pvContext, phSendHandle);
  76. hr = DPNERR_PENDING;
  77. pPData = (ProtocolData*)hProtocolData;
  78. ASSERT_PPD(pPData);
  79. pEPD = (PEPD) hDestination;
  80. ASSERT_EPD(pEPD);
  81. // Unified Send Processing -- Do this for all classes of service
  82. // We will do all of the work to build up the frames and create the send command before we check
  83. // the state of the EPD, that way we don't have to have complicated code to handle an endpoint that
  84. // goes away between the top and bottom of this function and we don't have to hold the EPDLock while
  85. // we do all of the buffer manipulation.
  86. // Hold a reference throughout the operation so we don't have to deal with the EPD going away.
  87. LOCK_EPD(pEPD, "LOCK (SEND)");
  88. // Count the bytes in all user buffers
  89. for(i=0; i < uiBufferCount; i++)
  90. {
  91. Length += pBufferDesc[i].dwBufferSize;
  92. }
  93. if (Length == 0)
  94. {
  95. DPFX(DPFPREP,0, "Attempt to send zero length packet, returning DPNERR_GENERIC");
  96. return DPNERR_GENERIC;
  97. }
  98. #ifndef DPNBUILD_NOMULTICAST
  99. fMulticastSend = pEPD->ulEPFlags2 & (EPFLAGS2_MULTICAST_SEND|EPFLAGS2_MULTICAST_RECEIVE);
  100. if (fMulticastSend && Length > pEPD->uiUserFrameLength)
  101. {
  102. DPFX(DPFPREP,0, "Multicast send too large to fit in one frame, returning DPNERR_SENDTOOLARGE");
  103. Lock(&pEPD->EPLock);
  104. RELEASE_EPD(pEPD, "UNLOCK (SEND)");
  105. return DPNERR_SENDTOOLARGE;
  106. }
  107. #endif // !DPNBUILD_NOMULTICAST
  108. // Allocate and fill out a Message Descriptor for this operation
  109. if((pMSD = (PMSD)POOLALLOC(MEMID_SEND_MSD, &MSDPool)) == NULL)
  110. {
  111. DPFX(DPFPREP,0, "Failed to allocate MSD, returning DPNERR_OUTOFMEMORY");
  112. Lock(&pEPD->EPLock);
  113. RELEASE_EPD(pEPD, "UNLOCK (SEND)");
  114. hr = DPNERR_OUTOFMEMORY;
  115. goto Exit;
  116. }
  117. // Copy SendData parameters into the Message Descriptor
  118. pMSD->ulSendFlags = ulFlags; // Store the actual flags passed into the API call
  119. pMSD->Context = pvContext;
  120. pMSD->iMsgLength = Length;
  121. pMSD->uiFrameCount = (Length + pEPD->uiUserFrameLength - 1) / pEPD->uiUserFrameLength; // round up
  122. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Initialize Frame count, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  123. #ifndef DPNBUILD_NOMULTICAST
  124. ASSERT(!fMulticastSend || pMSD->uiFrameCount == 1);
  125. #endif // !DPNBUILD_NOMULTICAST
  126. if(ulFlags & DN_SENDFLAGS_RELIABLE)
  127. {
  128. #ifndef DPNBUILD_NOMULTICAST
  129. ASSERT(!fMulticastSend);
  130. #endif // !DPNBUILD_NOMULTICAST
  131. pMSD->CommandID = COMMAND_ID_SEND_RELIABLE;
  132. ulFrameFlags = FFLAGS_RELIABLE;
  133. bCommand = PACKET_COMMAND_DATA | PACKET_COMMAND_RELIABLE;
  134. }
  135. else
  136. {
  137. pMSD->CommandID = COMMAND_ID_SEND_DATAGRAM;
  138. ulFrameFlags = 0;
  139. bCommand = PACKET_COMMAND_DATA;
  140. }
  141. if(!(ulFlags & DN_SENDFLAGS_COALESCE))
  142. {
  143. #ifdef DPNBUILD_COALESCEALWAYS
  144. DPFX(DPFPREP,7, "(%p) Attempting to coalesce send despite missing flag.", pEPD);
  145. #else // ! DPNBUILD_COALESCEALWAYS
  146. ulFrameFlags |= FFLAGS_DONT_COALESCE;
  147. #endif // ! DPNBUILD_COALESCEALWAYS
  148. }
  149. if(!(ulFlags & DN_SENDFLAGS_NON_SEQUENTIAL))
  150. {
  151. #ifndef DPNBUILD_NOMULTICAST
  152. ASSERT(!fMulticastSend);
  153. #endif // !DPNBUILD_NOMULTICAST
  154. bCommand |= PACKET_COMMAND_SEQUENTIAL;
  155. }
  156. bCommand |= (ulFlags & (DN_SENDFLAGS_SET_USER_FLAG | DN_SENDFLAGS_SET_USER_FLAG_TWO)); // preserve user flag values
  157. // Map user buffers directly into frame's buffer descriptors
  158. //
  159. // We will loop through each required frame, filling out buffer descriptors
  160. // from those provided as parameters. Frames may span user buffers or vice-versa...
  161. TotalRemain = Length;
  162. #ifdef DBG
  163. FromBufferCount = uiBufferCount - 1; // sanity check
  164. #endif // DBG
  165. FromBuffer = pBufferDesc;
  166. FromRemain = FromBuffer->dwBufferSize;
  167. FromPtr = reinterpret_cast<PCHAR>( (FromBuffer++)->pBufferData ); // note post-increment to next descriptor
  168. for(i=0; i<pMSD->uiFrameCount; i++)
  169. {
  170. ASSERT(TotalRemain > 0);
  171. // Grab a new frame
  172. if((pFMD = (PFMD)POOLALLOC(MEMID_SEND_FMD, &FMDPool)) == NULL)
  173. {
  174. // MSD_Release will clean up any previous frames if this isn't the first.
  175. // Release MSD before EPD since final EPD will call out to SP and we don't want any locks held
  176. Lock(&pMSD->CommandLock);
  177. pMSD->uiFrameCount = 0; // reset to prevent assert in pool release function
  178. RELEASE_MSD(pMSD, "Base Ref"); // MSD Release operation will also free frames
  179. Lock(&pEPD->EPLock);
  180. RELEASE_EPD(pEPD, "UNLOCK (SEND)");
  181. DPFX(DPFPREP,0, "Failed to allocate FMD, returning DPNERR_OUTOFMEMORY");
  182. hr = DPNERR_OUTOFMEMORY;
  183. goto Exit;
  184. }
  185. pFMD->pMSD = pMSD; // Link frame back to message
  186. pFMD->pEPD = pEPD;
  187. pFMD->CommandID = pMSD->CommandID;
  188. pFMD->bPacketFlags = bCommand; // save packet flags for each frame
  189. pFMD->blMSDLinkage.InsertBefore( &pMSD->blFrameList);
  190. ToRemain = pEPD->uiUserFrameLength;
  191. ToBuffer = pFMD->rgBufferList; // Address first user buffer desc
  192. pFMD->uiFrameLength = pEPD->uiUserFrameLength; // Assume we fill frame- only need to change size of last one
  193. pFMD->ulFFlags = ulFrameFlags; // Set control flags for frame (Sequential, Reliable)
  194. // Until this frame is full
  195. while((ToRemain != 0) && (TotalRemain != 0) && (pFMD->SendDataBlock.dwBufferCount <= MAX_USER_BUFFERS_IN_FRAME))
  196. {
  197. size = _MIN(FromRemain, ToRemain); // choose smaller of framesize or buffersize
  198. FromRemain -= size;
  199. ToRemain -= size;
  200. TotalRemain -= size;
  201. ToBuffer->dwBufferSize = size; // Fill in the next frame descriptor
  202. (ToBuffer++)->pBufferData = reinterpret_cast<BYTE*>( FromPtr ); // note post-increment
  203. ASSERT(pFMD->SendDataBlock.dwBufferCount <= MAX_USER_BUFFERS_IN_FRAME); // remember we already have 1 immediate data buffer
  204. pFMD->SendDataBlock.dwBufferCount++; // Count buffers as we add them
  205. // Get next user buffer
  206. if((FromRemain == 0) && (TotalRemain != 0))
  207. {
  208. FromRemain = FromBuffer->dwBufferSize;
  209. FromPtr = reinterpret_cast<PCHAR>( (FromBuffer++)->pBufferData ); // note post-increment to next descriptor
  210. #ifdef DBG
  211. FromBufferCount--; // Keep this code honest...
  212. ASSERT(FromBufferCount >= 0);
  213. #endif // DBG
  214. }
  215. else
  216. { // Either filled this frame, or have mapped the whole send
  217. FromPtr += size; // advance ptr to start next frame (if any)
  218. pFMD->uiFrameLength = pEPD->uiUserFrameLength - ToRemain; // wont be full at end of message
  219. }
  220. } // While (frame not full)
  221. } // For (each frame in message)
  222. pFMD->ulFFlags |= FFLAGS_END_OF_MESSAGE; // Mark last frame with EOM
  223. pFMD->bPacketFlags |= PACKET_COMMAND_END_MSG; // Set EOM in frame
  224. #ifdef DBG
  225. ASSERT(FromBufferCount == 0);
  226. ASSERT(TotalRemain == 0);
  227. #endif // DBG
  228. Lock(&pMSD->CommandLock);
  229. Lock(&pEPD->EPLock);
  230. // Don't allow sends if we are not connected or if a disconnect has been initiated
  231. if( ((pEPD->ulEPFlags & (EPFLAGS_END_POINT_IN_USE | EPFLAGS_STATE_CONNECTED)) !=
  232. (EPFLAGS_END_POINT_IN_USE | EPFLAGS_STATE_CONNECTED))
  233. || (pEPD->ulEPFlags & (EPFLAGS_SENT_DISCONNECT | EPFLAGS_HARD_DISCONNECT_SOURCE)))
  234. {
  235. // Release MSD before EPD since final EPD will call out to SP and we don't want any locks held
  236. pMSD->uiFrameCount = 0;
  237. RELEASE_MSD(pMSD, "Base Ref"); // MSD Release operation will also free frames, releases CommandLock
  238. RELEASE_EPD(pEPD, "UNLOCK (SEND)"); // Releases EPLock
  239. DPFX(DPFPREP,0, "(%p) Rejecting Send on invalid EPD, returning DPNERR_INVALIDENDPOINT", pEPD);
  240. hr = DPNERR_INVALIDENDPOINT;
  241. goto Exit;
  242. }
  243. pSPD = pEPD->pSPD;
  244. ASSERT_SPD(pSPD);
  245. pMSD->pSPD = pSPD;
  246. pMSD->pEPD = pEPD;
  247. // hang the message off a global command queue
  248. #ifdef DBG
  249. Lock(&pSPD->SPLock);
  250. pMSD->blSPLinkage.InsertBefore( &pSPD->blMessageList);
  251. pMSD->ulMsgFlags1 |= MFLAGS_ONE_ON_GLOBAL_LIST;
  252. Unlock(&pSPD->SPLock);
  253. #endif // DBG
  254. *phSendHandle = pMSD; // We will use the MSD as our handle.
  255. // Enqueue the message before setting the timeout
  256. EnqueueMessage(pMSD, pEPD);
  257. Unlock(&pEPD->EPLock);
  258. if(uiTimeout != 0)
  259. {
  260. LOCK_MSD(pMSD, "Send Timeout Timer"); // Add reference for timer
  261. DPFX(DPFPREP,7, "(%p) Setting Timeout Send Timer", pEPD);
  262. ScheduleProtocolTimer(pSPD, uiTimeout, 100, TimeoutSend, pMSD, &pMSD->TimeoutTimer, &pMSD->TimeoutTimerUnique);
  263. }
  264. Unlock(&pMSD->CommandLock);
  265. Exit:
  266. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  267. return hr;
  268. }
  269. /*
  270. ** Enqueue Message
  271. **
  272. ** Add complete MSD to the appropriate send queue, and kick start sending process if necessary.
  273. **
  274. ** ** This routine is called and returns with EPD->EPLOCK held **
  275. */
  276. #undef DPF_MODNAME
  277. #define DPF_MODNAME "EnqueueMessage"
  278. VOID
  279. EnqueueMessage(PMSD pMSD, PEPD pEPD)
  280. {
  281. PSPD pSPD = pEPD->pSPD;
  282. // Place Message in appriopriate priority queue. Datagrams get enqueued twice (!). They get put in the Master
  283. // queue where they are processed FIFO with all messages of the same priority. Datagrams also get placed in a priority
  284. // specific queue of only datagrams which is drawn from when the reliable stream is blocked.
  285. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  286. pEPD->uiQueuedMessageCount++;
  287. if(pMSD->ulSendFlags & DN_SENDFLAGS_HIGH_PRIORITY)
  288. {
  289. DPFX(DPFPREP,7, "(%p) Placing message on High Priority Q (total queued = %u)", pEPD, pEPD->uiQueuedMessageCount);
  290. pMSD->blQLinkage.InsertBefore( &pEPD->blHighPriSendQ);
  291. pEPD->uiMsgSentHigh++;
  292. }
  293. else if (pMSD->ulSendFlags & DN_SENDFLAGS_LOW_PRIORITY)
  294. {
  295. DPFX(DPFPREP,7, "(%p) Placing message on Low Priority Q (total queued = %u)", pEPD, pEPD->uiQueuedMessageCount);
  296. pMSD->blQLinkage.InsertBefore( &pEPD->blLowPriSendQ);
  297. pEPD->uiMsgSentLow++;
  298. }
  299. else
  300. {
  301. DPFX(DPFPREP,7, "(%p) Placing message on Normal Priority Q (total queued = %u)", pEPD, pEPD->uiQueuedMessageCount);
  302. pMSD->blQLinkage.InsertBefore( &pEPD->blNormPriSendQ);
  303. pEPD->uiMsgSentNorm++;
  304. }
  305. #ifdef DBG
  306. pMSD->ulMsgFlags2 |= MFLAGS_TWO_ENQUEUED;
  307. #endif // DBG
  308. pEPD->ulEPFlags |= EPFLAGS_SDATA_READY; // Note that there is *something* in one or more queues
  309. // If the session is not currently in the send pipeline then we will want to insert it here as long as the
  310. // the stream is not blocked.
  311. if(((pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE)==0) && (pEPD->ulEPFlags & EPFLAGS_STREAM_UNBLOCKED))
  312. {
  313. ASSERT(pEPD->SendTimer == NULL);
  314. DPFX(DPFPREP,7, "(%p) Send On Idle Link -- Returning to pipeline", pEPD);
  315. pEPD->ulEPFlags |= EPFLAGS_IN_PIPELINE;
  316. LOCK_EPD(pEPD, "LOCK (pipeline)"); // Add Ref for pipeline Q
  317. // We dont call send on users thread, but we dont have a dedicated send thread either. Use a thread
  318. // from the timer-worker pool to submit the sends to SP
  319. DPFX(DPFPREP,7, "(%p) Scheduling Send Thread", pEPD);
  320. ScheduleProtocolWork(pSPD, ScheduledSend, pEPD);
  321. }
  322. else if ((pEPD->ulEPFlags & EPFLAGS_IN_PIPELINE)==0)
  323. {
  324. DPFX(DPFPREP,7, "(%p) Declining to re-enter pipeline on blocked stream", pEPD);
  325. }
  326. else
  327. {
  328. DPFX(DPFPREP,7, "(%p) Already in pipeline", pEPD);
  329. }
  330. }
  331. #undef DPF_MODNAME
  332. #define DPF_MODNAME "TimeoutSend"
  333. VOID CALLBACK
  334. TimeoutSend(void * const pvUser, void * const uID, const UINT uMsg)
  335. {
  336. PMSD pMSD = (PMSD) pvUser;
  337. PEPD pEPD = pMSD->pEPD;
  338. DPFX(DPFPREP,7, "(%p) Timeout Send pMSD=%p, RefCnt=%d", pEPD, pMSD, pMSD->lRefCnt);
  339. Lock(&pMSD->CommandLock);
  340. if((pMSD->TimeoutTimer != uID)||(pMSD->TimeoutTimerUnique != uMsg))
  341. {
  342. DPFX(DPFPREP,7, "(%p) Ignoring late send timeout timer, pMSD[%p]", pEPD, pMSD);
  343. RELEASE_MSD(pMSD, "Timeout Timer"); // releases EPLock
  344. return;
  345. }
  346. pMSD->TimeoutTimer = NULL;
  347. if(pMSD->ulMsgFlags1 & (MFLAGS_ONE_CANCELLED | MFLAGS_ONE_TIMEDOUT))
  348. {
  349. DPFX(DPFPREP,7, "(%p) Timed out send has completed already pMSD=%p", pEPD, pMSD);
  350. RELEASE_MSD(pMSD, "Send Timout Timer"); // Releases CommandLock
  351. return;
  352. }
  353. pMSD->ulMsgFlags1 |= MFLAGS_ONE_TIMEDOUT;
  354. DPFX(DPFPREP,7, "(%p) Calling DoCancel to cancel pMSD=%p", pEPD, pMSD);
  355. if(DoCancel(pMSD, DPNERR_TIMEDOUT) == DPN_OK) // Releases CommandLock
  356. {
  357. ASSERT_EPD(pEPD);
  358. if(pMSD->ulSendFlags & DN_SENDFLAGS_HIGH_PRIORITY)
  359. {
  360. pEPD->uiMsgTOHigh++;
  361. }
  362. else if(pMSD->ulSendFlags & DN_SENDFLAGS_LOW_PRIORITY)
  363. {
  364. pEPD->uiMsgTOLow++;
  365. }
  366. else
  367. {
  368. pEPD->uiMsgTONorm++;
  369. }
  370. }
  371. else
  372. {
  373. DPFX(DPFPREP,7, "(%p) DoCancel did not succeed pMSD=%p", pEPD, pMSD);
  374. }
  375. Lock(&pMSD->CommandLock);
  376. RELEASE_MSD(pMSD, "Send Timout Timer"); // Release Ref for timer
  377. }
  378. /***********************
  379. ========SPACER==========
  380. ************************/
  381. /*
  382. ** MSD Pool support routines
  383. **
  384. ** These are the functions called by Fixed Pool Manager as it handles MSDs.
  385. */
  386. #define pELEMENT ((PMSD) pElement)
  387. #undef DPF_MODNAME
  388. #define DPF_MODNAME "MSD_Allocate"
  389. BOOL MSD_Allocate(PVOID pElement, PVOID pvContext)
  390. {
  391. DPFX(DPFPREP,7, "(%p) Allocating new MSD", pELEMENT);
  392. ZeroMemory(pELEMENT, sizeof(messagedesc));
  393. if (DNInitializeCriticalSection(&pELEMENT->CommandLock) == FALSE)
  394. {
  395. DPFX(DPFPREP,0, "Failed to initialize MSD CS");
  396. return FALSE;
  397. }
  398. DebugSetCriticalSectionRecursionCount(&pELEMENT->CommandLock,0);
  399. DebugSetCriticalSectionGroup(&pELEMENT->CommandLock, &g_blProtocolCritSecsHeld);
  400. pELEMENT->blFrameList.Initialize();
  401. pELEMENT->blQLinkage.Initialize();
  402. pELEMENT->blSPLinkage.Initialize();
  403. pELEMENT->Sign = MSD_SIGN;
  404. pELEMENT->lRefCnt = -1;
  405. // NOTE: pELEMENT->pEPD NULL'd by ZeroMemory above
  406. return TRUE;
  407. }
  408. // Get is called each time an MSD is used
  409. #undef DPF_MODNAME
  410. #define DPF_MODNAME "MSD_Get"
  411. VOID MSD_Get(PVOID pElement, PVOID pvContext)
  412. {
  413. DPFX(DPFPREP,DPF_REFCNT_FINAL_LVL, "CREATING MSD %p", pELEMENT);
  414. // NOTE: First sizeof(PVOID) bytes will have been overwritten by the pool code,
  415. // we must set them to acceptable values.
  416. pELEMENT->CommandID = COMMAND_ID_NONE;
  417. pELEMENT->ulMsgFlags1 = MFLAGS_ONE_IN_USE; // Dont need InUse flag since we have RefCnt
  418. pELEMENT->lRefCnt = 0; // One initial reference
  419. pELEMENT->hCommand = 0;
  420. ASSERT_MSD(pELEMENT);
  421. }
  422. /*
  423. ** MSD Release
  424. **
  425. ** This is called with the CommandLock held. The Lock should not be
  426. ** freed until the INUSE flag is cleared. This is to synchronize with
  427. ** last minute Cancel threads waiting on lock.
  428. **
  429. ** When freeing a message desc we will free all frame descriptors
  430. ** attached to it first.
  431. */
  432. #undef DPF_MODNAME
  433. #define DPF_MODNAME "MSD_Release"
  434. VOID MSD_Release(PVOID pElement)
  435. {
  436. CBilink *pLink;
  437. PFMD pFMD;
  438. #ifdef DBG
  439. ASSERT_MSD(pELEMENT);
  440. AssertCriticalSectionIsTakenByThisThread(&pELEMENT->CommandLock, TRUE);
  441. DPFX(DPFPREP,DPF_REFCNT_FINAL_LVL, "RELEASING MSD %p", pELEMENT);
  442. ASSERT(pELEMENT->ulMsgFlags1 & MFLAGS_ONE_IN_USE);
  443. ASSERT(pELEMENT->lRefCnt == -1);
  444. ASSERT((pELEMENT->ulMsgFlags1 & MFLAGS_ONE_ON_GLOBAL_LIST)==0);
  445. #endif // DBG
  446. while( (pLink = pELEMENT->blFrameList.GetNext()) != &pELEMENT->blFrameList)
  447. {
  448. pLink->RemoveFromList(); // remove from bilink
  449. pFMD = CONTAINING_OBJECT(pLink, FMD, blMSDLinkage);
  450. ASSERT_FMD(pFMD);
  451. RELEASE_FMD(pFMD, "MSD Frame List"); // If this is still submitted it will be referenced and wont be released here.
  452. }
  453. ASSERT(pELEMENT->blFrameList.IsEmpty());
  454. ASSERT(pELEMENT->blQLinkage.IsEmpty());
  455. ASSERT(pELEMENT->blSPLinkage.IsEmpty());
  456. ASSERT(pELEMENT->uiFrameCount == 0);
  457. pELEMENT->ulMsgFlags1 = 0;
  458. pELEMENT->ulMsgFlags2 = 0;
  459. ASSERT(pELEMENT->pEPD == NULL); // This should have gotten cleaned up before here.
  460. Unlock(&pELEMENT->CommandLock);
  461. }
  462. #undef DPF_MODNAME
  463. #define DPF_MODNAME "MSD_Free"
  464. VOID MSD_Free(PVOID pElement)
  465. {
  466. DNDeleteCriticalSection(&pELEMENT->CommandLock);
  467. }
  468. #undef pELEMENT
  469. /*
  470. ** FMD Pool support routines
  471. */
  472. #define pELEMENT ((PFMD) pElement)
  473. #undef DPF_MODNAME
  474. #define DPF_MODNAME "FMD_Allocate"
  475. BOOL FMD_Allocate(PVOID pElement, PVOID pvContext)
  476. {
  477. DPFX(DPFPREP,7, "(%p) Allocating new FMD", pELEMENT);
  478. pELEMENT->Sign = FMD_SIGN;
  479. pELEMENT->ulFFlags = 0;
  480. pELEMENT->lRefCnt = 0;
  481. pELEMENT->blMSDLinkage.Initialize();
  482. pELEMENT->blQLinkage.Initialize();
  483. pELEMENT->blWindowLinkage.Initialize();
  484. pELEMENT->blCoalesceLinkage.Initialize();
  485. pELEMENT->pCSD = NULL;
  486. return TRUE;
  487. }
  488. // Get is called each time an MSD is used
  489. //
  490. // Probably dont need to do this everytime, but some random SP might
  491. // munch the parameters someday and that could be bad if I dont...
  492. #undef DPF_MODNAME
  493. #define DPF_MODNAME "FMD_Get"
  494. VOID FMD_Get(PVOID pElement, PVOID pvContext)
  495. {
  496. DPFX(DPFPREP,DPF_REFCNT_FINAL_LVL, "CREATING FMD %p", pELEMENT);
  497. pELEMENT->CommandID = COMMAND_ID_NONE;
  498. pELEMENT->lpImmediatePointer = (LPVOID) pELEMENT->ImmediateData;
  499. pELEMENT->SendDataBlock.pBuffers = (PBUFFERDESC) &pELEMENT->uiImmediateLength;
  500. pELEMENT->SendDataBlock.dwBufferCount = 1; // always count one buffer for immediate data
  501. pELEMENT->SendDataBlock.dwFlags = 0;
  502. pELEMENT->SendDataBlock.pvContext = pElement;
  503. pELEMENT->SendDataBlock.hCommand = 0;
  504. pELEMENT->ulFFlags = 0;
  505. pELEMENT->bSubmitted = FALSE;
  506. pELEMENT->bPacketFlags = 0;
  507. pELEMENT->tAcked = -1;
  508. pELEMENT->lRefCnt = 1; // Assign first reference
  509. ASSERT_FMD(pELEMENT);
  510. }
  511. #undef DPF_MODNAME
  512. #define DPF_MODNAME "FMD_Release"
  513. VOID FMD_Release(PVOID pElement)
  514. {
  515. DPFX(DPFPREP,DPF_REFCNT_FINAL_LVL, "RELEASING FMD %p", pELEMENT);
  516. ASSERT_FMD(pELEMENT);
  517. ASSERT(pELEMENT->lRefCnt == 0);
  518. ASSERT(pELEMENT->bSubmitted == FALSE);
  519. pELEMENT->pMSD = NULL;
  520. ASSERT(pELEMENT->blMSDLinkage.IsEmpty());
  521. ASSERT(pELEMENT->blQLinkage.IsEmpty());
  522. ASSERT(pELEMENT->blWindowLinkage.IsEmpty());
  523. ASSERT(pELEMENT->blCoalesceLinkage.IsEmpty());
  524. ASSERT(pELEMENT->pCSD == NULL);
  525. }
  526. #undef DPF_MODNAME
  527. #define DPF_MODNAME "FMD_Free"
  528. VOID FMD_Free(PVOID pElement)
  529. {
  530. }
  531. #undef pELEMENT