Windows NT 4.0 source code leak
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.

340 lines
7.8 KiB

4 years ago
  1. /*****************************************************************************
  2. * *
  3. * CSTREAM.CPP *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1990-1995 *
  6. * All Rights reserved. *
  7. * *
  8. *****************************************************************************/
  9. #include "stdafx.h"
  10. #include "cstream.h"
  11. #ifdef _DEBUG
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. #ifdef _DEBUG
  16. static LONG hsemReadCount;
  17. static LONG hsemStartCount;
  18. #define PTR_SEM_READ_COUNT &hsemReadCount
  19. #define PTR_SEM_START_COUNT &hsemStartCount
  20. #else
  21. #define PTR_SEM_READ_COUNT NULL
  22. #define PTR_SEM_START_COUNT NULL
  23. #endif
  24. static HANDLE hsemRead; // semaphore used for dual-cpu processing
  25. static HANDLE hsemStart; // semaphore used for dual-cpu processing
  26. static CStream *pThis;
  27. static BOOL fReadAheadStarted;
  28. static BOOL fExitThread;
  29. static PBYTE pbuf1; // first buffer for dual-cpu processing
  30. static PBYTE pbuf2; // second buffer for dual-cpu processing
  31. /////////////////////// CStream implementation ////////////////////////////
  32. // We use our own stream class instead of using the C runtime, because this
  33. // change alone doubled the speed of the help compiler. I.e., the C runtime
  34. // implementation of stream io is horribly slow. 26-Feb-1994 [ralphw]
  35. CStream::CStream(PCSTR pszFileName)
  36. {
  37. // _fDualCPU = FALSE;
  38. // Only one CStream can use the read-ahead thread
  39. if (!pThis) {
  40. fDualCPU = _fDualCPU;
  41. pThis = this;
  42. }
  43. else
  44. fDualCPU = FALSE;
  45. if ((hfile = _lopen(pszFileName, OF_READ)) == HFILE_ERROR) {
  46. VReportError(HCERR_CANNOT_OPEN, &errHpj, pszFileName);
  47. fInitialized = FALSE;
  48. return;
  49. }
  50. if (fDualCPU) {
  51. cbBuf = DUAL_INPUT_BUF_SIZE;
  52. if (!hsemRead) {
  53. hsemRead = CreateSemaphore(NULL, 1, 1, NULL);
  54. hsemStart = CreateSemaphore(NULL, 1, 1, NULL);
  55. pbuf2 = (PBYTE) lcMalloc(DUAL_INPUT_BUF_SIZE + 1);
  56. pbuf1 = (PBYTE) lcMalloc(DUAL_INPUT_BUF_SIZE + 1);
  57. }
  58. pbuf = pbuf1;
  59. }
  60. else {
  61. cbBuf = INPUT_BUF_SIZE;
  62. pbuf = (PBYTE) lcMalloc(INPUT_BUF_SIZE + 1);
  63. }
  64. ConfirmOrDie(pbuf);
  65. fInitialized = TRUE;
  66. int cread = _lread(hfile, pbuf, cbBuf);
  67. if (cread == HFILE_ERROR) {
  68. _lclose(hfile);
  69. VReportError(HCERR_CANT_READ, &errHpj, pszFileName);
  70. fInitialized = FALSE;
  71. return;
  72. }
  73. if (fDualCPU) {
  74. // Start reading the next buffer
  75. cThrdRead = HFILE_NOTREAD;
  76. if (!fReadAheadStarted) {
  77. hthrd = CreateThread(NULL, 0,
  78. (LPTHREAD_START_ROUTINE) &ReadAhead, NULL,
  79. 0, &idThrd);
  80. ConfirmOrDie(hthrd);
  81. fReadAheadStarted = TRUE;
  82. }
  83. else {
  84. ReleaseSemaphore(hsemRead, 1, PTR_SEM_READ_COUNT);
  85. ReleaseSemaphore(hsemStart, 1, PTR_SEM_START_COUNT); // start read-ahead thread
  86. }
  87. }
  88. pCurBuf = pbuf;
  89. pEndBuf = pbuf + cread;
  90. pEndBuf[1] = '\0';
  91. lFilePos = cread;
  92. lFileBuf = 0;
  93. pszFile = lcStrDup(pszFileName);
  94. fInitialized = TRUE;
  95. }
  96. CStream::~CStream()
  97. {
  98. if (fInitialized) {
  99. if (fDualCPU) {
  100. WaitForReadAhead();
  101. }
  102. else
  103. lcFree(pbuf);
  104. lcFree(pszFile);
  105. _lclose(hfile);
  106. }
  107. pThis = NULL;
  108. }
  109. /***************************************************************************
  110. FUNCTION: CStream::ReadBuf
  111. PURPOSE: Read the next block into buffer
  112. PARAMETERS:
  113. void
  114. RETURNS:
  115. COMMENTS:
  116. Zero-terminates the buffer
  117. MODIFICATION DATES:
  118. 13-Nov-1994 [ralphw]
  119. ***************************************************************************/
  120. char CStream::ReadBuf(void)
  121. {
  122. int cread;
  123. if (fDualCPU) {
  124. ASSERT(fReadAheadStarted);
  125. WaitForReadAhead();
  126. if (pbuf == pbuf1)
  127. pbuf = pbuf2;
  128. else
  129. pbuf = pbuf1;
  130. cread = cThrdRead;
  131. cThrdRead = HFILE_NOTREAD;
  132. ReleaseSemaphore(hsemRead, 1, PTR_SEM_READ_COUNT);
  133. // Error-checking must occur AFTER we release the read semaphore
  134. if (cread == HFILE_ERROR) {
  135. VReportError(HCERR_READ_FAILURE, &errHpj, pszFile);
  136. return chEOF;
  137. }
  138. ReleaseSemaphore(hsemStart, 1, PTR_SEM_START_COUNT); // start read-ahead thread
  139. }
  140. else {
  141. cread = _lread(hfile, pbuf, cbBuf);
  142. if (cread == HFILE_ERROR) {
  143. VReportError(HCERR_READ_FAILURE, &errHpj, pszFile);
  144. return chEOF;
  145. }
  146. }
  147. lFileBuf = lFilePos;
  148. lFilePos += cread;
  149. pCurBuf = pbuf;
  150. pEndBuf = pbuf + cread;
  151. pEndBuf[1] = '\0';
  152. return (char) *pCurBuf++;
  153. }
  154. BOOL STDCALL CStream::read(LPBYTE pbDest, int cbBytes)
  155. {
  156. while (cbBytes--)
  157. *pbDest++ = (BYTE) cget();
  158. return (pbDest[-1] == chEOF) ? FALSE : TRUE;
  159. }
  160. int STDCALL CStream::seek(int pos, SEEK_TYPE seek)
  161. {
  162. ConfirmOrDie(seek != SK_END); // we don't support this one
  163. if (seek == SK_CUR)
  164. pos = lFileBuf + (pCurBuf - pbuf) + pos;
  165. if (pos >= lFileBuf && pos < lFilePos) {
  166. pCurBuf = pbuf + (pos - lFileBuf);
  167. return lFileBuf + (pCurBuf - pbuf);
  168. }
  169. else {
  170. if (fDualCPU) {
  171. WaitForReadAhead();
  172. }
  173. lFileBuf = _llseek(hfile, pos, SEEK_SET);
  174. int cread = _lread(hfile, pbuf, cbBuf);
  175. if (cread == HFILE_ERROR) {
  176. VReportError(HCERR_READ_FAILURE, &errHpj, pszFile);
  177. return chEOF;
  178. }
  179. lFilePos = lFileBuf + cread;
  180. pCurBuf = pbuf;
  181. pEndBuf = pbuf + cread;
  182. if (fDualCPU) {
  183. cThrdRead = HFILE_NOTREAD;
  184. ReleaseSemaphore(hsemRead, 1, PTR_SEM_READ_COUNT);
  185. if (fReadAheadStarted)
  186. ReleaseSemaphore(hsemStart, 1, PTR_SEM_START_COUNT); // start read-ahead thread
  187. }
  188. return lFilePos;
  189. }
  190. }
  191. void CStream::WaitForReadAhead(void)
  192. {
  193. for(;;) {
  194. WaitForSingleObject(hsemRead, INFINITE);
  195. if (cThrdRead == HFILE_NOTREAD) {
  196. ReleaseSemaphore(hsemRead, 1, PTR_SEM_READ_COUNT);
  197. Sleep(1); // give read-ahead thread a chance to run
  198. }
  199. else
  200. return;
  201. }
  202. }
  203. /***************************************************************************
  204. FUNCTION: ReadAhead
  205. PURPOSE: Reads the next block of data from a file
  206. PARAMETERS:
  207. pthis
  208. RETURNS:
  209. COMMENTS:
  210. Two semaphores control this thread:
  211. hsemStart: keeps the thread suspended while waiting for the
  212. caller to finish reading one of its blocks.
  213. hsemRead: used as a signal between the main thread and this
  214. thread as to when this thread has completed.
  215. Because it is theoretically possible for a thread switch to occur
  216. between the time the hsemStart thread starts this thread and this
  217. thread's call to WaitForSingleObject(hsemRead), the caller also sets
  218. the read return value to HFILE_NOTREAD to ensure that it does not
  219. attempt to use this buffer until in fact the read has completed.
  220. NOTE: this thread approach only makes sense on a system with more
  221. then one CPU.
  222. MODIFICATION DATES:
  223. 05-Feb-1995 [ralphw]
  224. ***************************************************************************/
  225. DWORD WINAPI ReadAhead(LPVOID pv)
  226. {
  227. /*
  228. * Each time through the loop, we block on hsemStart, waiting for our
  229. * caller to release it. The hsemRead is used to block the caller until
  230. * we have completed our read.
  231. */
  232. for (;;) {
  233. PBYTE pbReadBuf;
  234. WaitForSingleObject(hsemStart, INFINITE);
  235. if (fExitThread)
  236. break;
  237. WaitForSingleObject(hsemRead, INFINITE);
  238. pbReadBuf = (pThis->pbuf == pbuf1) ? pbuf2 : pbuf1;
  239. pThis->cThrdRead = _lread(pThis->hfile, pbReadBuf, pThis->cbBuf);
  240. ReleaseSemaphore(hsemRead, 1, PTR_SEM_READ_COUNT);
  241. }
  242. ExitThread(0);
  243. return 0;
  244. }
  245. /***************************************************************************
  246. FUNCTION: CStream::Cleanup
  247. PURPOSE: Cleanup global variables
  248. PARAMETERS:
  249. void
  250. RETURNS:
  251. COMMENTS:
  252. MODIFICATION DATES:
  253. 05-Feb-1995 [ralphw]
  254. ***************************************************************************/
  255. void CStream::Cleanup(void)
  256. {
  257. if (fReadAheadStarted) {
  258. fExitThread = TRUE;
  259. ReleaseSemaphore(hsemStart, 1, PTR_SEM_START_COUNT); // start read-ahead thread
  260. Sleep(1); // Let the other thread run
  261. CloseHandle(hsemStart);
  262. CloseHandle(hsemRead);
  263. lcFree(pbuf1);
  264. lcFree(pbuf2);
  265. hsemStart = hsemRead = pbuf1 = pbuf2 = NULL;
  266. }
  267. }
  268. #ifdef _DEBUG
  269. char CStream::cget() {
  270. if (pCurBuf < pEndBuf)
  271. return (char) *pCurBuf++;
  272. else if (pEndBuf < pbuf + cbBuf)
  273. return chEOF;
  274. else
  275. return ReadBuf();
  276. }
  277. #endif