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.

485 lines
11 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: async.c
  3. *
  4. * Copyright (c) 1991, Microsoft Corporation
  5. *
  6. * This module implements asynchronous I/O on file handles in a more
  7. * useful way than provided for by Win32 apis.
  8. *
  9. * This module provides 2 main apis : ReadFileAsync, WriteFileAsync.
  10. * These apis take a handle to an async object and always return
  11. * immediately without waiting for the I/O to complete. An event
  12. * can be queried from the async object and used to wait for completion.
  13. * When this event is signalled, the I/O result can be queried from
  14. * the async object.
  15. *
  16. * History:
  17. * 06-29-92 Davidc Created.
  18. \***************************************************************************/
  19. #include <nt.h>
  20. #include <ntrtl.h>
  21. #include <windef.h>
  22. #include <nturtl.h>
  23. #include <winbase.h>
  24. #include "rcmdsrv.h"
  25. //
  26. // Define RCOVERLAPPED structure
  27. //
  28. typedef struct {
  29. OVERLAPPED Overlapped;
  30. HANDLE FileHandle; // Non-null when I/O operation in progress.
  31. DWORD CompletionCode;
  32. DWORD BytesTransferred;
  33. BOOL CompletedSynchronously;
  34. } RCOVERLAPPED, *PRCOVERLAPPED;
  35. /////////////////////////////////////////////////////////////////////////////
  36. //
  37. // CreateAsync
  38. //
  39. // Creates an async object.
  40. // The async event is created with the initial state specified. If this
  41. // is TRUE the async object created simulates a successfully completed
  42. // transfer of 0 bytes.
  43. //
  44. // Returns handle on success, NULL on failure. GetLastError() for details.
  45. //
  46. // The object should be deleted by calling DeleteAsync.
  47. //
  48. /////////////////////////////////////////////////////////////////////////////
  49. HANDLE
  50. CreateAsync(
  51. BOOL InitialState
  52. )
  53. {
  54. SECURITY_ATTRIBUTES SecurityAttributes;
  55. PRCOVERLAPPED RcOverlapped;
  56. SecurityAttributes.nLength = sizeof(SecurityAttributes);
  57. SecurityAttributes.lpSecurityDescriptor = NULL; // Use default ACL
  58. SecurityAttributes.bInheritHandle = FALSE; // No inheritance
  59. //
  60. // Allocate space for the async structure
  61. //
  62. RcOverlapped = (PRCOVERLAPPED)Alloc(sizeof(RCOVERLAPPED));
  63. if (RcOverlapped == NULL) {
  64. RcDbgPrint("CreateAsync : Failed to allocate space for async object\n");
  65. return(NULL);
  66. }
  67. //
  68. // Create the synchronisation event
  69. //
  70. RcOverlapped->Overlapped.hEvent = CreateEvent( &SecurityAttributes,
  71. TRUE, // Manual-reset
  72. InitialState,
  73. NULL); // Name
  74. if (RcOverlapped->Overlapped.hEvent == NULL) {
  75. RcDbgPrint("CreateAsync failed to create event, error = %d\n", GetLastError());
  76. Free(RcOverlapped);
  77. return(NULL);
  78. }
  79. //
  80. // Initialize other fields.
  81. // (Set FileHandle non-NULL to keep GetAsyncResult happy)
  82. //
  83. RcOverlapped->FileHandle = InitialState ? (HANDLE)1 : NULL;
  84. RcOverlapped->BytesTransferred = 0;
  85. RcOverlapped->CompletionCode = ERROR_SUCCESS;
  86. RcOverlapped->CompletedSynchronously = TRUE;
  87. return((HANDLE)RcOverlapped);
  88. }
  89. /////////////////////////////////////////////////////////////////////////////
  90. //
  91. // DeleteAsync
  92. //
  93. // Deletes resources used by async object
  94. //
  95. // Returns nothing
  96. //
  97. /////////////////////////////////////////////////////////////////////////////
  98. VOID
  99. DeleteAsync(
  100. HANDLE AsyncHandle
  101. )
  102. {
  103. PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
  104. DWORD BytesTransferred;
  105. //
  106. // Wait for operation if in progress
  107. //
  108. if (GetAsyncResult(AsyncHandle, &BytesTransferred) == ERROR_IO_INCOMPLETE) {
  109. if (WaitForSingleObject(
  110. GetAsyncCompletionHandle(AsyncHandle),
  111. 5000) != WAIT_OBJECT_0 ) {
  112. RcDbgPrint("Async object rundown wait failed, error %d\n",
  113. GetLastError());
  114. }
  115. }
  116. RcCloseHandle(RcOverlapped->Overlapped.hEvent, "async overlapped event");
  117. Free(RcOverlapped);
  118. return;
  119. }
  120. /////////////////////////////////////////////////////////////////////////////
  121. //
  122. // ReadFileAsync
  123. //
  124. // Reads from file asynchronously.
  125. //
  126. // Returns TRUE on success, FALSE on failure (GetLastError() for detail)
  127. //
  128. // Caller should wait on async event for operation to complete, then call
  129. // GetAsyncResult to retrieve information on transfer.
  130. //
  131. /////////////////////////////////////////////////////////////////////////////
  132. BOOL
  133. ReadFileAsync(
  134. HANDLE hFile,
  135. LPVOID lpBuffer,
  136. DWORD nBytesToRead,
  137. HANDLE AsyncHandle
  138. )
  139. {
  140. BOOL Result;
  141. DWORD Error;
  142. PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
  143. //
  144. // Check an IO operation is not in progress
  145. //
  146. if (RcOverlapped->FileHandle != NULL) {
  147. RcDbgPrint("ReadFileAsync : Operation already in progress!\n");
  148. SetLastError(ERROR_IO_PENDING);
  149. return(FALSE);
  150. }
  151. //
  152. // Reset the event
  153. //
  154. Result = ResetEvent(RcOverlapped->Overlapped.hEvent);
  155. if (!Result) {
  156. RcDbgPrint("ReadFileAsync : Failed to reset async event, error = %d\n", GetLastError());
  157. return(FALSE);
  158. }
  159. //
  160. // Store the file handle in our structure.
  161. // This also functions as a signal that an operation is in progress.
  162. //
  163. RcOverlapped->FileHandle = hFile;
  164. RcOverlapped->CompletedSynchronously = FALSE;
  165. Result = ReadFile(hFile,
  166. lpBuffer,
  167. nBytesToRead,
  168. &RcOverlapped->BytesTransferred,
  169. &RcOverlapped->Overlapped);
  170. if (!Result) {
  171. Error = GetLastError();
  172. if (Error == ERROR_IO_PENDING) {
  173. //
  174. // The I/O has been started synchronously, we're done
  175. //
  176. return(TRUE);
  177. }
  178. //
  179. // The read really did fail, reset our flag and get out
  180. //
  181. RcDbgPrint("ReadFileAsync : ReadFile failed, error = %d\n", Error);
  182. RcOverlapped->FileHandle = NULL;
  183. return(FALSE);
  184. }
  185. //
  186. // The operation completed synchronously. Store the paramaters in our
  187. // structure ready for GetAsyncResult and signal the event
  188. //
  189. RcOverlapped->CompletionCode = ERROR_SUCCESS;
  190. RcOverlapped->CompletedSynchronously = TRUE;
  191. //
  192. // Set the event
  193. //
  194. Result = SetEvent(RcOverlapped->Overlapped.hEvent);
  195. if (!Result) {
  196. RcDbgPrint("ReadFileAsync : Failed to set async event, error = %d\n", GetLastError());
  197. }
  198. return(TRUE);
  199. }
  200. /////////////////////////////////////////////////////////////////////////////
  201. //
  202. // WriteFileAsync
  203. //
  204. // Writes to file asynchronously.
  205. //
  206. // Returns TRUE on success, FALSE on failure (GetLastError() for detail)
  207. //
  208. // Caller should wait on async event for operation to complete, then call
  209. // GetAsyncResult to retrieve information on transfer.
  210. //
  211. /////////////////////////////////////////////////////////////////////////////
  212. BOOL
  213. WriteFileAsync(
  214. HANDLE hFile,
  215. LPVOID lpBuffer,
  216. DWORD nBytesToWrite,
  217. HANDLE AsyncHandle
  218. )
  219. {
  220. BOOL Result;
  221. DWORD Error;
  222. PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
  223. //
  224. // Check an IO operation is not in progress
  225. //
  226. if (RcOverlapped->FileHandle != NULL) {
  227. RcDbgPrint("ReadFileAsync : Operation already in progress!\n");
  228. SetLastError(ERROR_IO_PENDING);
  229. return(FALSE);
  230. }
  231. //
  232. // Reset the event
  233. //
  234. Result = ResetEvent(RcOverlapped->Overlapped.hEvent);
  235. if (!Result) {
  236. RcDbgPrint("WriteFileAsync : Failed to reset async event, error = %d\n", GetLastError());
  237. return(FALSE);
  238. }
  239. //
  240. // Store the file handle in our structure.
  241. // This also functions as a signal that an operation is in progress.
  242. //
  243. RcOverlapped->FileHandle = hFile;
  244. RcOverlapped->CompletedSynchronously = FALSE;
  245. Result = WriteFile(hFile,
  246. lpBuffer,
  247. nBytesToWrite,
  248. &RcOverlapped->BytesTransferred,
  249. &RcOverlapped->Overlapped);
  250. if (!Result) {
  251. Error = GetLastError();
  252. if (Error == ERROR_IO_PENDING) {
  253. //
  254. // The I/O has been started synchronously, we're done
  255. //
  256. return(TRUE);
  257. }
  258. //
  259. // The read really did fail, reset our flag and get out
  260. //
  261. RcDbgPrint("WriteFileAsync : WriteFile failed, error = %d\n", Error);
  262. RcOverlapped->FileHandle = NULL;
  263. return(FALSE);
  264. }
  265. //
  266. // The operation completed synchronously. Store the paramaters in our
  267. // structure ready for GetAsyncResult and signal the event
  268. //
  269. RcOverlapped->CompletionCode = ERROR_SUCCESS;
  270. RcOverlapped->CompletedSynchronously = TRUE;
  271. //
  272. // Set the event
  273. //
  274. Result = SetEvent(RcOverlapped->Overlapped.hEvent);
  275. if (!Result) {
  276. RcDbgPrint("WriteFileAsync : Failed to set async event, error = %d\n", GetLastError());
  277. }
  278. return(TRUE);
  279. }
  280. /////////////////////////////////////////////////////////////////////////////
  281. //
  282. // GetCompletionHandle
  283. //
  284. // Returns a handle that can be used to wait for completion of the
  285. // operation associated with this async object
  286. //
  287. // Returns an event handle or NULL on failure
  288. //
  289. /////////////////////////////////////////////////////////////////////////////
  290. HANDLE
  291. GetAsyncCompletionHandle(
  292. HANDLE AsyncHandle
  293. )
  294. {
  295. PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
  296. return(RcOverlapped->Overlapped.hEvent);
  297. }
  298. /////////////////////////////////////////////////////////////////////////////
  299. //
  300. // GetAsyncResult
  301. //
  302. // Returns the result of the last completed operation involving the
  303. // passed async object handle.
  304. //
  305. // Returns the completion code of the last operation OR
  306. // ERROR_IO_INCOMPLETE if the operation has not completed.
  307. // ERROR_NO_DATA if there is no operation in progress.
  308. //
  309. /////////////////////////////////////////////////////////////////////////////
  310. DWORD
  311. GetAsyncResult(
  312. HANDLE AsyncHandle,
  313. LPDWORD BytesTransferred
  314. )
  315. {
  316. BOOL Result;
  317. DWORD WaitResult;
  318. PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
  319. DWORD AsyncResult;
  320. //
  321. // Check an IO operation is (was) in progress
  322. //
  323. if (RcOverlapped->FileHandle == NULL) {
  324. RcDbgPrint("GetAsyncResult : No operation in progress !\n");
  325. return(ERROR_NO_DATA);
  326. }
  327. //
  328. // Check the event is set - i.e that an IO operation has completed
  329. //
  330. WaitResult = WaitForSingleObject(RcOverlapped->Overlapped.hEvent, 0);
  331. if (WaitResult != 0) {
  332. RcDbgPrint("GetAsyncResult : Event was not set, wait result = %d\n", WaitResult);
  333. return(ERROR_IO_INCOMPLETE);
  334. }
  335. //
  336. // If the call completed synchronously, copy the data out of
  337. // our structure
  338. //
  339. if (RcOverlapped->CompletedSynchronously) {
  340. AsyncResult = RcOverlapped->CompletionCode;
  341. *BytesTransferred = RcOverlapped->BytesTransferred;
  342. } else {
  343. //
  344. // Go get the asynchronous result info from the system
  345. //
  346. AsyncResult = ERROR_SUCCESS;
  347. Result = GetOverlappedResult(RcOverlapped->FileHandle,
  348. &RcOverlapped->Overlapped,
  349. BytesTransferred,
  350. FALSE);
  351. if (!Result) {
  352. AsyncResult = GetLastError();
  353. RcDbgPrint("GetAsyncResult : GetOverlappedResult failed, error = %d\n", AsyncResult);
  354. }
  355. }
  356. //
  357. // Reset the event so it doesn't trigger the caller again
  358. //
  359. Result = ResetEvent(RcOverlapped->Overlapped.hEvent);
  360. if (!Result) {
  361. RcDbgPrint("GetAsyncResult : Failed to reset async event\n");
  362. }
  363. //
  364. // Result the file handle so we know there is no pending operation
  365. //
  366. RcOverlapped->FileHandle = NULL;
  367. return(AsyncResult);
  368. }