[+] AuIO::IIOHandle

This commit is contained in:
Reece Wilson 2023-07-29 08:02:47 +01:00
parent 0cf38d5fcd
commit 7e2aa2de3d
21 changed files with 988 additions and 334 deletions

View File

@ -15,4 +15,10 @@ namespace Aurora::IO::FS
bool bDirectIO = true, // true disables buffering under Win32 bool bDirectIO = true, // true disables buffering under Win32
// true enables non-blocking ticks under Linux aio by bypassing the kernels cache // true enables non-blocking ticks under Linux aio by bypassing the kernels cache
EFileAdvisoryLockLevel lock = EFileAdvisoryLockLevel::eNoSafety); EFileAdvisoryLockLevel lock = EFileAdvisoryLockLevel::eNoSafety);
#if defined(AUX_FSAOPEX)
AUKN_SYM AuSPtr<IAsyncTransaction> OpenDirectIOAsyncFileStreamFromHandle(AuSPtr<IIOHandle> pIOHandle);
AUKN_SYM AuSPtr<IAsyncTransaction> OpenBufferedAsyncFileStreamFromHandle(AuSPtr<IIOHandle> pIOHandle);
#endif
} }

View File

@ -18,4 +18,6 @@ namespace Aurora::IO::FS
AUKN_SHARED_API(OpenWrite, IFileStream, const AuString &path, EFileAdvisoryLockLevel successPostAdvisoryLevel = EFileAdvisoryLockLevel::eBlockReadWrite); AUKN_SHARED_API(OpenWrite, IFileStream, const AuString &path, EFileAdvisoryLockLevel successPostAdvisoryLevel = EFileAdvisoryLockLevel::eBlockReadWrite);
AUKN_SHARED_API(Open, IFileStream, const AuString &path, EFileOpenMode mode = EFileOpenMode::eRead, EFileAdvisoryLockLevel successPostAdvisoryLevel = EFileAdvisoryLockLevel::eBlockReadWrite); AUKN_SHARED_API(Open, IFileStream, const AuString &path, EFileOpenMode mode = EFileOpenMode::eRead, EFileAdvisoryLockLevel successPostAdvisoryLevel = EFileAdvisoryLockLevel::eBlockReadWrite);
AUKN_SYM AuSPtr<IFileStream> OpenBlockingFileStreamFromHandle(AuSPtr<IIOHandle> pIOHandle);
} }

View File

@ -20,6 +20,8 @@
#include "Async.hpp" #include "Async.hpp"
#include "IOSleep.hpp" #include "IOSleep.hpp"
#include "IOHandle.hpp"
#include "FS/FS.hpp" #include "FS/FS.hpp"
#include "Net/Net.hpp" #include "Net/Net.hpp"
#include "Character/Character.hpp" #include "Character/Character.hpp"

View File

@ -0,0 +1,129 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IOHandle.hpp
Date: 2023-7-28
Author: Reece
***/
#pragma once
#include "FS/EFileAdvisoryLockLevel.hpp"
#include "FS/EFileOpenMode.hpp"
namespace Aurora::IO
{
// Note: A handle is never disposable to prevent IO fd use after close
// You must ensure RAII and/or shared ownership release to dispose of the IO handle.
// This class is only intended to be an handle view; therefore, it is not possible to close the handle.
struct IIOHandle
{
struct HandleCreate
{
/**
* "Create"
*/
bool bFailIfNonEmptyFile {};
/**
* Lock level
*/
FS::EFileAdvisoryLockLevel eAdvisoryLevel;
/**
* Path
*/
const AuString &path;
/**
* Mode
*/
FS::EFileOpenMode eMode;
/**
*
*/
bool bAlwaysCreateDirTree { true };
/**
* Indicates the handle will be for use with IAsyncTransactions as opposed to IFileStream and AuProcess
*/
bool bAsyncHandle { false };
/**
* Indicates the handle will only ever directly interface with the disk hardware as opposed to leveraging kernel assigned user shared memory
*/
bool bDirectIOMode { false };
cstatic HandleCreate Create(const AuString &path)
{
HandleCreate create(path);
create.bFailIfNonEmptyFile = true;
create.eMode = FS::EFileOpenMode::eReadWrite;
create.eAdvisoryLevel = FS::EFileAdvisoryLockLevel::eBlockReadWrite;
return AuMove(create);
}
cstatic HandleCreate ReadWrite(const AuString &path)
{
HandleCreate create(path);
create.eMode = FS::EFileOpenMode::eReadWrite;
create.eAdvisoryLevel = FS::EFileAdvisoryLockLevel::eBlockReadWrite;
return AuMove(create);
}
cstatic HandleCreate Read(const AuString &path)
{
HandleCreate read(path);
read.eMode = FS::EFileOpenMode::eRead;
read.eAdvisoryLevel = FS::EFileAdvisoryLockLevel::eBlockWrite;
return AuMove(read);
}
cstatic HandleCreate Open(const AuString &path)
{
HandleCreate read(path);
read.eMode = FS::EFileOpenMode::eRead;
read.eAdvisoryLevel = FS::EFileAdvisoryLockLevel::eBlockReadWrite;
return AuMove(read);
}
inline HandleCreate(const AuString &path) :
path(path)
{
}
};
virtual bool InitFromHandle(AuSPtr<IIOHandle> pHandle) = 0;
virtual bool InitFromPath(HandleCreate create) = 0;
virtual bool InitFromCopy(AuUInt64 uOSHandle) = 0;
virtual bool InitFromMove(AuUInt64 uOSHandle) = 0;
virtual bool InitFromPair(AuUInt64 uOSReadHandle, AuUInt64 uOSWriteHandle) = 0;
virtual bool InitFromPairMove(AuOptionalEx<AuUInt64> uOSReadHandle,
AuOptionalEx<AuUInt64> uOSWriteHandle) = 0;
virtual AuUInt64 GetOSHandle() = 0;
virtual AuUInt64 GetOSReadHandle() = 0;
virtual AuOptionalEx<AuUInt64> GetOSReadHandleSafe() = 0;
virtual AuUInt64 GetOSWriteHandle() = 0;
virtual AuOptionalEx<AuUInt64> GetOSWriteHandleSafe() = 0;
virtual bool IsValid() = 0;
virtual bool HasUniqueWriteHandle() = 0;
virtual bool IsAsync() = 0;
virtual AuString GetPath() = 0;
};
AUKN_SHARED_SOO(IOHandle, IIOHandle, 256);
}

View File

@ -124,7 +124,7 @@ namespace Aurora::Memory
{ {
if (buffer.length) if (buffer.length)
{ {
this->base = FAlloc<AuUInt8 *>(buffer.length); this->base = ZAlloc<AuUInt8 *>(buffer.length);
} }
this->scaleSize = buffer.scaleSize; this->scaleSize = buffer.scaleSize;
this->flagCircular = buffer.flagCircular; this->flagCircular = buffer.flagCircular;
@ -160,7 +160,7 @@ namespace Aurora::Memory
inline ByteBuffer(const void *in, AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0) inline ByteBuffer(const void *in, AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{ {
this->scaleSize = kBufferInitialPower; this->scaleSize = kBufferInitialPower;
this->base = length ? FAlloc<AuUInt8 *>(length) : nullptr; this->base = length ? ZAlloc<AuUInt8 *>(length) : nullptr;
if (!this->base) if (!this->base)
{ {
Reset(); Reset();
@ -181,7 +181,7 @@ namespace Aurora::Memory
inline ByteBuffer(const AuList<AuUInt8> &vector, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0) inline ByteBuffer(const AuList<AuUInt8> &vector, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{ {
this->scaleSize = kBufferInitialPower; this->scaleSize = kBufferInitialPower;
this->base = vector.size() ? FAlloc<AuUInt8 *>(vector.size()) : nullptr; this->base = vector.size() ? ZAlloc<AuUInt8 *>(vector.size()) : nullptr;
if (!this->base) if (!this->base)
{ {
Reset(); Reset();

View File

@ -31,7 +31,7 @@ namespace Aurora::Memory
return true; return true;
} }
this->base = fast ? FAlloc<AuUInt8 *>(length) : ZAlloc<AuUInt8 *>(length); this->base = ZAlloc<AuUInt8 *>(length);
if (!this->base) if (!this->base)
{ {
return false; return false;
@ -65,7 +65,7 @@ namespace Aurora::Memory
return true; return true;
} }
this->base = fast ? FAlloc<AuUInt8 *>(length, alignment) : ZAlloc<AuUInt8 *>(length, alignment); this->base = ZAlloc<AuUInt8 *>(length, alignment);
if (!this->base) if (!this->base)
{ {
return false; return false;

260
Source/IO/AuIOHandle.NT.cpp Normal file
View File

@ -0,0 +1,260 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIOHandle.NT.cpp
Date: 2023-7-28
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "AuIOHandle.hpp"
#include "AuIOHandle.NT.hpp"
#include "FS/FS.hpp"
#include "FS/FileAdvisory.NT.hpp"
namespace Aurora::IO
{
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess)
{
HANDLE hTargetHandle = (HANDLE)uOSHandle;
HANDLE hTargetProcess = ::GetCurrentProcess();
HANDLE hHandle {};
if (!::DuplicateHandle(hTargetProcess,
hTargetHandle,
hTargetProcess,
&hHandle,
bWriteAccess ? GENERIC_WRITE | GENERIC_READ : GENERIC_READ,
FALSE,
FALSE))
{
return 0;
}
return AuUInt64(hHandle);
}
void AFileHandle::CloseHandle(AuUInt64 uOSHandle)
{
HANDLE hHandle = (HANDLE)uOSHandle;
AuWin32CloseHandle(hHandle);
}
struct NTIOHandle final : AFileHandle
{
bool InitFromPath(HandleCreate create) override
{
HANDLE hFileHandle;
DWORD dwFlags {};
DWORD dwShare {};
if (create.path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
if (!FS::EFileOpenModeIsValid(create.eMode))
{
SysPushErrorParam("Invalid open mode");
return false;
}
if (!FS::EFileAdvisoryLockLevelIsValid(create.eAdvisoryLevel))
{
SysPushErrorParam("Invalid lock mode");
return false;
}
auto pathex = FS::NormalizePathRet(create.path);
if (pathex.empty())
{
SysPushErrorMemory();
return false;
}
auto win32Path = Locale::ConvertFromUTF8(pathex);
if (win32Path.empty())
{
SysPushErrorMemory();
return false;
}
hFileHandle = INVALID_HANDLE_VALUE;
dwShare = FS::NtLockAdvisoryToShare(create.eAdvisoryLevel);
if (create.bAsyncHandle)
{
dwFlags |= FILE_FLAG_OVERLAPPED;
}
if (create.bDirectIOMode)
{
dwFlags |= FILE_FLAG_NO_BUFFERING;
}
if (!dwFlags)
{
dwFlags |= FILE_ATTRIBUTE_NORMAL;
}
switch (create.eMode)
{
case FS::EFileOpenMode::eRead:
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_READ,
dwShare,
NULL,
OPEN_EXISTING,
dwFlags,
NULL);
if (hFileHandle != INVALID_HANDLE_VALUE)
{
this->uOSReadHandle = AuUInt64(hFileHandle);
}
break;
}
case FS::EFileOpenMode::eReadWrite:
{
if (create.bAlwaysCreateDirTree)
{
FS::CreateDirectories(pathex, true);
}
if (create.bFailIfNonEmptyFile)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
NULL,
NULL,
CREATE_NEW,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
if (AuFS::FileExists(pathex.c_str()))
{
SysPushErrorResourceExists("File {} already exists", create.path);
return false;
}
}
}
else
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
dwShare,
NULL,
OPEN_EXISTING,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
dwShare,
NULL,
CREATE_NEW,
dwFlags,
NULL);
}
}
if (hFileHandle != INVALID_HANDLE_VALUE)
{
this->uOSReadHandle = AuUInt64(hFileHandle);
this->uOSWriteHandle = AuUInt64(hFileHandle);
}
break;
}
case FS::EFileOpenMode::eWrite:
{
if (create.bAlwaysCreateDirTree)
{
FS::CreateDirectories(pathex, true);
}
if (create.bFailIfNonEmptyFile)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | DELETE,
NULL,
NULL,
CREATE_NEW,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
if (AuFS::FileExists(pathex.c_str()))
{
SysPushErrorResourceExists("File {} already exists", create.path);
return false;
}
}
}
else
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | FILE_READ_ATTRIBUTES | DELETE,
dwShare,
NULL,
OPEN_EXISTING,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | DELETE,
dwShare,
NULL,
CREATE_NEW,
dwFlags,
NULL);
}
}
if (hFileHandle != INVALID_HANDLE_VALUE)
{
this->uOSWriteHandle = AuUInt64(hFileHandle);
}
break;
}
}
if (hFileHandle == INVALID_HANDLE_VALUE)
{
SysPushErrorIO("Couldn't open: {}", create.path);
return false;
}
this->bIsAsync = create.bAsyncHandle;
this->path = create.path;
return this->IsValid();
}
};
AUKN_SYM IIOHandle *IOHandleNew()
{
return _new NTIOHandle();
}
AUKN_SYM void IOHandleRelease(IIOHandle *pIOHandle)
{
AuSafeDelete<NTIOHandle *>(pIOHandle);
}
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, IOHandle, NTIOHandle)
}

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIOHandle.NT.hpp
Date: 2023-7-28
Author: Reece
***/
#pragma once
namespace Aurora::IO
{
}

174
Source/IO/AuIOHandle.cpp Normal file
View File

@ -0,0 +1,174 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIOHandle.cpp
Date: 2023-7-28
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "AuIOHandle.hpp"
namespace Aurora::IO
{
AFileHandle::~AFileHandle()
{
if (this->uOSWriteHandle.HasValue() && this->uOSReadHandle.HasValue() &&
this->uOSReadHandle.Value() == this->uOSWriteHandle.Value())
{
this->CloseHandle(this->uOSReadHandle.value());
AuResetMember(this->uOSReadHandle);
AuResetMember(this->uOSWriteHandle);
}
if (this->uOSReadHandle)
{
this->CloseHandle(this->uOSReadHandle.value());
AuResetMember(this->uOSReadHandle);
}
if (this->uOSWriteHandle)
{
this->CloseHandle(this->uOSWriteHandle.value());
AuResetMember(this->uOSWriteHandle);
}
}
bool AFileHandle::InitFromHandle(AuSPtr<IIOHandle> pHandle)
{
auto pSrc = AuStaticCast<AFileHandle>(pHandle);
auto pDest = this;
if (this->IsValid())
{
return false;
}
pDest->pThat = pHandle;
pDest->uOSReadHandle = pSrc->uOSReadHandle;
pDest->uOSWriteHandle = pSrc->uOSWriteHandle;
pDest->bIsAsync = pSrc->bIsAsync;
return true;
}
bool AFileHandle::InitFromCopy(AuUInt64 uOSHandle)
{
if (this->IsValid())
{
return false;
}
if (auto uOSWriteHandle = this->DupHandle(uOSHandle, true))
{
this->uOSReadHandle = uOSWriteHandle;
this->uOSWriteHandle = uOSWriteHandle;
return true;
}
else
{
return {};
}
}
bool AFileHandle::InitFromMove(AuUInt64 uOSHandle)
{
if (this->IsValid())
{
return false;
}
this->uOSReadHandle = uOSHandle;
this->uOSWriteHandle = uOSHandle;
return true;
}
bool AFileHandle::InitFromPair(AuUInt64 uOSReadHandle,
AuUInt64 uOSWriteHandle)
{
if (this->IsValid())
{
return false;
}
if (auto uOSReadHandle2 = this->DupHandle(uOSReadHandle, false))
{
this->uOSReadHandle = uOSReadHandle2;
}
else
{
return {};
}
if (auto uOSWriteHandle2 = this->DupHandle(uOSWriteHandle, true))
{
this->uOSWriteHandle = uOSWriteHandle2;
}
else
{
this->CloseHandle(this->uOSReadHandle);
AuResetMember(this->uOSReadHandle);
return {};
}
return true;
}
bool AFileHandle::InitFromPairMove(AuOptionalEx<AuUInt64> uOSReadHandle,
AuOptionalEx<AuUInt64> uOSWriteHandle)
{
if (this->IsValid())
{
return false;
}
this->uOSReadHandle = uOSReadHandle;
this->uOSWriteHandle = uOSWriteHandle;
return true;
}
AuUInt64 AFileHandle::GetOSHandle()
{
return this->uOSReadHandle.ValueOr(this->uOSWriteHandle.Value());
}
AuUInt64 AFileHandle::GetOSReadHandle()
{
return this->uOSReadHandle.value();
}
AuOptionalEx<AuUInt64> AFileHandle::GetOSReadHandleSafe()
{
return this->uOSReadHandle;
}
AuUInt64 AFileHandle::GetOSWriteHandle()
{
return this->uOSWriteHandle.Value();
}
AuOptionalEx<AuUInt64> AFileHandle::GetOSWriteHandleSafe()
{
return this->uOSWriteHandle;
}
bool AFileHandle::IsValid()
{
return this->uOSReadHandle.HasValue() ||
this->uOSWriteHandle.HasValue();
}
bool AFileHandle::HasUniqueWriteHandle()
{
return this->uOSWriteHandle.HasValue();
}
bool AFileHandle::IsAsync()
{
return this->bIsAsync;
}
AuString AFileHandle::GetPath()
{
return this->path;
}
}

60
Source/IO/AuIOHandle.hpp Normal file
View File

@ -0,0 +1,60 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIOHandle.hpp
Date: 2023-7-28
Author: Reece
***/
#pragma once
namespace Aurora::IO
{
struct AFileHandle : IIOHandle
{
virtual ~AFileHandle();
bool InitFromHandle(AuSPtr<IIOHandle> pHandle) override;
bool InitFromCopy(AuUInt64 uOSHandle) override;
bool InitFromMove(AuUInt64 uOSHandle) override;
bool InitFromPair(AuUInt64 uOSReadHandle,
AuUInt64 uOSWriteHandle) override;
bool InitFromPairMove(AuOptionalEx<AuUInt64> uOSReadHandle,
AuOptionalEx<AuUInt64> uOSWriteHandle) override;
AuUInt64 GetOSHandle() override;
AuUInt64 GetOSReadHandle() override;
AuOptionalEx<AuUInt64> GetOSReadHandleSafe() override;
AuUInt64 GetOSWriteHandle() override;
AuOptionalEx<AuUInt64> GetOSWriteHandleSafe() override;
bool IsValid() override;
bool HasUniqueWriteHandle() override;
bool IsAsync() override;
AuString GetPath() override;
AuOptionalEx<AuUInt64> uOSWriteHandle;
AuOptionalEx<AuUInt64> uOSReadHandle;
AuSPtr<IIOHandle> pThat;
bool bIsAsync {};
AuString path;
protected:
// Implement me:
// bool InitFromPath(HandleCreate create) override;
static AuUInt64 DupHandle(AuUInt64 uOSHandle, bool bWriteAccess);
static void CloseHandle(AuUInt64 uOSHandle);
};
}

View File

@ -62,105 +62,14 @@ namespace Aurora::IO::FS
AuWin32CloseHandle(this->event); AuWin32CloseHandle(this->event);
} }
FileHandle::~FileHandle() AuSPtr<IIOHandle> NtAsyncFileStream::GetHandle()
{ {
if (this->bNoOwns) return this->pHandle_;
{
return;
}
if (this->writeHandle != this->handle)
{
AuWin32CloseHandle(this->writeHandle);
}
this->writeHandle = INVALID_HANDLE_VALUE;
AuWin32CloseHandle(this->handle);
} }
bool FileHandle::Init(const AuString &path, EFileOpenMode openMode, bool directIO, EFileAdvisoryLockLevel lock) void NtAsyncFileStream::Init(const AuSPtr<IIOHandle> &pHandle)
{ {
HANDLE fileHandle; this->pHandle_ = pHandle;
auto pathex = NormalizePathRet(path);
if (pathex.empty())
{
return false;
}
auto win32Path = Locale::ConvertFromUTF8(pathex);
if (win32Path.empty())
{
return false;
}
auto flags = FILE_FLAG_OVERLAPPED;
if (directIO)
{
flags |= FILE_FLAG_NO_BUFFERING;
}
fileHandle = INVALID_HANDLE_VALUE;
switch (openMode)
{
case EFileOpenMode::eRead:
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, OPEN_EXISTING, flags, NULL);
break;
}
case EFileOpenMode::eReadWrite:
{
CreateDirectories(pathex, true);
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, OPEN_ALWAYS, flags, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, CREATE_ALWAYS, flags, NULL);
}
break;
}
case EFileOpenMode::eWrite:
{
CreateDirectories(pathex, true);
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES, NtLockAdvisoryToShare(lock), NULL, OPEN_ALWAYS, flags, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ, NtLockAdvisoryToShare(lock), NULL, CREATE_ALWAYS, flags, NULL);
}
break;
}
}
if (fileHandle == INVALID_HANDLE_VALUE)
{
SysPushErrorIO("Missing file: {}", path);
return {};
}
this->directIO = directIO;
this->handle = fileHandle;
this->writeHandle = fileHandle;
this->readOnly = openMode == EFileOpenMode::eRead;
return true;
}
void FileHandle::Init(HANDLE read, HANDLE write)
{
this->directIO = true;
this->handle = read;
this->writeHandle = write;
this->readOnly = false;
}
AuSPtr<FileHandle> NtAsyncFileStream::GetHandle()
{
return handle_;
}
void NtAsyncFileStream::Init(const AuSPtr<FileHandle> &handle)
{
this->handle_ = handle;
} }
AuSPtr<IAsyncTransaction> NtAsyncFileStream::NewTransaction() AuSPtr<IAsyncTransaction> NtAsyncFileStream::NewTransaction()
@ -171,7 +80,7 @@ namespace Aurora::IO::FS
return {}; return {};
} }
if (!shared->Init(this->handle_)) if (!shared->InitWeak(this->pHandle_))
{ {
return {}; return {};
} }
@ -184,13 +93,15 @@ namespace Aurora::IO::FS
LARGE_INTEGER i {}; LARGE_INTEGER i {};
i.QuadPart = length; i.QuadPart = length;
if (!SetFilePointerEx(this->handle_->handle, i, nullptr, FILE_BEGIN)) auto hHandle = (HANDLE)this->pHandle_->GetOSHandle();
if (!SetFilePointerEx(hHandle, i, nullptr, FILE_BEGIN))
{ {
SysPushErrorIO(); SysPushErrorIO();
return false; return false;
} }
return SetEndOfFile(this->handle_->handle); return SetEndOfFile(hHandle);
} }
bool NtAsyncFileStream::BlockingRead(AuUInt64 offset, const Memory::MemoryViewStreamWrite &parameters) bool NtAsyncFileStream::BlockingRead(AuUInt64 offset, const Memory::MemoryViewStreamWrite &parameters)
@ -198,12 +109,15 @@ namespace Aurora::IO::FS
LARGE_INTEGER i {}; LARGE_INTEGER i {};
i.QuadPart = offset; i.QuadPart = offset;
if (this->handle_->bReadLock) auto hOptSafe = this->pHandle_->GetOSReadHandleSafe();
if (!hOptSafe)
{ {
return false; return false;
} }
if (!SetFilePointerEx(this->handle_->handle, i, nullptr, FILE_BEGIN)) auto hHandle = (HANDLE)hOptSafe.Value();
if (!SetFilePointerEx(hHandle, i, nullptr, FILE_BEGIN))
{ {
SysPushErrorIO(); SysPushErrorIO();
return false; return false;
@ -213,7 +127,7 @@ namespace Aurora::IO::FS
a.hEvent = CreateEventA(NULL, true, 0, NULL); a.hEvent = CreateEventA(NULL, true, 0, NULL);
DWORD read; DWORD read;
if (!::ReadFile(this->handle_->handle, parameters.ptr, parameters.length, NULL, &a) && if (!::ReadFile(hHandle, parameters.ptr, parameters.length, NULL, &a) &&
::GetLastError() != ERROR_IO_PENDING) ::GetLastError() != ERROR_IO_PENDING)
{ {
SysPushErrorIO(); SysPushErrorIO();
@ -222,7 +136,7 @@ namespace Aurora::IO::FS
} }
::WaitForSingleObject(a.hEvent, 0); ::WaitForSingleObject(a.hEvent, 0);
if (!::GetOverlappedResult(this->handle_->handle, &a, &read, true)) if (!::GetOverlappedResult(hHandle, &a, &read, true))
{ {
::CloseHandle(a.hEvent); ::CloseHandle(a.hEvent);
return false; return false;
@ -238,12 +152,15 @@ namespace Aurora::IO::FS
LARGE_INTEGER i {}; LARGE_INTEGER i {};
i.QuadPart = offset; i.QuadPart = offset;
if (this->handle_->bWriteLock) auto hOptSafe = this->pHandle_->GetOSWriteHandleSafe();
if (!hOptSafe)
{ {
return false; return false;
} }
if (!SetFilePointerEx(this->handle_->handle, i, nullptr, FILE_BEGIN)) auto hHandle = (HANDLE)hOptSafe.Value();
if (!SetFilePointerEx(hHandle, i, nullptr, FILE_BEGIN))
{ {
SysPushErrorIO(); SysPushErrorIO();
return false; return false;
@ -253,7 +170,7 @@ namespace Aurora::IO::FS
a.hEvent = CreateEventA(NULL, true, 0, NULL); a.hEvent = CreateEventA(NULL, true, 0, NULL);
DWORD read; DWORD read;
if (!::WriteFile(this->handle_->writeHandle, parameters.ptr, parameters.length, NULL, &a) && if (!::WriteFile(hHandle, parameters.ptr, parameters.length, NULL, &a) &&
::GetLastError() != ERROR_IO_PENDING) ::GetLastError() != ERROR_IO_PENDING)
{ {
SysPushErrorIO(); SysPushErrorIO();
@ -262,7 +179,7 @@ namespace Aurora::IO::FS
} }
::WaitForSingleObject(a.hEvent, 0); ::WaitForSingleObject(a.hEvent, 0);
if (!::GetOverlappedResult(this->handle_->writeHandle, &a, &read, true)) if (!::GetOverlappedResult(hHandle, &a, &read, true))
{ {
::CloseHandle(a.hEvent); ::CloseHandle(a.hEvent);
return false; return false;
@ -273,7 +190,14 @@ namespace Aurora::IO::FS
return true; return true;
} }
bool NtAsyncFileTransaction::Init(const AuSPtr<FileHandle> &handle) bool NtAsyncFileTransaction::InitWeak(const AuSPtr<IIOHandle> &handle)
{
this->wpHandle_ = handle;
this->overlap.hEvent = this->event = CreateEventW(nullptr, true, false, nullptr);
return this->overlap.hEvent != INVALID_HANDLE_VALUE;
}
bool NtAsyncFileTransaction::Init(const AuSPtr<IIOHandle> &handle)
{ {
this->pHandle_ = handle; this->pHandle_ = handle;
this->overlap.hEvent = this->event = CreateEventW(nullptr, true, false, nullptr); this->overlap.hEvent = this->event = CreateEventW(nullptr, true, false, nullptr);
@ -292,8 +216,7 @@ namespace Aurora::IO::FS
auto er = GetLastError(); auto er = GetLastError();
if (val) if (val)
{ {
::SetEvent(that->event); //(void)that->Complete();
that->DispatchCb(that->dwLastAbstractStat);
return true; return true;
} }
else if (er == ERROR_IO_PENDING) else if (er == ERROR_IO_PENDING)
@ -309,7 +232,7 @@ namespace Aurora::IO::FS
that->bHasFailed = true; // to pass completion that->bHasFailed = true; // to pass completion
that->dwOsErrorCode = er; // to suppress actual error condition that->dwOsErrorCode = er; // to suppress actual error condition
auto pipe = that->pNtIpcPipeImpl.lock(); auto pipe = AuTryLockMemoryType(that->pNtIpcPipeImpl);
that->DispatchCb(0); that->DispatchCb(0);
@ -319,6 +242,7 @@ namespace Aurora::IO::FS
} }
that->pMemoryHold.reset(); that->pMemoryHold.reset();
that->pPin.reset();
return true; return true;
} }
else else
@ -327,7 +251,7 @@ namespace Aurora::IO::FS
that->Reset(); that->Reset();
that->dwOsErrorCode = er; that->dwOsErrorCode = er;
that->bHasFailed = true; that->bHasFailed = true;
SysPushErrorFIO("QoA async FIO error: {} {}", that->GetFileHandle()->path, that->dwOsErrorCode); SysPushErrorFIO("QoA async FIO error: {} {}", /*that->GetFileHandle()->path*/ "", that->dwOsErrorCode);
return false; return false;
} }
} }
@ -340,6 +264,11 @@ namespace Aurora::IO::FS
auto transaction = reinterpret_cast<NtAsyncFileTransaction *>(reinterpret_cast<AuUInt8*>(lpOverlapped) - offsetof(NtAsyncFileTransaction, overlap)); auto transaction = reinterpret_cast<NtAsyncFileTransaction *>(reinterpret_cast<AuUInt8*>(lpOverlapped) - offsetof(NtAsyncFileTransaction, overlap));
auto hold = AuExchange(transaction->pPin, {}); auto hold = AuExchange(transaction->pPin, {});
if (!hold)
{
return;
}
if (dwErrorCode) if (dwErrorCode)
{ {
hold->bHasFailed = true; hold->bHasFailed = true;
@ -399,7 +328,12 @@ namespace Aurora::IO::FS
return {}; return {};
} }
if (this->pHandle_->bReadLock) auto pHandle = this->GetFileHandle();
auto optRead = pHandle->GetOSReadHandleSafe();
if (!optRead)
{ {
return false; return false;
} }
@ -418,7 +352,7 @@ namespace Aurora::IO::FS
this->overlap.Offset = AuBitsToLower(offset); this->overlap.Offset = AuBitsToLower(offset);
this->overlap.OffsetHigh = AuBitsToHigher(offset); this->overlap.OffsetHigh = AuBitsToHigher(offset);
auto ret = ::ReadFileEx(this->pHandle_->handle, memoryView->ptr, memoryView->length, &this->overlap, FileOperationCompletion); auto ret = ::ReadFileEx((HANDLE)optRead.value(), memoryView->ptr, memoryView->length, &this->overlap, FileOperationCompletion);
return TranslateNtStatus(this, ret); return TranslateNtStatus(this, ret);
} }
@ -447,7 +381,11 @@ namespace Aurora::IO::FS
return {}; return {};
} }
if (this->pHandle_->bWriteLock) auto pHandle = this->GetFileHandle();
auto optWrite = pHandle->GetOSWriteHandleSafe();
if (!optWrite)
{ {
return false; return false;
} }
@ -465,7 +403,7 @@ namespace Aurora::IO::FS
this->ResetAIO(); this->ResetAIO();
this->overlap.Offset = AuBitsToLower(offset); this->overlap.Offset = AuBitsToLower(offset);
this->overlap.OffsetHigh = AuBitsToHigher(offset); this->overlap.OffsetHigh = AuBitsToHigher(offset);
auto ret = ::WriteFileEx(this->pHandle_->writeHandle, memoryView->ptr, memoryView->length, &this->overlap, FileOperationCompletion); auto ret = ::WriteFileEx((HANDLE)optWrite.value(), memoryView->ptr, memoryView->length, &this->overlap, FileOperationCompletion);
return TranslateNtStatus(this, ret); return TranslateNtStatus(this, ret);
} }
@ -493,14 +431,22 @@ namespace Aurora::IO::FS
{ {
this->isIrredeemable_ = true; this->isIrredeemable_ = true;
this->bHasFailed = true; this->bHasFailed = true;
if (pCancelIoEx)
auto hOptSafe = this->GetFileHandle()->GetOSReadHandleSafe();
if (hOptSafe)
{ {
pCancelIoEx(this->pHandle_->handle, &this->overlap); auto hHandle = (HANDLE)hOptSafe.Value();
}
else if (pCancelIoEx)
{ {
::CancelIo(this->pHandle_->handle); pCancelIoEx(hHandle, &this->overlap);
}
else
{
::CancelIo(hHandle);
}
} }
::SetEvent(this->event); ::SetEvent(this->event);
this->dwOsErrorCode = ERROR_ABANDONED_WAIT_0; this->dwOsErrorCode = ERROR_ABANDONED_WAIT_0;
} }
@ -540,13 +486,20 @@ namespace Aurora::IO::FS
if (!completeRoutine) if (!completeRoutine)
{ {
if (::GetOverlappedResult(this->pHandle_->handle, auto hOptSafe = this->GetFileHandle()->GetOSReadHandleSafe();
&this->overlap, if (hOptSafe)
&read,
false) && (read || bForce))
{ {
DispatchCb(read); auto hHandle = (HANDLE)hOptSafe.Value();
return true;
if (::GetOverlappedResult(hHandle,
&this->overlap,
&read,
false) && (read || bForce))
{
SetEvent(this->overlap.hEvent);
DispatchCb(read);
return true;
}
} }
} }
else else
@ -572,7 +525,7 @@ namespace Aurora::IO::FS
} }
return bool(this->dwLastBytes) || return bool(this->dwLastBytes) ||
this->Failed(); this->bHasFailed;
} }
bool NtAsyncFileTransaction::Complete() bool NtAsyncFileTransaction::Complete()
@ -616,9 +569,9 @@ namespace Aurora::IO::FS
return this->event; return this->event;
} }
AuSPtr<FileHandle> NtAsyncFileTransaction::GetFileHandle() AuSPtr<IIOHandle> NtAsyncFileTransaction::GetFileHandle()
{ {
return this->pHandle_; return this->pHandle_ ? this->pHandle_ : AuTryLockMemoryType(this->wpHandle_);
} }
AuSPtr<AuLoop::ILoopSource> NtAsyncFileTransaction::NewLoopSource() AuSPtr<AuLoop::ILoopSource> NtAsyncFileTransaction::NewLoopSource()
@ -628,36 +581,34 @@ namespace Aurora::IO::FS
AUKN_SYM IAsyncFileStream *OpenAsyncNew(const AuString &path, EFileOpenMode openMode, bool directIO, EFileAdvisoryLockLevel lock) AUKN_SYM IAsyncFileStream *OpenAsyncNew(const AuString &path, EFileOpenMode openMode, bool directIO, EFileAdvisoryLockLevel lock)
{ {
AuSPtr<FileHandle> fileHandle; auto pHandle = AuIO::IOHandleShared();
NtAsyncFileStream *stream; if (!pHandle)
if (path.empty())
{ {
SysPushErrorParam("Empty path"); SysPushErrorMemory();
return {}; return nullptr;
} }
if (!EFileOpenModeIsValid(openMode)) AuIO::IIOHandle::HandleCreate createhandle(path);
createhandle.eAdvisoryLevel = lock;
createhandle.eMode = openMode;
createhandle.bFailIfNonEmptyFile = false;
createhandle.bDirectIOMode = directIO;
createhandle.bAsyncHandle = true;
if (!pHandle->InitFromPath(createhandle))
{ {
SysPushErrorParam("Invalid open mode"); return nullptr;
return {};
} }
fileHandle = AuMakeShared<FileHandle>(); auto pStream = _new NtAsyncFileStream();
if (!fileHandle->Init(path, openMode, directIO, lock)) if (!pStream)
{ {
return {}; SysPushErrorMemory();
return nullptr;
} }
stream = _new NtAsyncFileStream(); pStream->Init(pHandle);
if (!stream) return pStream;
{
return {};
}
stream->Init(fileHandle);
return stream;
} }
AUKN_SYM void OpenAsyncRelease(IAsyncFileStream *handle) AUKN_SYM void OpenAsyncRelease(IAsyncFileStream *handle)

View File

@ -14,22 +14,6 @@ namespace Aurora::IO::IPC
namespace Aurora::IO::FS namespace Aurora::IO::FS
{ {
struct FileHandle
{
~FileHandle();
bool Init(const AuString &path, EFileOpenMode openMode, bool directIO, EFileAdvisoryLockLevel lock);
void Init(HANDLE read, HANDLE write);
HANDLE handle {INVALID_HANDLE_VALUE}, writeHandle {INVALID_HANDLE_VALUE};
AuString path;
bool readOnly;
bool directIO;
bool bNoOwns { false };
bool bWriteLock { false };
bool bReadLock { false };
};
struct NtAsyncFileStream : IAsyncFileStream struct NtAsyncFileStream : IAsyncFileStream
{ {
AuSPtr<IAsyncTransaction> NewTransaction() override; AuSPtr<IAsyncTransaction> NewTransaction() override;
@ -38,19 +22,20 @@ namespace Aurora::IO::FS
bool BlockingRead(AuUInt64 offset, const Memory::MemoryViewStreamWrite &parameters) override; bool BlockingRead(AuUInt64 offset, const Memory::MemoryViewStreamWrite &parameters) override;
bool BlockingWrite(AuUInt64 offset, const Memory::MemoryViewStreamRead &parameters) override; bool BlockingWrite(AuUInt64 offset, const Memory::MemoryViewStreamRead &parameters) override;
void Init(const AuSPtr<FileHandle> &handle); void Init(const AuSPtr<IIOHandle> &pHandle);
AuSPtr<FileHandle> GetHandle(); AuSPtr<IIOHandle> GetHandle();
private: private:
AuSPtr<FileHandle> handle_; AuSPtr<IIOHandle> pHandle_;
}; };
struct NtAsyncFileTransaction : IAsyncTransaction, AuEnableSharedFromThis<NtAsyncFileTransaction> struct NtAsyncFileTransaction : IAsyncTransaction, AuEnableSharedFromThis<NtAsyncFileTransaction>
{ {
~NtAsyncFileTransaction(); ~NtAsyncFileTransaction();
bool Init(const AuSPtr<FileHandle> &handle); bool Init(const AuSPtr<IIOHandle> &handle);
bool InitWeak(const AuSPtr<IIOHandle> &handle);
void ResetAIO(); void ResetAIO();
bool StartRead(AuUInt64 offset, const AuSPtr<AuMemoryViewWrite> &memoryView) override; bool StartRead(AuUInt64 offset, const AuSPtr<AuMemoryViewWrite> &memoryView) override;
@ -78,7 +63,7 @@ namespace Aurora::IO::FS
void DispatchCb(AuUInt32 len); void DispatchCb(AuUInt32 len);
HANDLE GetHandle(); HANDLE GetHandle();
AuSPtr<FileHandle> GetFileHandle(); AuSPtr<IIOHandle> GetFileHandle();
OVERLAPPED overlap {}; OVERLAPPED overlap {};
HANDLE event = INVALID_HANDLE_VALUE; HANDLE event = INVALID_HANDLE_VALUE;
@ -94,7 +79,8 @@ namespace Aurora::IO::FS
AuSPtr<void> pMemoryHold; AuSPtr<void> pMemoryHold;
private: private:
AuSPtr<FileHandle> pHandle_; AuSPtr<IIOHandle> pHandle_;
AuWPtr<IIOHandle> wpHandle_;
AuSPtr<IAsyncFinishedSubscriber> pSub_; AuSPtr<IAsyncFinishedSubscriber> pSub_;
}; };
} }

View File

@ -14,17 +14,16 @@
namespace Aurora::IO::FS namespace Aurora::IO::FS
{ {
static const AuUInt64 kFileCopyBlock = 0xFFFF; // 64KiB, 1k iterations to max out 64MB/s disk, 2k iteration to make out 128MB/s disk, is this number still way too low? cpu go brr static const AuUInt64 kFileCopyBlock = 0xFFFF * 128;
WinFileStream::~WinFileStream() WinFileStream::~WinFileStream()
{ {
Close(); Close();
} }
void WinFileStream::Init(HANDLE handle, const AuString &path) void WinFileStream::Init(AuSPtr<IIOHandle> pHandle)
{ {
this->handle_ = handle; this->pHandle_ = pHandle;
this->path_ = path;
} }
AuUInt64 WinFileStream::GetOffset() AuUInt64 WinFileStream::GetOffset()
@ -32,16 +31,20 @@ namespace Aurora::IO::FS
LARGE_INTEGER distance {}; LARGE_INTEGER distance {};
LARGE_INTEGER pos {}; LARGE_INTEGER pos {};
if (this->handle_ == INVALID_HANDLE_VALUE) auto hHandle = this->GetHandle();
if (hHandle == INVALID_HANDLE_VALUE)
{ {
SysPushErrorUninitialized(); SysPushErrorUninitialized();
return 0; return 0;
} }
if (SetFilePointerEx(this->handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER) if (::SetFilePointerEx(hHandle,
distance,
&pos,
FILE_CURRENT) == INVALID_SET_FILE_POINTER)
{ {
AuLogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), this->pHandle_ ? this->pHandle_->GetPath() : "");
SysPushErrorIO();
return 0; return 0;
} }
@ -53,7 +56,9 @@ namespace Aurora::IO::FS
LARGE_INTEGER distance {}; LARGE_INTEGER distance {};
LARGE_INTEGER pos {}; LARGE_INTEGER pos {};
if (this->handle_ == INVALID_HANDLE_VALUE) auto hHandle = this->GetHandle();
if (hHandle == INVALID_HANDLE_VALUE)
{ {
SysPushErrorUninitialized(); SysPushErrorUninitialized();
return false; return false;
@ -61,10 +66,9 @@ namespace Aurora::IO::FS
distance.QuadPart = offset; distance.QuadPart = offset;
if (SetFilePointerEx(this->handle_, distance, &pos, FILE_BEGIN) == INVALID_SET_FILE_POINTER) if (::SetFilePointerEx(hHandle, distance, &pos, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{ {
AuLogWarn("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), path_); SysPushErrorIO("SetFilePointerEx IO Error: 0x{:x}, {}", GetLastError(), this->pHandle_ ? this->pHandle_->GetPath() : "");
SysPushErrorIO();
return false; return false;
} }
@ -74,14 +78,16 @@ namespace Aurora::IO::FS
AuUInt64 WinFileStream::GetLength() AuUInt64 WinFileStream::GetLength()
{ {
LARGE_INTEGER length; LARGE_INTEGER length;
auto hHandle = this->GetHandle();
if (handle_ == INVALID_HANDLE_VALUE) if (hHandle == INVALID_HANDLE_VALUE)
{ {
SysPushErrorUninitialized(); SysPushErrorUninitialized();
return 0; return 0;
} }
if (!GetFileSizeEx(this->handle_, &length)) if (!::GetFileSizeEx(hHandle, &length))
{ {
SysPushErrorIO(); SysPushErrorIO();
return 0; return 0;
@ -92,113 +98,218 @@ namespace Aurora::IO::FS
bool WinFileStream::Read(const Memory::MemoryViewStreamWrite &parameters) bool WinFileStream::Read(const Memory::MemoryViewStreamWrite &parameters)
{ {
if (this->handle_ == INVALID_HANDLE_VALUE) auto hHandle = this->GetHandle();
HANDLE hEventHandle { INVALID_HANDLE_VALUE };
if (hHandle == INVALID_HANDLE_VALUE)
{ {
SysPushErrorUninitialized(); SysPushErrorUninitialized();
return {}; return {};
} }
auto length = parameters.length; bool bIsAsync = this->pHandle_->IsAsync();
if (bIsAsync)
{
hEventHandle = ::CreateEventA(nullptr, false, false, nullptr);
}
parameters.outVariable = 0; parameters.outVariable = 0;
AuUInt64 offset {0};
while (length) AuUInt64 uLength = parameters.length;
AuUInt64 uOffset {};
while (uLength)
{ {
DWORD read; DWORD read;
int blockSize = AuMin(AuUInt(kFileCopyBlock), length); auto blockSize = AuMin(AuUInt(kFileCopyBlock), uLength);
if (!::ReadFile(this->handle_, reinterpret_cast<char *>(parameters.ptr) + offset, blockSize, &read, NULL)) if (this->pHandle_->IsAsync())
{ {
AuLogWarn("ReadFile IO Error: 0x{:x}, {}", GetLastError(), path_); OVERLAPPED overlapped {};
SysPushErrorIO(); overlapped.hEvent = hEventHandle;
return false;
if (!::ReadFile(hHandle,
reinterpret_cast<char *>(parameters.ptr) + uOffset,
blockSize,
NULL,
&overlapped) &&
::GetLastError() != ERROR_IO_PENDING)
{
SysPushErrorIO("ReadFile IO Error: 0x{:x}, {}", GetLastError(), this->pHandle_ ? this->pHandle_->GetPath() : "");
AuWin32CloseHandle(hEventHandle);
parameters.outVariable = uOffset;
return false;
}
::WaitForSingleObject(hEventHandle, 0);
if (!::GetOverlappedResult(hHandle, &overlapped, &read, true))
{
AuWin32CloseHandle(hEventHandle);
parameters.outVariable = uOffset;
return false;
}
::CloseHandle(hEventHandle);
} }
else
{
if (!::ReadFile(hHandle,
reinterpret_cast<char *>(parameters.ptr) + uOffset,
blockSize,
&read,
NULL))
{
SysPushErrorIO("ReadFile IO Error: 0x{:x}, {}", GetLastError(), this->pHandle_ ? this->pHandle_->GetPath() : "");
AuWin32CloseHandle(hEventHandle);
parameters.outVariable = uOffset;
return false;
}
}
if (read == 0) if (read == 0)
{ {
break; break;
} }
offset += read; uOffset += read;
length -= read; uLength -= read;
} }
parameters.outVariable = offset; AuWin32CloseHandle(hEventHandle);
parameters.outVariable = uOffset;
return true; return true;
} }
bool WinFileStream::Write(const Memory::MemoryViewStreamRead &parameters) bool WinFileStream::Write(const Memory::MemoryViewStreamRead &parameters)
{ {
if (this->handle_ == INVALID_HANDLE_VALUE) auto hHandle = this->GetHandle();
HANDLE hEventHandle { INVALID_HANDLE_VALUE };
if (hHandle == INVALID_HANDLE_VALUE)
{ {
SysPushErrorUninitialized(); SysPushErrorUninitialized();
return 0; return 0;
} }
auto length = parameters.length; bool bIsAsync = this->pHandle_->IsAsync();
if (bIsAsync)
{
hEventHandle = ::CreateEventA(nullptr, false, false, nullptr);
}
parameters.outVariable = 0; parameters.outVariable = 0;
AuUInt offset {0};
while (length) AuUInt64 uLength = parameters.length;
AuUInt64 uOffset {};
while (uLength)
{ {
DWORD written; DWORD written;
int blockSize = AuMin(AuUInt(kFileCopyBlock), length); auto uBlockSize = AuMin(AuUInt(kFileCopyBlock), uLength);
if (!::WriteFile(this->handle_, reinterpret_cast<const char *>(parameters.ptr) + offset, blockSize, &written, NULL)) if (this->pHandle_->IsAsync())
{ {
SysPushErrorIO("WriteFileEx IO Error: 0x{:x}, {}", GetLastError(), this->path_); OVERLAPPED overlapped {};
return false; overlapped.hEvent = hEventHandle;
if (!::WriteFile(hHandle,
reinterpret_cast<const char *>(parameters.ptr) + uOffset,
uBlockSize,
NULL,
&overlapped) &&
::GetLastError() != ERROR_IO_PENDING)
{
SysPushErrorIO("WriteFile IO Error: 0x{:x}, {}", GetLastError(), this->pHandle_ ? this->pHandle_->GetPath() : "");
AuWin32CloseHandle(hEventHandle);
parameters.outVariable = uOffset;
return false;
}
::WaitForSingleObject(hEventHandle, 0);
if (!::GetOverlappedResult(hHandle, &overlapped, &written, true))
{
AuWin32CloseHandle(hEventHandle);
parameters.outVariable = uOffset;
return false;
}
::CloseHandle(hEventHandle);
}
else
{
if (!::WriteFile(hHandle, reinterpret_cast<const char *>(parameters.ptr) + uOffset, uBlockSize, &written, NULL))
{
SysPushErrorIO("WriteFile IO Error: 0x{:x}, {}", GetLastError(), this->pHandle_ ? this->pHandle_->GetPath() : "");
AuWin32CloseHandle(hEventHandle);
parameters.outVariable = uOffset;
return false;
}
} }
if (!written) if (!written)
{ {
SysPushErrorIO(); SysPushErrorIO();
parameters.outVariable = offset; parameters.outVariable = uOffset;
AuWin32CloseHandle(hEventHandle);
return true; return true;
} }
offset += written; uOffset += written;
length -= written; uLength -= written;
} }
if (!offset) AuWin32CloseHandle(hEventHandle);
if (!uOffset)
{ {
return false; return false;
} }
parameters.outVariable = offset; parameters.outVariable = uOffset;
return true; return true;
} }
void WinFileStream::WriteEoS() void WinFileStream::WriteEoS()
{ {
if (this->handle_ == INVALID_HANDLE_VALUE) auto hHandle = this->GetHandle();
if (hHandle == INVALID_HANDLE_VALUE)
{ {
SysPushErrorUninitialized(); SysPushErrorUninitialized();
return; return;
} }
SetEndOfFile(this->handle_); SetEndOfFile(hHandle);
} }
void WinFileStream::Close() void WinFileStream::Close()
{ {
if ((this->handle_ != INVALID_HANDLE_VALUE) && auto hHandle = this->GetHandle();
if ((hHandle != INVALID_HANDLE_VALUE) &&
(this->bShouldDelete)) (this->bShouldDelete))
{ {
FILE_DISPOSITION_INFO rm {}; FILE_DISPOSITION_INFO rm {};
rm.DeleteFile = true; rm.DeleteFile = true;
if (!(pSetFileInformationByHandle && pSetFileInformationByHandle(this->handle_, _FILE_INFO_BY_HANDLE_CLASS::FileDispositionInfo, &rm, sizeof(rm)))) if (!(pSetFileInformationByHandle &&
pSetFileInformationByHandle(hHandle, _FILE_INFO_BY_HANDLE_CLASS::FileDispositionInfo, &rm, sizeof(rm))))
{ {
SysPushErrorIO("Couldn't delete temporary file {}", this->path_); SysPushErrorIO("Couldn't delete temporary file {}", this->pHandle_ ? this->pHandle_->GetPath() : "");
} }
} }
AuWin32CloseHandle(this->handle_);
AuResetMember(this->pHandle_);
} }
void WinFileStream::Flush() void WinFileStream::Flush()
{ {
FlushFileBuffers(this->handle_); auto hHandle = this->GetHandle();
::FlushFileBuffers(hHandle);
} }
void WinFileStream::MakeTemporary() void WinFileStream::MakeTemporary()
@ -208,104 +319,57 @@ namespace Aurora::IO::FS
HANDLE WinFileStream::GetHandle() HANDLE WinFileStream::GetHandle()
{ {
return this->handle_; return this->pHandle_ ?
(HANDLE)this->pHandle_->GetOSWriteHandleSafe().ValueOr(this->pHandle_->GetOSReadHandleSafe().ValueOr((AuUInt)INVALID_HANDLE_VALUE)) :
INVALID_HANDLE_VALUE;
} }
static IFileStream *OpenNewEx(const AuString &path, EFileOpenMode openMode, EFileAdvisoryLockLevel lock, bool bCheck) AUKN_SYM AuSPtr<IFileStream> OpenBlockingFileStreamFromHandle(AuSPtr<IIOHandle> pIOHandle)
{
auto pStream = AuMakeShared<WinFileStream>();
if (!pStream)
{
return nullptr;
}
pStream->Init(pIOHandle);
return pStream;
}
static IFileStream *OpenNewEx(const AuString &path,
EFileOpenMode openMode,
EFileAdvisoryLockLevel lock,
bool bCheck)
{ {
try try
{ {
auto pathex = NormalizePathRet(path); auto pHandle = AuIO::IOHandleShared();
if (pathex.empty()) if (!pHandle)
{
SysPushErrorMemory();
return nullptr;
}
AuIO::IIOHandle::HandleCreate createhandle(path);
createhandle.eAdvisoryLevel = lock;
createhandle.eMode = openMode;
createhandle.bFailIfNonEmptyFile = bCheck;
createhandle.bDirectIOMode = false;
createhandle.bAsyncHandle = false;
if (!pHandle->InitFromPath(createhandle))
{ {
return nullptr; return nullptr;
} }
auto win32Path = Locale::ConvertFromUTF8(pathex); auto pStream = _new WinFileStream();
if (win32Path.empty()) if (!pStream)
{ {
return nullptr; return nullptr;
} }
HANDLE fileHandle; pStream->Init(pHandle);
return pStream;
fileHandle = INVALID_HANDLE_VALUE;
auto dwShare = NtLockAdvisoryToShare(lock);
switch (openMode)
{
case EFileOpenMode::eRead:
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
case EFileOpenMode::eReadWrite:
{
CreateDirectories(pathex, true);
if (bCheck)
{
fileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
NULL,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
else
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ | DELETE, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ | DELETE, dwShare, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
}
}
break;
}
case EFileOpenMode::eWrite:
{
CreateDirectories(pathex, true);
if (bCheck)
{
fileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | DELETE,
NULL,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
else
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES | DELETE, dwShare, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE | DELETE, dwShare, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
}
}
break;
}
}
if (fileHandle == INVALID_HANDLE_VALUE)
{
SysPushErrorIO("Invalid filepath, couldn't open: {}", path);
return nullptr;
}
auto stream = _new WinFileStream();
if (!stream)
{
CloseHandle(fileHandle);
return nullptr;
}
stream->Init(fileHandle, pathex);
return stream;
} }
catch (...) catch (...)
{ {

View File

@ -15,7 +15,7 @@ namespace Aurora::IO::FS
{ {
~WinFileStream(); ~WinFileStream();
void Init(HANDLE handle, const AuString &path); void Init(AuSPtr<IIOHandle> pHandle);
AuUInt64 GetOffset() override; AuUInt64 GetOffset() override;
bool SetOffset(AuUInt64 offset) override; bool SetOffset(AuUInt64 offset) override;
@ -28,11 +28,11 @@ namespace Aurora::IO::FS
void MakeTemporary() override; void MakeTemporary() override;
HANDLE GetHandle(); HANDLE GetHandle();
private:
private:
AuSPtr<IIOHandle> pHandle_;
bool bShouldDelete {}; bool bShouldDelete {};
HANDLE handle_ = INVALID_HANDLE_VALUE; HANDLE hEventHandle_ { INVALID_HANDLE_VALUE };
AuString path_;
}; };
} }
#endif #endif

View File

@ -88,12 +88,15 @@ namespace Aurora::IO::IPC
if (serverHandle != INVALID_HANDLE_VALUE) if (serverHandle != INVALID_HANDLE_VALUE)
{ {
this->hasClient_ = Loop::NewLSEvent(false, false, true); this->hasClient_ = Loop::NewLSEvent(false, false, true);
SysAssert(this->hasClient_);
} }
this->fsHandle_ = AuMakeShared<IO::FS::FileHandle>(); this->fsHandle_ = AuIO::IOHandleShared();
this->fsStream_ = AuMakeShared<IO::FS::NtAsyncFileStream>(); SysAssert(this->fsHandle_);
this->fsHandle_->Init(this->GetPipeHandle(), this->GetPipeHandle()); this->fsStream_ = AuMakeSharedPanic<IO::FS::NtAsyncFileStream>();
this->fsHandle_->InitFromMove((AuUInt)this->GetPipeHandle());
this->fsStream_->Init(this->fsHandle_); this->fsStream_->Init(this->fsHandle_);
TryConnect(); TryConnect();

View File

@ -49,7 +49,7 @@ namespace Aurora::IO::IPC
private: private:
HANDLE serverHandle_ {INVALID_HANDLE_VALUE}; HANDLE serverHandle_ {INVALID_HANDLE_VALUE};
IPCHandle ipcHandle_; IPCHandle ipcHandle_;
AuSPtr<IO::FS::FileHandle> fsHandle_; AuSPtr<IO::IIOHandle> fsHandle_;
AuSPtr<IO::FS::NtAsyncFileStream> fsStream_; AuSPtr<IO::FS::NtAsyncFileStream> fsStream_;
AuSPtr<IPCHasConnectionEvent> lshasConnection_; AuSPtr<IPCHasConnectionEvent> lshasConnection_;
bool bFirstTime {true}; bool bFirstTime {true};

View File

@ -14,6 +14,8 @@
#include "AuNetSocketServer.hpp" #include "AuNetSocketServer.hpp"
#include "AuNetInterface.hpp" #include "AuNetInterface.hpp"
#include "../AuIOHandle.hpp"
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
#include "AuNetStream.NT.hpp" #include "AuNetStream.NT.hpp"
#endif #endif
@ -40,7 +42,7 @@ namespace Aurora::IO::Net
{ {
this->pWorker_->AddSocket(this); this->pWorker_->AddSocket(this);
this->osHandleOwner_ = AuMakeShared<AuFS::FileHandle>(); this->osHandleOwner_ = AuIO::IOHandleShared();
if (!this->osHandle_) if (!this->osHandle_)
{ {
return; return;
@ -48,10 +50,11 @@ namespace Aurora::IO::Net
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
//this->osHandleOwner_->Init((HANDLE)this->osHandle_, (HANDLE)this->osHandle_); //this->osHandleOwner_->InitFromPairMove((HANDLE)this->osHandle_, (HANDLE)this->osHandle_);
#else #else
this->osHandleOwner_->Init((int)this->osHandle_, (int)this->osHandle_); this->osHandleOwner_->InitFromPairMove((int)this->osHandle_, (int)this->osHandle_);
#endif #endif
} }
SocketBase::SocketBase(struct NetInterface *pInterface, SocketBase::SocketBase(struct NetInterface *pInterface,
@ -65,7 +68,7 @@ namespace Aurora::IO::Net
pSocketDriver_(pSocketDriver), pSocketDriver_(pSocketDriver),
remoteEndpoint_(endpoint) remoteEndpoint_(endpoint)
{ {
this->osHandleOwner_ = AuMakeShared<AuFS::FileHandle>(); this->osHandleOwner_ = AuIO::IOHandleShared();
if (!this->osHandle_) if (!this->osHandle_)
{ {
return; return;
@ -102,7 +105,8 @@ namespace Aurora::IO::Net
this->connectMany_.protocol = eProtocol; this->connectMany_.protocol = eProtocol;
} }
this->osHandleOwner_ = AuMakeShared<AuFS::FileHandle>(); this->osHandleOwner_ = AuIO::IOHandleShared();
if (!this->osHandle_) if (!this->osHandle_)
{ {
return; return;
@ -126,7 +130,8 @@ namespace Aurora::IO::Net
{ {
this->connectMany_.pDriver.reset(); this->connectMany_.pDriver.reset();
this->osHandleOwner_ = AuMakeShared<AuFS::FileHandle>(); this->osHandleOwner_ = AuIO::IOHandleShared();
if (!this->osHandle_) if (!this->osHandle_)
{ {
return; return;
@ -490,7 +495,7 @@ namespace Aurora::IO::Net
{ {
if (this->osHandleOwner_) if (this->osHandleOwner_)
{ {
this->osHandleOwner_->bWriteLock = true; AuStaticCast<AFileHandle>(this->osHandleOwner_)->uOSWriteHandle.Reset();
} }
} }

View File

@ -137,7 +137,7 @@ namespace Aurora::IO::Net
NetInterface *pInterface_; NetInterface *pInterface_;
SocketChannel socketChannel_; SocketChannel socketChannel_;
AuSPtr<ISocketDriver> pSocketDriver_; AuSPtr<ISocketDriver> pSocketDriver_;
AuSPtr<FS::FileHandle> osHandleOwner_; AuSPtr<IIOHandle> osHandleOwner_;
NetError error_; NetError error_;

View File

@ -243,8 +243,6 @@ namespace Aurora::IO::Net
auto er = WSAGetLastError(); auto er = WSAGetLastError();
if (bReturnValue) if (bReturnValue)
{ {
::SetEvent(this->GetAlertable());
this->DispatchCb(this->dwLastAbstractStat);
return true; return true;
} }
else if (er == ERROR_IO_PENDING) else if (er == ERROR_IO_PENDING)
@ -276,6 +274,7 @@ namespace Aurora::IO::Net
} }
this->pMemoryHold.reset(); this->pMemoryHold.reset();
this->pPin.reset();
return true; return true;
} }
else else

View File

@ -371,7 +371,7 @@ namespace Aurora::Processes
if (this->startup_.fwdIn == EStreamForward::eAsyncPipe || this->startup_.fwdOut == EStreamForward::eAsyncPipe) if (this->startup_.fwdIn == EStreamForward::eAsyncPipe || this->startup_.fwdOut == EStreamForward::eAsyncPipe)
{ {
this->fsHandle_ = AuMakeShared<IO::FS::FileHandle>(); this->fsHandle_ = AuIO::IOHandleShared();
if (!this->fsHandle_) if (!this->fsHandle_)
{ {
return false; return false;
@ -383,13 +383,13 @@ namespace Aurora::Processes
return false; return false;
} }
this->fsHandle_->Init(this->pipeStdOutRead_, this->pipeStdInWrite_); this->fsHandle_->InitFromPairMove((AuUInt64)this->pipeStdOutRead_, (AuUInt64)this->pipeStdInWrite_);
this->fsStream_->Init(this->fsHandle_); this->fsStream_->Init(this->fsHandle_);
} }
if (this->startup_.fwdErr == EStreamForward::eAsyncPipe) if (this->startup_.fwdErr == EStreamForward::eAsyncPipe)
{ {
this->fsErrorHandle_ = AuMakeShared<IO::FS::FileHandle>(); this->fsErrorHandle_ = AuIO::IOHandleShared();
if (!this->fsErrorHandle_) if (!this->fsErrorHandle_)
{ {
return false; return false;
@ -401,7 +401,7 @@ namespace Aurora::Processes
return false; return false;
} }
this->fsErrorHandle_->Init(this->pipeStdErrRead_, INVALID_HANDLE_VALUE); this->fsErrorHandle_->InitFromPairMove((AuUInt64)this->pipeStdErrRead_, {});
this->fsErrorStream_->Init(this->fsErrorHandle_); this->fsErrorStream_->Init(this->fsErrorHandle_);
} }

View File

@ -59,10 +59,10 @@ namespace Aurora::Processes
AuSPtr<AuLoop::ILoopSource> loopSource_; AuSPtr<AuLoop::ILoopSource> loopSource_;
AuSPtr<IO::FS::FileHandle> fsHandle_; AuSPtr<IO::IIOHandle> fsHandle_;
AuSPtr<IO::FS::NtAsyncFileStream> fsStream_; AuSPtr<IO::FS::NtAsyncFileStream> fsStream_;
AuSPtr<IO::FS::FileHandle> fsErrorHandle_; AuSPtr<IO::IIOHandle> fsErrorHandle_;
AuSPtr<IO::FS::NtAsyncFileStream> fsErrorStream_; AuSPtr<IO::FS::NtAsyncFileStream> fsErrorStream_;
StartupParmaters startup_; StartupParmaters startup_;