//EnsureCleanup.h
/******************************************************************************
Module: EnsureCleanup.h
Notices: Copyright (c) 2007 Jeffrey Richter & Christophe Nasarre
Purpose: These classes ensure object cleanup when an object goes out of scope.See Appendix A.
******************************************************************************/#pragma once // Include this header file once per compilation unit///#include <Windows.h>///// Data type representing the address of the object's cleanup function.
// I used UINT_PTR so that this class works properly in 64-bit Windows.
typedef VOID (WINAPI* PFNENSURECLEANUP)(UINT_PTR);///// Each template instantiation requires a data type, address of cleanup
// function, and a value that indicates an invalid value.
template<class TYPE, PFNENSURECLEANUP pfn, UINT_PTR tInvalid = NULL>
class CEnsureCleanup {
public:// Default constructor assumes an invalid value (nothing to cleanup)CEnsureCleanup() { m_t = tInvalid; }// This constructor sets the value to the specified valueCEnsureCleanup(TYPE t) : m_t((UINT_PTR) t) { }// The destructor performs the cleanup.~CEnsureCleanup() { Cleanup(); }// Helper methods to tell if the value represents a valid object or not..BOOL IsValid() { return(m_t != tInvalid); }BOOL IsInvalid() { return(!IsValid()); }// Re-assigning the object forces the current object to be cleaned-up.TYPE operator=(TYPE t) { Cleanup(); m_t = (UINT_PTR) t;return(*this); }// Returns the value (supports both 32-bit and 64-bit Windows).operator TYPE() { return (TYPE) m_t;}// Cleanup the object if the value represents a valid objectvoid Cleanup() { if (IsValid()) {// In 64-bit Windows, all parameters are 64-bits, // so no casting is requiredpfn(m_t); // Close the object.m_t = tInvalid; // We no longer represent a valid object.}}private:UINT_PTR m_t; // The member representing the object
};///// Macros to make it easier to declare instances of the template
// class for specific data types.#define MakeCleanupClass(className, tData, pfnCleanup) \typedef CEnsureCleanup<tData, (PFNENSURECLEANUP) pfnCleanup> className;#define MakeCleanupClassX(className, tData, pfnCleanup, tInvalid) \typedef CEnsureCleanup<tData, (PFNENSURECLEANUP) pfnCleanup, \(INT_PTR) tInvalid> className;///// Instances of the template C++ class for common data types.
MakeCleanupClass(CEnsureCloseHandle, HANDLE, CloseHandle);
MakeCleanupClassX(CEnsureCloseFile, HANDLE, CloseHandle, INVALID_HANDLE_VALUE);
MakeCleanupClass(CEnsureLocalFree, HLOCAL, LocalFree);
MakeCleanupClass(CEnsureGlobalFree, HGLOBAL, GlobalFree);
MakeCleanupClass(CEnsureRegCloseKey, HKEY, RegCloseKey);
MakeCleanupClass(CEnsureCloseServiceHandle, SC_HANDLE, CloseServiceHandle);
MakeCleanupClass(CEnsureCloseWindowStation, HWINSTA, CloseWindowStation);
MakeCleanupClass(CEnsureCloseDesktop, HDESK, CloseDesktop);
MakeCleanupClass(CEnsureUnmapViewOfFile, PVOID, UnmapViewOfFile);
MakeCleanupClass(CEnsureFreeLibrary, HMODULE, FreeLibrary);///// Special class for releasing a reserved region.
// Special class is required because VirtualFree requires 3 parameters
class CEnsureReleaseRegion {
public:CEnsureReleaseRegion(PVOID pv = NULL) : m_pv(pv) { }~CEnsureReleaseRegion() { Cleanup(); }PVOID operator=(PVOID pv) { Cleanup(); m_pv = pv; return(m_pv); }operator PVOID() { return(m_pv); }void Cleanup() { if (m_pv != NULL) { VirtualFree(m_pv, 0, MEM_RELEASE); m_pv = NULL; } }private:PVOID m_pv;
};///// Special class for freeing a block from a heap
// Special class is required because HeapFree requires 3 parameters
class CEnsureHeapFree {
public:CEnsureHeapFree(PVOID pv = NULL, HANDLE hHeap = GetProcessHeap()) : m_pv(pv), m_hHeap(hHeap) { }~CEnsureHeapFree() { Cleanup(); }PVOID operator=(PVOID pv) { Cleanup(); m_pv = pv; return(m_pv); }operator PVOID() { return(m_pv); }void Cleanup() { if (m_pv != NULL) { HeapFree(m_hHeap, 0, m_pv); m_pv = NULL; } }private:HANDLE m_hHeap;PVOID m_pv;
};template <class TV, class TM>
inline TV chROUNDDOWN(TV Value, TM Multiple) {return((Value / Multiple) * Multiple);
}// This inline function rounds a value down to the nearest multiple
template <class TV, class TM>
inline TV chROUNDUP(TV Value, TM Multiple) {return(chROUNDDOWN(Value, Multiple) + (((Value % Multiple) > 0) ? Multiple : 0));
}
/ End of File /
?
//IoCompletionPort.h
/******************************************************************************
Module: IOCP.h
Notices: Copyright (c) 2007 Jeffrey Richter & Christophe Nasarre
Purpose: This class wraps an I/O Completion Port.See Appendix B.
******************************************************************************/#pragma once // Include this header file once per compilation unit///#include <Windows.h>#define chVERIFY
#define chASSERT///class CIOCP {
public:CIOCP(int nMaxConcurrency = -1) { m_hIOCP = NULL; if (nMaxConcurrency != -1)(void) Create(nMaxConcurrency);}~CIOCP() { if (m_hIOCP != NULL) chVERIFY(CloseHandle(m_hIOCP)); }BOOL Close() {BOOL bResult = CloseHandle(m_hIOCP);m_hIOCP = NULL;return(bResult);}BOOL Create(int nMaxConcurrency = 0) {m_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, nMaxConcurrency);chASSERT(m_hIOCP != NULL);return(m_hIOCP != NULL);}BOOL AssociateDevice(HANDLE hDevice, ULONG_PTR CompKey) {BOOL fOk = (CreateIoCompletionPort(hDevice, m_hIOCP, CompKey, 0) == m_hIOCP);chASSERT(fOk);return(fOk);}BOOL AssociateSocket(SOCKET hSocket, ULONG_PTR CompKey) {return(AssociateDevice((HANDLE) hSocket, CompKey));}BOOL PostStatus(ULONG_PTR CompKey, DWORD dwNumBytes = 0, OVERLAPPED* po = NULL) {BOOL fOk = PostQueuedCompletionStatus(m_hIOCP, dwNumBytes, CompKey, po);chASSERT(fOk);return(fOk);}BOOL GetStatus(ULONG_PTR* pCompKey, PDWORD pdwNumBytes,OVERLAPPED** ppo, DWORD dwMilliseconds = INFINITE) {return(GetQueuedCompletionStatus(m_hIOCP, pdwNumBytes, pCompKey, ppo, dwMilliseconds));}private:HANDLE m_hIOCP;
};/ End of File /
?
//main.cpp
/******************************************************************************
Module: FileCopy.cpp
Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre
******************************************************************************/#include "IOCompletionPort.h" // See Appendix A.
#include "EnsureCleanup.h" // See Appendix A.#include <WindowsX.h>// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <string>///// Each I/O Request needs an OVERLAPPED structure and a data buffer
class CIOReq : public OVERLAPPED {
public:CIOReq() {Internal = InternalHigh = 0; Offset = OffsetHigh = 0; hEvent = NULL;m_nBuffSize = 0;m_pvData = NULL;}~CIOReq() {if (m_pvData != NULL)VirtualFree(m_pvData, 0, MEM_RELEASE);}BOOL AllocBuffer(SIZE_T nBuffSize) {m_nBuffSize = nBuffSize;m_pvData = VirtualAlloc(NULL, m_nBuffSize, MEM_COMMIT, PAGE_READWRITE);return(m_pvData != NULL);}BOOL Read(HANDLE hDevice, PLARGE_INTEGER pliOffset = NULL) {if (pliOffset != NULL) {Offset = pliOffset->LowPart;OffsetHigh = pliOffset->HighPart;}return(::ReadFile(hDevice, m_pvData, m_nBuffSize, NULL, this));}BOOL Write(HANDLE hDevice, PLARGE_INTEGER pliOffset = NULL) {if (pliOffset != NULL) {Offset = pliOffset->LowPart;OffsetHigh = pliOffset->HighPart;}return(::WriteFile(hDevice, m_pvData, m_nBuffSize, NULL, this));}private:SIZE_T m_nBuffSize;PVOID m_pvData;
};/////#define BUFFSIZE (64 * 1024) // The size of an I/O buffer
DWORD BUFFSIZE = 0;
#define MAX_PENDING_IO_REQS 4 // The maximum # of I/Os// The completion key values indicate the type of completed I/O.
#define CK_READ 1
#define CK_WRITE 2///BOOL FileCopy(PCTSTR pszFileSrc, PCTSTR pszFileDst) {BOOL bOk = FALSE; // Assume file copy failsLARGE_INTEGER liFileSizeSrc = { 0 }, liFileSizeDst;try {{// Open the source file without buffering & get its sizeCEnsureCloseFile hFileSrc = CreateFile(pszFileSrc, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);if (hFileSrc.IsInvalid()) goto leave;// Get the file's sizeGetFileSizeEx(hFileSrc, &liFileSizeSrc);// Nonbuffered I/O requires sector-sized transfers.// I'll use buffer-size transfers since it's easier to calculate.liFileSizeDst.QuadPart = chROUNDUP(liFileSizeSrc.QuadPart, BUFFSIZE);// Open the destination file without buffering & set its sizeCEnsureCloseFile hFileDst = CreateFile(pszFileDst, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, hFileSrc);if (hFileDst.IsInvalid()) goto leave;// File systems extend files synchronously. Extend the destination file // now so that I/Os execute asynchronously improving performance.SetFilePointerEx(hFileDst, liFileSizeDst, NULL, FILE_BEGIN);SetEndOfFile(hFileDst);// Create an I/O completion port and associate the files with it.CIOCP iocp(2); //并行數iocp.AssociateDevice(hFileSrc, CK_READ); // Read from source fileiocp.AssociateDevice(hFileDst, CK_WRITE); // Write to destination file// Initialize record-keeping variablesCIOReq ior[MAX_PENDING_IO_REQS];LARGE_INTEGER liNextReadOffset = { 0 };int nReadsInProgress = 0;int nWritesInProgress = 0;// Prime the file copy engine by simulating that writes have completed.// This causes read operations to be issued.for (int nIOReq = 0; nIOReq < _countof(ior); nIOReq++) {// Each I/O request requires a data buffer for transferschVERIFY(ior[nIOReq].AllocBuffer(BUFFSIZE));nWritesInProgress++;iocp.PostStatus(CK_WRITE, 0, &ior[nIOReq]);}BOOL bResult = FALSE;// Loop while outstanding I/O requests still existwhile ((nReadsInProgress > 0) || (nWritesInProgress > 0)) {// Suspend the thread until an I/O completesULONG_PTR CompletionKey;DWORD dwNumBytes;CIOReq* pior;bResult = iocp.GetStatus(&CompletionKey, &dwNumBytes, (OVERLAPPED**) &pior, INFINITE);switch (CompletionKey) {case CK_READ: // Read completed, write to destinationnReadsInProgress--;bResult = pior->Write(hFileDst); // Write to same offset read from sourcenWritesInProgress++;break;case CK_WRITE: // Write completed, read from sourcenWritesInProgress--;if (liNextReadOffset.QuadPart < liFileSizeDst.QuadPart) {// Not EOF, read the next block of data from the source file.bResult = pior->Read(hFileSrc, &liNextReadOffset);nReadsInProgress++;liNextReadOffset.QuadPart += BUFFSIZE; // Advance source offset}break;}}bOk = TRUE;}leave:;}catch (...) {}if (bOk) {// The destination file size is a multiple of the page size. Open the// file WITH buffering to shrink its size to the source file's size.CEnsureCloseFile hFileDst = CreateFile(pszFileDst, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);if (hFileDst.IsValid()) {SetFilePointerEx(hFileDst, liFileSizeSrc, NULL, FILE_BEGIN);SetEndOfFile(hFileDst);}}return(bOk);
}int wmain(int argc,wchar_t **argv)
{GetDiskFreeSpaceW(NULL,NULL,&BUFFSIZE,NULL,NULL); //cache bytes of per sector for support FILE_FLAG_NO_BUFFERING flag.if(argc < 3) return -1;FileCopy(argv[1],argv[2]);return(0);
}End of File //