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.

401 lines
9.9 KiB

  1. ////////////////////////////////////////////////////////////
  2. //
  3. // buffer.c
  4. //
  5. // this modularizes some of the circular buffer functionality
  6. //
  7. /////////////////////////////////////////////////////////////
  8. #include "windows.h"
  9. #include "assert.h"
  10. #include "tapi.h"
  11. #include "tspi.h"
  12. #include "utils.h"
  13. #include "..\client\client.h"
  14. #include "buffer.h"
  15. #define INVAL_KEY ((DWORD) 'LVNI')
  16. #if DBG
  17. extern BOOL gbBreakOnLeak;
  18. #define ServerAlloc( __size__ ) ServerAllocReal( __size__, __LINE__, __FILE__ )
  19. LPVOID
  20. WINAPI
  21. ServerAllocReal(
  22. DWORD dwSize,
  23. DWORD dwLine,
  24. PSTR pszFile
  25. );
  26. void
  27. MyRealAssert(
  28. DWORD dwLine,
  29. PSTR pszFile
  30. );
  31. #define MyAssert( __exp__ ) { if ( !(__exp__) ) MyRealAssert (__LINE__, __FILE__); }
  32. #else
  33. #define ServerAlloc( __size__ ) ServerAllocReal( __size__ )
  34. LPVOID
  35. WINAPI
  36. ServerAllocReal(
  37. DWORD dwSize
  38. );
  39. #define MyAssert( __exp__ )
  40. #endif
  41. VOID
  42. WINAPI
  43. ServerFree(
  44. LPVOID lp
  45. );
  46. ///////////////////////////////////////////////////////////////////////////////
  47. //
  48. // PeekAsyncEventMsgFromQueue - peeks an ASYNCEVENTMSG from a circular buffer.
  49. // Places the next messge in the queue into the *ppMsg passed in. pdwID
  50. // is used for multiple calls to this function, to save the place in the
  51. // buffer. On the first call to this function, *pdwID must be 0.
  52. //
  53. // If the buffer needs to be critical sectioned, it is up to the calling
  54. // procedure to do that.
  55. //
  56. // PARAMETERS
  57. // pBufferInfo
  58. // [in] pointer to bufferinfo structure. this does not get modified
  59. // since we are just doing a peek message here.
  60. // ppCurrent
  61. // [in, out] pointer to the location in the buffer
  62. // where the last message was retrieved. When this function
  63. // is first called, *ppCurrent MUST be 0. *ppCurrent is filled in
  64. // if this function is successful. *ppCurrent can be passed to
  65. // subsequent calls to this function to retreive subsequent
  66. // messages. ppCurrent may not be NULL.
  67. // ppMsg
  68. // [in, out] pointer to pointer to ASYNCEVENTMSG. Preallocated - size
  69. // is in *pdwMsgSize. May be realloced if message is too big.
  70. // Uses ServerAlloc and ServerFree.
  71. // pdwMsgSize
  72. // [in, out] pointer to size of ppMsg. Can be modified if ppMsg is realloced.
  73. //
  74. //
  75. // RETURNS
  76. // TRUE if a message is copied to the buffer
  77. //
  78. // FALSE if a message is not copied to the buffer.
  79. //
  80. ////////////////////////////////////////////////////////////////////////////////////
  81. BOOL
  82. PeekAsyncEventMsgFromQueue(
  83. PBUFFERINFO pBufferInfo,
  84. PBYTE *ppCurrent,
  85. PASYNCEVENTMSG *ppMsg,
  86. DWORD *pdwMsgSize
  87. )
  88. {
  89. DWORD dwBytesToEnd;
  90. DWORD dwMoveSize, dwMoveSizeWrapped;
  91. PBYTE pBufferEnd, pStart;
  92. PASYNCEVENTMSG pMsg;
  93. LOG((TL_TRACE, "Entering PeekAsyncEventMsgFromQueue"));
  94. MyAssert (ppCurrent);
  95. do_it:
  96. if (*ppCurrent)
  97. {
  98. pStart = *ppCurrent;
  99. }
  100. else
  101. {
  102. pStart = pBufferInfo->pDataOut;
  103. }
  104. pMsg = *ppMsg;
  105. pBufferEnd = pBufferInfo->pBuffer + pBufferInfo->dwTotalSize;
  106. MyAssert(pStart < pBufferEnd);
  107. MyAssert(pStart >= pBufferInfo->pBuffer);
  108. MyAssert(*pdwMsgSize >= sizeof(ASYNCEVENTMSG));
  109. MyAssert(*ppMsg != NULL);
  110. if (pBufferInfo->dwUsedSize == 0)
  111. {
  112. LOG((TL_INFO, "GetAsyncEventMsg: dwUsedSize == 0"));
  113. return FALSE;
  114. }
  115. if ((pStart == pBufferInfo->pDataIn) ||
  116. ((pStart == pBufferInfo->pBuffer) &&
  117. (pBufferInfo->pDataIn == pBufferEnd)))
  118. {
  119. // gone through the whole buffer
  120. LOG((TL_TRACE, "PeekAsyncEventMsg: Gone through whole buffer"));
  121. return FALSE;
  122. }
  123. // Copy the fixed portion of the msg to the local buf
  124. // dwBytesToEnd is the number of bytes between the start
  125. // of copying and the end of the buffer
  126. dwBytesToEnd = pBufferEnd - pStart;
  127. // if dwBytesToEnd is greater than the fixed portion of
  128. // ASYNCEVENTMSG, just copy it
  129. // otherwise, the message wraps, so figure out where
  130. // it wraps.
  131. if (dwBytesToEnd >= sizeof (ASYNCEVENTMSG))
  132. {
  133. dwMoveSize = sizeof (ASYNCEVENTMSG);
  134. dwMoveSizeWrapped = 0;
  135. }
  136. else
  137. {
  138. dwMoveSize = dwBytesToEnd;
  139. dwMoveSizeWrapped = sizeof (ASYNCEVENTMSG) - dwBytesToEnd;
  140. }
  141. CopyMemory (pMsg, pStart, dwMoveSize);
  142. pStart += dwMoveSize;
  143. if (dwMoveSizeWrapped)
  144. {
  145. CopyMemory(
  146. ((LPBYTE) pMsg) + dwMoveSize,
  147. pBufferInfo->pBuffer,
  148. dwMoveSizeWrapped
  149. );
  150. pStart = pBufferInfo->pBuffer + dwMoveSizeWrapped;
  151. }
  152. // See if there's any extra data in this msg
  153. if (pMsg->dwTotalSize > sizeof (ASYNCEVENTMSG))
  154. {
  155. BOOL bCopy = TRUE;
  156. LOG((TL_INFO, "GetAsyncEventMessage: Message > ASYNCEVENTMSG"));
  157. // See if we need to grow the msg buffer
  158. if (pMsg->dwTotalSize > *pdwMsgSize)
  159. {
  160. DWORD dwNewMsgSize = pMsg->dwTotalSize + 256;
  161. if ((pMsg = ServerAlloc (dwNewMsgSize)))
  162. {
  163. CopyMemory(
  164. pMsg,
  165. *ppMsg,
  166. sizeof(ASYNCEVENTMSG)
  167. );
  168. ServerFree (*ppMsg);
  169. *ppMsg = pMsg;
  170. *pdwMsgSize = dwNewMsgSize;
  171. }
  172. else
  173. {
  174. return FALSE;
  175. }
  176. }
  177. // pStart has been moved to the end of the fixed portion
  178. // of the message.
  179. // dwBytesToEnd is the number of bytes between pStart and
  180. // the end of the buffer.
  181. dwBytesToEnd = pBufferEnd - pStart;
  182. // if dwBytesToEnd is greater than the size that we need
  183. // to copy...
  184. // otherwise, the copying wraps.
  185. if (dwBytesToEnd >= (pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG)))
  186. {
  187. dwMoveSize = pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG);
  188. dwMoveSizeWrapped = 0;
  189. }
  190. else
  191. {
  192. dwMoveSize = dwBytesToEnd;
  193. dwMoveSizeWrapped = (pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG)) -
  194. dwBytesToEnd;
  195. }
  196. CopyMemory (pMsg + 1, pStart, dwMoveSize);
  197. pStart += dwMoveSize;
  198. if (dwMoveSizeWrapped)
  199. {
  200. CopyMemory(
  201. ((LPBYTE) (pMsg + 1)) + dwMoveSize,
  202. pBufferInfo->pBuffer,
  203. dwMoveSizeWrapped
  204. );
  205. pStart = pBufferInfo->pBuffer + dwMoveSizeWrapped;
  206. }
  207. }
  208. *ppCurrent = pStart;
  209. // check to see if it is wrapping
  210. if (*ppCurrent >= pBufferEnd)
  211. {
  212. *ppCurrent = pBufferInfo->pBuffer;
  213. }
  214. if (pMsg->dwMsg == INVAL_KEY)
  215. {
  216. goto do_it;
  217. }
  218. return TRUE;
  219. }
  220. void
  221. RemoveAsyncEventMsgFromQueue(
  222. PBUFFERINFO pBufferInfo,
  223. PASYNCEVENTMSG pMsg,
  224. PBYTE *ppCurrent
  225. )
  226. /*++
  227. Removes a message retrieved by PeekAsyncEventMsgFromQueue.
  228. Basically, this function simply fixes up the pointers in the
  229. pBufferInfo structure to remove the message.
  230. --*/
  231. {
  232. DWORD dwMsgSize;
  233. LPBYTE pBuffer = pBufferInfo->pBuffer;
  234. LPBYTE pBufferEnd = pBuffer + pBufferInfo->dwTotalSize;
  235. PASYNCEVENTMSG pMsgInBuf, pMsgXxx;
  236. dwMsgSize = pMsg->dwTotalSize;
  237. pMsgInBuf = (PASYNCEVENTMSG) ((*ppCurrent - dwMsgSize) >= pBuffer ?
  238. *ppCurrent - dwMsgSize :
  239. *ppCurrent + pBufferInfo->dwTotalSize - dwMsgSize
  240. );
  241. if ((LPBYTE) pMsgInBuf == pBufferInfo->pDataOut)
  242. {
  243. //
  244. // This is the oldest msg in the ring buffer so we can easily
  245. // remove it. Then we'll loop checking each next message in the
  246. // queue & deleting those which have been invalidated, only
  247. // breaking out of the loop when there's no more msgs or we find
  248. // a msg that's not been invalidated.
  249. //
  250. do
  251. {
  252. if ((((LPBYTE) pMsgInBuf) + dwMsgSize) < pBufferEnd)
  253. {
  254. pBufferInfo->pDataOut = ((LPBYTE) pMsgInBuf) + dwMsgSize;
  255. }
  256. else
  257. {
  258. pBufferInfo->pDataOut = pBuffer +
  259. ((((LPBYTE) pMsgInBuf) + dwMsgSize) - pBufferEnd);
  260. }
  261. if ((pBufferInfo->dwUsedSize -= dwMsgSize) == 0)
  262. {
  263. break;
  264. }
  265. pMsgInBuf = (PASYNCEVENTMSG) pBufferInfo->pDataOut;
  266. if ((LPBYTE) &pMsgInBuf->dwMsg <=
  267. (pBufferEnd - sizeof (pMsgInBuf->dwMsg)))
  268. {
  269. if (pMsgInBuf->dwMsg != INVAL_KEY)
  270. {
  271. break;
  272. }
  273. }
  274. else
  275. {
  276. pMsgXxx = (PASYNCEVENTMSG)
  277. (pBuffer - (pBufferEnd - ((LPBYTE) pMsgInBuf)));
  278. if (pMsgXxx->dwMsg != INVAL_KEY)
  279. {
  280. break;
  281. }
  282. }
  283. dwMsgSize = pMsgInBuf->dwTotalSize;
  284. } while (1);
  285. }
  286. else
  287. {
  288. //
  289. // Msg is not the oldest in the ring buffer, so mark it as invalid
  290. // and it'll get cleaned up later
  291. //
  292. if ((LPBYTE) &pMsgInBuf->dwMsg <=
  293. (pBufferEnd - sizeof (pMsgInBuf->dwMsg)))
  294. {
  295. pMsgInBuf->dwMsg = INVAL_KEY;
  296. }
  297. else
  298. {
  299. pMsgXxx = (PASYNCEVENTMSG)
  300. (pBuffer - (pBufferEnd - ((LPBYTE) pMsgInBuf)));
  301. pMsgXxx->dwMsg = INVAL_KEY;
  302. }
  303. }
  304. }
  305. #if DBG
  306. void
  307. MyRealAssert(
  308. DWORD dwLine,
  309. PSTR pszFile
  310. )
  311. {
  312. LOG((TL_ERROR, "Assert in %s at line # %d", pszFile, dwLine));
  313. if (gbBreakOnLeak)
  314. {
  315. DebugBreak();
  316. }
  317. }
  318. #endif