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

/****************************** Module Header ******************************\
* Module Name: async.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* This module implements asynchronous I/O on file handles in a more
* useful way than provided for by Win32 apis.
*
* This module provides 2 main apis : ReadFileAsync, WriteFileAsync.
* These apis take a handle to an async object and always return
* immediately without waiting for the I/O to complete. An event
* can be queried from the async object and used to wait for completion.
* When this event is signalled, the I/O result can be queried from
* the async object.
*
* History:
* 06-29-92 Davidc Created.
\***************************************************************************/
#include <nt.h>
#include <ntrtl.h>
#include <windef.h>
#include <nturtl.h>
#include <winbase.h>
#include "rcmdsrv.h"
//
// Define RCOVERLAPPED structure
//
typedef struct {
OVERLAPPED Overlapped;
HANDLE FileHandle; // Non-null when I/O operation in progress.
DWORD CompletionCode;
DWORD BytesTransferred;
BOOL CompletedSynchronously;
} RCOVERLAPPED, *PRCOVERLAPPED;
/////////////////////////////////////////////////////////////////////////////
//
// CreateAsync
//
// Creates an async object.
// The async event is created with the initial state specified. If this
// is TRUE the async object created simulates a successfully completed
// transfer of 0 bytes.
//
// Returns handle on success, NULL on failure. GetLastError() for details.
//
// The object should be deleted by calling DeleteAsync.
//
/////////////////////////////////////////////////////////////////////////////
HANDLE
CreateAsync(
BOOL InitialState
)
{
SECURITY_ATTRIBUTES SecurityAttributes;
PRCOVERLAPPED RcOverlapped;
SecurityAttributes.nLength = sizeof(SecurityAttributes);
SecurityAttributes.lpSecurityDescriptor = NULL; // Use default ACL
SecurityAttributes.bInheritHandle = FALSE; // No inheritance
//
// Allocate space for the async structure
//
RcOverlapped = (PRCOVERLAPPED)Alloc(sizeof(RCOVERLAPPED));
if (RcOverlapped == NULL) {
RcDbgPrint("CreateAsync : Failed to allocate space for async object\n");
return(NULL);
}
//
// Create the synchronisation event
//
RcOverlapped->Overlapped.hEvent = CreateEvent( &SecurityAttributes,
TRUE, // Manual-reset
InitialState,
NULL); // Name
if (RcOverlapped->Overlapped.hEvent == NULL) {
RcDbgPrint("CreateAsync failed to create event, error = %d\n", GetLastError());
Free(RcOverlapped);
return(NULL);
}
//
// Initialize other fields.
// (Set FileHandle non-NULL to keep GetAsyncResult happy)
//
RcOverlapped->FileHandle = InitialState ? (HANDLE)1 : NULL;
RcOverlapped->BytesTransferred = 0;
RcOverlapped->CompletionCode = ERROR_SUCCESS;
RcOverlapped->CompletedSynchronously = TRUE;
return((HANDLE)RcOverlapped);
}
/////////////////////////////////////////////////////////////////////////////
//
// DeleteAsync
//
// Deletes resources used by async object
//
// Returns nothing
//
/////////////////////////////////////////////////////////////////////////////
VOID
DeleteAsync(
HANDLE AsyncHandle
)
{
PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
DWORD BytesTransferred;
//
// Wait for operation if in progress
//
if (GetAsyncResult(AsyncHandle, &BytesTransferred) == ERROR_IO_INCOMPLETE) {
if (WaitForSingleObject(
GetAsyncCompletionHandle(AsyncHandle),
5000) != WAIT_OBJECT_0 ) {
RcDbgPrint("Async object rundown wait failed, error %d\n",
GetLastError());
}
}
RcCloseHandle(RcOverlapped->Overlapped.hEvent, "async overlapped event");
Free(RcOverlapped);
return;
}
/////////////////////////////////////////////////////////////////////////////
//
// ReadFileAsync
//
// Reads from file asynchronously.
//
// Returns TRUE on success, FALSE on failure (GetLastError() for detail)
//
// Caller should wait on async event for operation to complete, then call
// GetAsyncResult to retrieve information on transfer.
//
/////////////////////////////////////////////////////////////////////////////
BOOL
ReadFileAsync(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nBytesToRead,
HANDLE AsyncHandle
)
{
BOOL Result;
DWORD Error;
PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
//
// Check an IO operation is not in progress
//
if (RcOverlapped->FileHandle != NULL) {
RcDbgPrint("ReadFileAsync : Operation already in progress!\n");
SetLastError(ERROR_IO_PENDING);
return(FALSE);
}
//
// Reset the event
//
Result = ResetEvent(RcOverlapped->Overlapped.hEvent);
if (!Result) {
RcDbgPrint("ReadFileAsync : Failed to reset async event, error = %d\n", GetLastError());
return(FALSE);
}
//
// Store the file handle in our structure.
// This also functions as a signal that an operation is in progress.
//
RcOverlapped->FileHandle = hFile;
RcOverlapped->CompletedSynchronously = FALSE;
Result = ReadFile(hFile,
lpBuffer,
nBytesToRead,
&RcOverlapped->BytesTransferred,
&RcOverlapped->Overlapped);
if (!Result) {
Error = GetLastError();
if (Error == ERROR_IO_PENDING) {
//
// The I/O has been started synchronously, we're done
//
return(TRUE);
}
//
// The read really did fail, reset our flag and get out
//
RcDbgPrint("ReadFileAsync : ReadFile failed, error = %d\n", Error);
RcOverlapped->FileHandle = NULL;
return(FALSE);
}
//
// The operation completed synchronously. Store the paramaters in our
// structure ready for GetAsyncResult and signal the event
//
RcOverlapped->CompletionCode = ERROR_SUCCESS;
RcOverlapped->CompletedSynchronously = TRUE;
//
// Set the event
//
Result = SetEvent(RcOverlapped->Overlapped.hEvent);
if (!Result) {
RcDbgPrint("ReadFileAsync : Failed to set async event, error = %d\n", GetLastError());
}
return(TRUE);
}
/////////////////////////////////////////////////////////////////////////////
//
// WriteFileAsync
//
// Writes to file asynchronously.
//
// Returns TRUE on success, FALSE on failure (GetLastError() for detail)
//
// Caller should wait on async event for operation to complete, then call
// GetAsyncResult to retrieve information on transfer.
//
/////////////////////////////////////////////////////////////////////////////
BOOL
WriteFileAsync(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nBytesToWrite,
HANDLE AsyncHandle
)
{
BOOL Result;
DWORD Error;
PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
//
// Check an IO operation is not in progress
//
if (RcOverlapped->FileHandle != NULL) {
RcDbgPrint("ReadFileAsync : Operation already in progress!\n");
SetLastError(ERROR_IO_PENDING);
return(FALSE);
}
//
// Reset the event
//
Result = ResetEvent(RcOverlapped->Overlapped.hEvent);
if (!Result) {
RcDbgPrint("WriteFileAsync : Failed to reset async event, error = %d\n", GetLastError());
return(FALSE);
}
//
// Store the file handle in our structure.
// This also functions as a signal that an operation is in progress.
//
RcOverlapped->FileHandle = hFile;
RcOverlapped->CompletedSynchronously = FALSE;
Result = WriteFile(hFile,
lpBuffer,
nBytesToWrite,
&RcOverlapped->BytesTransferred,
&RcOverlapped->Overlapped);
if (!Result) {
Error = GetLastError();
if (Error == ERROR_IO_PENDING) {
//
// The I/O has been started synchronously, we're done
//
return(TRUE);
}
//
// The read really did fail, reset our flag and get out
//
RcDbgPrint("WriteFileAsync : WriteFile failed, error = %d\n", Error);
RcOverlapped->FileHandle = NULL;
return(FALSE);
}
//
// The operation completed synchronously. Store the paramaters in our
// structure ready for GetAsyncResult and signal the event
//
RcOverlapped->CompletionCode = ERROR_SUCCESS;
RcOverlapped->CompletedSynchronously = TRUE;
//
// Set the event
//
Result = SetEvent(RcOverlapped->Overlapped.hEvent);
if (!Result) {
RcDbgPrint("WriteFileAsync : Failed to set async event, error = %d\n", GetLastError());
}
return(TRUE);
}
/////////////////////////////////////////////////////////////////////////////
//
// GetCompletionHandle
//
// Returns a handle that can be used to wait for completion of the
// operation associated with this async object
//
// Returns an event handle or NULL on failure
//
/////////////////////////////////////////////////////////////////////////////
HANDLE
GetAsyncCompletionHandle(
HANDLE AsyncHandle
)
{
PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
return(RcOverlapped->Overlapped.hEvent);
}
/////////////////////////////////////////////////////////////////////////////
//
// GetAsyncResult
//
// Returns the result of the last completed operation involving the
// passed async object handle.
//
// Returns the completion code of the last operation OR
// ERROR_IO_INCOMPLETE if the operation has not completed.
// ERROR_NO_DATA if there is no operation in progress.
//
/////////////////////////////////////////////////////////////////////////////
DWORD
GetAsyncResult(
HANDLE AsyncHandle,
LPDWORD BytesTransferred
)
{
BOOL Result;
DWORD WaitResult;
PRCOVERLAPPED RcOverlapped = (PRCOVERLAPPED)AsyncHandle;
DWORD AsyncResult;
//
// Check an IO operation is (was) in progress
//
if (RcOverlapped->FileHandle == NULL) {
RcDbgPrint("GetAsyncResult : No operation in progress !\n");
return(ERROR_NO_DATA);
}
//
// Check the event is set - i.e that an IO operation has completed
//
WaitResult = WaitForSingleObject(RcOverlapped->Overlapped.hEvent, 0);
if (WaitResult != 0) {
RcDbgPrint("GetAsyncResult : Event was not set, wait result = %d\n", WaitResult);
return(ERROR_IO_INCOMPLETE);
}
//
// If the call completed synchronously, copy the data out of
// our structure
//
if (RcOverlapped->CompletedSynchronously) {
AsyncResult = RcOverlapped->CompletionCode;
*BytesTransferred = RcOverlapped->BytesTransferred;
} else {
//
// Go get the asynchronous result info from the system
//
AsyncResult = ERROR_SUCCESS;
Result = GetOverlappedResult(RcOverlapped->FileHandle,
&RcOverlapped->Overlapped,
BytesTransferred,
FALSE);
if (!Result) {
AsyncResult = GetLastError();
RcDbgPrint("GetAsyncResult : GetOverlappedResult failed, error = %d\n", AsyncResult);
}
}
//
// Reset the event so it doesn't trigger the caller again
//
Result = ResetEvent(RcOverlapped->Overlapped.hEvent);
if (!Result) {
RcDbgPrint("GetAsyncResult : Failed to reset async event\n");
}
//
// Result the file handle so we know there is no pending operation
//
RcOverlapped->FileHandle = NULL;
return(AsyncResult);
}