340 lines
8.5 KiB
C
340 lines
8.5 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tfile.c
|
|
|
|
Abstract:
|
|
|
|
Test program for Win32 Base File API calls
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 26-Sep-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
|
|
#define xassert ASSERT
|
|
|
|
typedef struct _aio {
|
|
LIST_ENTRY Links;
|
|
HANDLE ReadHandle;
|
|
HANDLE WriteHandle;
|
|
LPVOID Buffer;
|
|
OVERLAPPED Overlapped;
|
|
} AIO, *PAIO;
|
|
|
|
HANDLE IoReadsDoneEvent;
|
|
HANDLE IoWritesDoneEvent;
|
|
HANDLE IoWorkerListLock;
|
|
HANDLE IoWorkerListSemaphore;
|
|
LIST_ENTRY IoRequestList;
|
|
ULONG IoCount;
|
|
ULONG IoReadCount;
|
|
ULONG IoWriteCount;
|
|
#define BSIZE 2048
|
|
|
|
|
|
VOID
|
|
WriteIoComplete(
|
|
DWORD dwErrorCode,
|
|
DWORD dwNumberOfBytesTransfered,
|
|
LPOVERLAPPED lpOverlapped
|
|
)
|
|
{
|
|
PAIO paio;
|
|
|
|
//
|
|
// If an I/O error occured, display the error and then exit
|
|
//
|
|
|
|
if ( dwErrorCode ) {
|
|
printf("FATAL I/O Error %ld I/O Context %lx.%lx\n",
|
|
dwErrorCode,
|
|
lpOverlapped,
|
|
lpOverlapped->hEvent
|
|
);
|
|
ExitProcess(dwErrorCode);
|
|
}
|
|
paio = (PAIO)CONTAINING_RECORD(lpOverlapped,AIO,Overlapped);
|
|
if ( InterlockedDecrement(&IoWriteCount) == 0 ) {
|
|
SetEvent(IoWritesDoneEvent);
|
|
}
|
|
LocalFree(paio->Buffer);
|
|
LocalFree(paio);
|
|
}
|
|
|
|
VOID
|
|
ReadIoComplete(
|
|
DWORD dwErrorCode,
|
|
DWORD dwNumberOfBytesTransfered,
|
|
LPOVERLAPPED lpOverlapped
|
|
)
|
|
{
|
|
PAIO paio;
|
|
BOOL IoOperationStatus;
|
|
|
|
//
|
|
// If an I/O error occured, display the error and then exit
|
|
//
|
|
|
|
if ( dwErrorCode ) {
|
|
printf("FATAL I/O Error %ld I/O Context %lx.%lx\n",
|
|
dwErrorCode,
|
|
lpOverlapped,
|
|
lpOverlapped->hEvent
|
|
);
|
|
ExitProcess(dwErrorCode);
|
|
}
|
|
paio = (PAIO)CONTAINING_RECORD(lpOverlapped,AIO,Overlapped);
|
|
//printf("%s",paio->Buffer);
|
|
|
|
IoOperationStatus = WriteFileEx(
|
|
paio->WriteHandle,
|
|
paio->Buffer,
|
|
dwNumberOfBytesTransfered,
|
|
&paio->Overlapped,
|
|
WriteIoComplete
|
|
);
|
|
|
|
//
|
|
// Test to see if I/O was queued successfully
|
|
//
|
|
|
|
if ( !IoOperationStatus ) {
|
|
if ( GetLastError() != ERROR_HANDLE_EOF ) {
|
|
printf("FATAL I/O Error %ld\n",
|
|
GetLastError()
|
|
);
|
|
ExitProcess(1);
|
|
}
|
|
}
|
|
|
|
if ( InterlockedDecrement(&IoReadCount) == 0 ) {
|
|
SetEvent(IoReadsDoneEvent);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
IoWorkerThread(
|
|
PVOID Unused
|
|
)
|
|
{
|
|
HANDLE HandleVector[2];
|
|
DWORD CompletionStatus;
|
|
PAIO paio;
|
|
BOOL IoOperationStatus;
|
|
|
|
HandleVector[0] = IoWorkerListLock;
|
|
HandleVector[1] = IoWorkerListSemaphore;
|
|
|
|
for(;;){
|
|
|
|
//
|
|
// Do an alertable wait on the handle vector. Both objects
|
|
// becoming signaled at the same time means there is an
|
|
// I/O request in the queue, and the caller has exclusive
|
|
// access to the queue
|
|
//
|
|
|
|
|
|
CompletionStatus = WaitForMultipleObjectsEx(
|
|
2,
|
|
HandleVector,
|
|
TRUE,
|
|
0xffffffff,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// If the wait failed, error out
|
|
//
|
|
|
|
if ( CompletionStatus == 0xffffffff ) {
|
|
printf("FATAL WAIT ERROR %ld\n",GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
|
|
//
|
|
// If an I/O completion occured, then wait for another
|
|
// I/O request or I/O completion
|
|
//
|
|
|
|
if ( CompletionStatus != WAIT_IO_COMPLETION ) {
|
|
|
|
//
|
|
// Wait was satisfied. We now have exclusive ownership of the
|
|
// I/O request queue, and there is something on the queue.
|
|
// Note that to insert something on the queue, the inserter
|
|
// gets the list lock (mutex), inserts an entry, signals the
|
|
// list semaphore, and finally releases the list lock
|
|
//
|
|
|
|
paio = (PAIO)RemoveHeadList(&IoRequestList);
|
|
|
|
ReleaseMutex(IoWorkerListLock);
|
|
|
|
IoOperationStatus = ReadFileEx(
|
|
paio->ReadHandle,
|
|
paio->Buffer,
|
|
paio->Overlapped.Internal,
|
|
&paio->Overlapped,
|
|
ReadIoComplete
|
|
);
|
|
|
|
//
|
|
// Test to see if I/O was queued successfully
|
|
//
|
|
|
|
if ( !IoOperationStatus ) {
|
|
if ( GetLastError() != ERROR_HANDLE_EOF ) {
|
|
printf("FATAL I/O Error %ld\n",
|
|
GetLastError()
|
|
);
|
|
ExitProcess(1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// The I/O was successfully queued. Go back into the alertable
|
|
// wait waiting for I/O completion, or for more I/O requests
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DWORD
|
|
main(
|
|
int argc,
|
|
char *argv[],
|
|
char *envp[]
|
|
)
|
|
{
|
|
|
|
HANDLE iFile,oFile;
|
|
DWORD FileSize;
|
|
PAIO paio;
|
|
DWORD WaitStatus;
|
|
DWORD Offset;
|
|
HANDLE CompletionHandles[2];
|
|
HANDLE Thread;
|
|
DWORD ThreadId;
|
|
|
|
if ( argc < 2 ) {
|
|
printf("Usage: trd source-file destination-file\n");
|
|
}
|
|
|
|
iFile = CreateFile(
|
|
argv[1],
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL
|
|
);
|
|
if ( iFile == INVALID_HANDLE_VALUE ) {
|
|
printf("OPEN %s failed %ld\n",argv[1],GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
|
|
oFile = CreateFile(
|
|
argv[2],
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL
|
|
);
|
|
if ( oFile == INVALID_HANDLE_VALUE ) {
|
|
printf("OPEN %s failed %ld\n",argv[2],GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
|
|
IoReadsDoneEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
IoWritesDoneEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
IoWorkerListLock = CreateMutex(NULL,FALSE,NULL);;
|
|
IoWorkerListSemaphore = CreateSemaphore(NULL,0,0x7fffffff,NULL);
|
|
xassert(IoReadsDoneEvent);
|
|
xassert(IoWritesDoneEvent);
|
|
xassert(IoWorkerListLock);
|
|
xassert(IoWorkerListSemaphore);
|
|
InitializeListHead(&IoRequestList);
|
|
|
|
Thread = CreateThread(NULL,0L,IoWorkerThread,0,0,&ThreadId);
|
|
xassert(Thread);
|
|
|
|
Offset = 0;
|
|
FileSize = GetFileSize(iFile,NULL);
|
|
|
|
WaitStatus = WaitForSingleObject(IoWorkerListLock,-1);
|
|
xassert(WaitStatus == 0);
|
|
|
|
while(FileSize >= BSIZE) {
|
|
FileSize -= BSIZE;
|
|
paio = LocalAlloc(LMEM_ZEROINIT,sizeof(*paio));
|
|
xassert(paio);
|
|
paio->Buffer = LocalAlloc(LMEM_ZEROINIT,BSIZE+1);
|
|
xassert(paio->Buffer);
|
|
paio->ReadHandle = iFile;
|
|
paio->WriteHandle = oFile;
|
|
paio->Overlapped.Internal = BSIZE;
|
|
paio->Overlapped.Offset = Offset;
|
|
Offset += BSIZE;
|
|
IoCount++;
|
|
if ( IoCount & 1 ) {
|
|
InsertTailList(&IoRequestList,&paio->Links);
|
|
}
|
|
else {
|
|
InsertHeadList(&IoRequestList,&paio->Links);
|
|
}
|
|
ReleaseSemaphore(IoWorkerListSemaphore,1,NULL);
|
|
}
|
|
if ( FileSize != 0 ) {
|
|
paio = LocalAlloc(LMEM_ZEROINIT,sizeof(*paio));
|
|
xassert(paio);
|
|
paio->Buffer = LocalAlloc(LMEM_ZEROINIT,FileSize+1);
|
|
xassert(paio->Buffer);
|
|
paio->ReadHandle = iFile;
|
|
paio->WriteHandle = oFile;
|
|
paio->Overlapped.interlockInternal = FileSize;
|
|
paio->Overlapped.Offset = Offset;
|
|
IoCount++;
|
|
if ( IoCount & 1 ) {
|
|
InsertTailList(&IoRequestList,&paio->Links);
|
|
}
|
|
else {
|
|
InsertHeadList(&IoRequestList,&paio->Links);
|
|
}
|
|
ReleaseSemaphore(IoWorkerListSemaphore,1,NULL);
|
|
}
|
|
IoReadCount = IoCount;
|
|
IoWriteCount = IoCount;
|
|
ReleaseMutex(IoWorkerListLock);
|
|
|
|
CompletionHandles[0] = IoReadsDoneEvent;
|
|
CompletionHandles[1] = IoWritesDoneEvent;
|
|
|
|
WaitStatus = WaitForMultipleObjects(2,CompletionHandles,TRUE,0xffffffff);
|
|
xassert(WaitStatus != 0xffffffff);
|
|
CloseHandle(iFile);
|
|
CloseHandle(oFile);
|
|
return 1;
|
|
}
|