[+] Possible NT async file io implementation
This commit is contained in:
parent
2b4517352c
commit
2382f75759
@ -34,10 +34,12 @@ namespace Aurora::IO::FS
|
|||||||
|
|
||||||
virtual void SetCallback(const AuSPtr<IAsyncFinishedSubscriber> &sub) = 0;
|
virtual void SetCallback(const AuSPtr<IAsyncFinishedSubscriber> &sub) = 0;
|
||||||
|
|
||||||
virtual void Wait(AuUInt32 timeout) = 0;
|
virtual bool Wait(AuUInt32 timeout) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
AUKN_SHARED_API(OpenAsync, IAsyncFileStream, const AuString &path, bool readOnly = true, bool directIO = false);
|
AUKN_SHARED_API(OpenAsync, IAsyncFileStream, const AuString &path, bool readOnly = true, bool directIO = false);
|
||||||
|
|
||||||
AUKN_SYM bool WaitMultiple(const AuList<IAsyncTransaction> &files, AuUInt32 timeout);
|
/// \param transactions Array of FIO transactions
|
||||||
|
/// \param timeout Aurora Timeout
|
||||||
|
AUKN_SYM bool WaitMultiple(const AuList<AuSPtr<IAsyncTransaction>> &transactions, AuUInt32 timeout);
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ namespace Aurora::Loop
|
|||||||
eSourceMutex,
|
eSourceMutex,
|
||||||
eSourceSRW,
|
eSourceSRW,
|
||||||
eSourceTimer,
|
eSourceTimer,
|
||||||
|
eSourceAIO,
|
||||||
eSourceHandle,
|
eSourceHandle,
|
||||||
|
|
||||||
// Specific to the runtime subsystem
|
// Specific to the runtime subsystem
|
||||||
@ -77,17 +78,17 @@ namespace Aurora::Loop
|
|||||||
virtual void UpdateTime(AuUInt64 absTimeMs) = 0;
|
virtual void UpdateTime(AuUInt64 absTimeMs) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
AUKN_SYM AuSPtr<IConditionVar> NewLSCondVar(const AuSPtr<Aurora::Threading::> &primitive);
|
AUKN_SYM AuSPtr<IConditionVar> NewLSCondVar(const AuSPtr<Aurora::Threading::IWaitable> &primitive);
|
||||||
AUKN_SYM AuSPtr<IConditionVar> NewLSCondVar(const AuSPtr<ILSMutex> &source);
|
AUKN_SYM AuSPtr<IConditionVar> NewLSCondVar(const AuSPtr<ILSMutex> &source);
|
||||||
|
|
||||||
AUKN_SYM AuSPtr<ITimer> NewLSTimer(AuUInt64 absTimeMs);
|
AUKN_SYM AuSPtr<ITimer> NewLSTimer(AuUInt64 absTimeMs);
|
||||||
AUKN_SYM AuSPtr<ILSMutex> NewLSMutex();
|
AUKN_SYM AuSPtr<ILSMutex> NewLSMutex();
|
||||||
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent(bool triggerd = false, bool atomicRelease = true, bool permitMultipleTriggers = false);
|
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent(bool triggerd = false, bool atomicRelease = true, bool permitMultipleTriggers = false);
|
||||||
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphore(AuUInt32 initialCount = 0);
|
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphore(AuUInt32 initialCount = 0);
|
||||||
|
AUKN_SYM AuSPtr<ILoopSource> NewLSOSHandle(AuUInt);
|
||||||
AUKN_SYM AuSPtr<ILoopSource> NewLSAsync();
|
AUKN_SYM AuSPtr<ILoopSource> NewLSAsync();
|
||||||
AUKN_SYM AuSPtr<ILoopSource> NewLSWin32Source();
|
AUKN_SYM AuSPtr<ILoopSource> NewLSWin32Source();
|
||||||
AUKN_SYM AuSPtr<ILoopSource> NewLSAppleSource();
|
AUKN_SYM AuSPtr<ILoopSource> NewLSAppleSource();
|
||||||
AUKN_SYM AuSPtr<ILoopSource> NewLSOSHandle(AuUInt);
|
|
||||||
|
|
||||||
#if defined(X_PROTOCOL)
|
#if defined(X_PROTOCOL)
|
||||||
static AuSPtr<ILoopSource> NewLSX11(Display *display)
|
static AuSPtr<ILoopSource> NewLSX11(Display *display)
|
||||||
@ -106,7 +107,7 @@ namespace Aurora::Loop
|
|||||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||||
static AuSPtr<ILoopSource> NewLSHandle(HANDLE handle)
|
static AuSPtr<ILoopSource> NewLSHandle(HANDLE handle)
|
||||||
{
|
{
|
||||||
return NewLSOSHandle(static_cast<AuUInt>(handle));
|
return NewLSOSHandle(reinterpret_cast<AuUInt>(handle));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
@ -58,6 +58,7 @@
|
|||||||
#include "Threading/Threading.hpp"
|
#include "Threading/Threading.hpp"
|
||||||
#include "Async/Async.hpp"
|
#include "Async/Async.hpp"
|
||||||
#include "Time/Time.hpp"
|
#include "Time/Time.hpp"
|
||||||
|
#include "Loop/Loop.hpp"
|
||||||
|
|
||||||
#include "../AuroraUtils.hpp"
|
#include "../AuroraUtils.hpp"
|
||||||
|
|
||||||
|
@ -14,7 +14,14 @@
|
|||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
static inline AuSPtr<T> AuMakeShared(Args... args)
|
static inline AuSPtr<T> AuMakeShared(Args... args)
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
return AURORA_RUNTIME_MAKE_SHARED<T>(args...);
|
return AURORA_RUNTIME_MAKE_SHARED<T>(args...);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(AURORA_RUNTIME_MAKE_PAIR)
|
#if !defined(AURORA_RUNTIME_MAKE_PAIR)
|
||||||
@ -475,7 +482,20 @@ struct is_base_of_template_impl_au
|
|||||||
template < template <typename...> class base,typename derived>
|
template < template <typename...> class base,typename derived>
|
||||||
using AuIsBaseOfTemplate = typename is_base_of_template_impl_au<base,derived>::type;
|
using AuIsBaseOfTemplate = typename is_base_of_template_impl_au<base,derived>::type;
|
||||||
|
|
||||||
static inline bool AuTestBit(AuUInt32 value, AuUInt8 idx)
|
template<typename T>
|
||||||
|
static inline bool AuTestBit(T value, AuUInt8 idx)
|
||||||
{
|
{
|
||||||
return value & (1 << idx);
|
return value & (T(1) << T(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline void AuSetBit(T &value, AuUInt8 idx)
|
||||||
|
{
|
||||||
|
value |= T(1) << T(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline void AuClearBit(T &value, AuUInt8 idx)
|
||||||
|
{
|
||||||
|
value &= ~(T(1) << T(idx));
|
||||||
}
|
}
|
@ -451,9 +451,11 @@ namespace Aurora::HWInfo
|
|||||||
gCpuInfo.threads = opt.value_or(1)
|
gCpuInfo.threads = opt.value_or(1)
|
||||||
|
|
||||||
#elif defined(AURORA_IS_POSIX_DERIVED)
|
#elif defined(AURORA_IS_POSIX_DERIVED)
|
||||||
|
|
||||||
gCpuInfo.socket = 1;
|
gCpuInfo.socket = 1;
|
||||||
gCpuInfo.cores = 1;
|
gCpuInfo.cores = 1;
|
||||||
gCpuInfo.threads = sysconf(_SC_NPROCESSORS_ONLN);
|
gCpuInfo.threads = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
namespace Aurora::HWInfo
|
namespace Aurora::HWInfo
|
||||||
{
|
{
|
||||||
static AuOptional<RamStat> gMemStartup;
|
static AuOptional<RamStat> gMemStartup;
|
||||||
static AuOptional<RamStat> gMemSystem;
|
|
||||||
|
|
||||||
AUKN_SYM AuOptional<RamStat> GetMemStatProcess()
|
AUKN_SYM AuOptional<RamStat> GetMemStatProcess()
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,295 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: Async.NT.cpp
|
||||||
|
Date: 2021-9-13
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#include <RuntimeInternal.hpp>
|
||||||
|
#include "FS.hpp"
|
||||||
|
#include "Async.NT.hpp"
|
||||||
|
|
||||||
|
namespace Aurora::IO::FS
|
||||||
|
{
|
||||||
|
struct FileHandle
|
||||||
|
{
|
||||||
|
~FileHandle();
|
||||||
|
|
||||||
|
bool Init(const AuString &path, bool readOnly, bool directIO);
|
||||||
|
|
||||||
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||||
|
AuString path;
|
||||||
|
bool readOnly;
|
||||||
|
bool directIO;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NtAsyncFileStream : public IAsyncFileStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AuSPtr<IAsyncTransaction> NewTransaction() override;
|
||||||
|
|
||||||
|
void Init(const AuSPtr<FileHandle> &handle);
|
||||||
|
|
||||||
|
AuSPtr<FileHandle> GetHandle();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AuSPtr<FileHandle> handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NtAsyncFileTransaction : public IAsyncTransaction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~NtAsyncFileTransaction();
|
||||||
|
|
||||||
|
bool Init(const AuSPtr<FileHandle> &handle);
|
||||||
|
|
||||||
|
bool StartRead(AuUInt64 offset, void *, AuUInt32 length) override;
|
||||||
|
bool StartWrite(AuUInt64 offset, const void *, AuUInt32 length) override;
|
||||||
|
|
||||||
|
bool Complete() override;
|
||||||
|
AuUInt32 GetLastPacketLength() override;
|
||||||
|
|
||||||
|
void SetCallback(const AuSPtr<IAsyncFinishedSubscriber> &sub) override;
|
||||||
|
|
||||||
|
bool Wait(AuUInt32 timeout) override;
|
||||||
|
|
||||||
|
void DispatchCb();
|
||||||
|
|
||||||
|
HANDLE GetHandle();
|
||||||
|
AuSPtr<FileHandle> GetFileHandle();
|
||||||
|
private:
|
||||||
|
AuSPtr<FileHandle> handle_;
|
||||||
|
HANDLE event_ = INVALID_HANDLE_VALUE;
|
||||||
|
OVERLAPPED overlap_ {};
|
||||||
|
AuUInt32 lastAbstractStat_ {}, lastAbstractOffset_ {};
|
||||||
|
bool latch_ {};
|
||||||
|
AuSPtr<IAsyncFinishedSubscriber> sub_;
|
||||||
|
};
|
||||||
|
|
||||||
|
AuSPtr<FileHandle> NtAsyncFileTransaction::GetFileHandle()
|
||||||
|
{
|
||||||
|
return this->handle_;
|
||||||
|
}
|
||||||
|
|
||||||
|
NtAsyncFileTransaction::~NtAsyncFileTransaction()
|
||||||
|
{
|
||||||
|
AuWin32CloseHandle(this->event_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileHandle::~FileHandle()
|
||||||
|
{
|
||||||
|
AuWin32CloseHandle(this->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileHandle::Init(const AuString &path, bool readOnly, bool directIO)
|
||||||
|
{
|
||||||
|
HANDLE fileHandle;
|
||||||
|
|
||||||
|
auto pathex = NormalizePathRet(path);
|
||||||
|
auto win32Path = Locale::ConvertFromUTF8(pathex);
|
||||||
|
|
||||||
|
auto flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
|
||||||
|
|
||||||
|
if (directIO)
|
||||||
|
{
|
||||||
|
flags |= FILE_FLAG_NO_BUFFERING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readOnly)
|
||||||
|
{
|
||||||
|
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreateDirectories(pathex, true);
|
||||||
|
fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, flags, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
LogWarn("Missing file: {}", path);
|
||||||
|
SysPushErrorIO("Missing file: {}", path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
this->directIO = directIO;
|
||||||
|
this->handle = fileHandle;
|
||||||
|
this->readOnly = readOnly;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AuSPtr<FileHandle> NtAsyncFileStream::GetHandle()
|
||||||
|
{
|
||||||
|
return handle_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NtAsyncFileStream::Init(const AuSPtr<FileHandle> &handle)
|
||||||
|
{
|
||||||
|
this->handle_ = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuSPtr<IAsyncTransaction> NtAsyncFileStream::NewTransaction()
|
||||||
|
{
|
||||||
|
auto shared = AuMakeShared<NtAsyncFileTransaction>();
|
||||||
|
if (!shared)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shared->Init(this->handle_))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return shared;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NtAsyncFileTransaction::Init(const AuSPtr<FileHandle> &handle)
|
||||||
|
{
|
||||||
|
this->handle_ = handle;
|
||||||
|
this->overlap_.hEvent = this->event_ = CreateEvent(NULL, true, 0, NULL);
|
||||||
|
return this->overlap_.hEvent != INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool TranslateNtStatus(NtAsyncFileTransaction *that, BOOL val)
|
||||||
|
{
|
||||||
|
if ((val) ||
|
||||||
|
(!val && GetLastError() == ERROR_IO_PENDING))
|
||||||
|
{
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
that->DispatchCb();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SysPushErrorFIO("Async FIO error: {}", that->GetFileHandle()->path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NtAsyncFileTransaction::StartRead(AuUInt64 offset, void *buffer, AuUInt32 length)
|
||||||
|
{
|
||||||
|
this->latch_ = {};
|
||||||
|
this->lastAbstractStat_ = length;
|
||||||
|
this->lastAbstractOffset_ = offset;
|
||||||
|
this->overlap_.Offset = offset & 0xFFFFFFFF;
|
||||||
|
this->overlap_.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
|
||||||
|
auto ret = ::ReadFile(this->handle_->handle, buffer, length, NULL, &overlap_);
|
||||||
|
return TranslateNtStatus(this, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NtAsyncFileTransaction::StartWrite(AuUInt64 offset, const void *buffer, AuUInt32 length)
|
||||||
|
{
|
||||||
|
this->latch_ = {};
|
||||||
|
this->lastAbstractStat_ = length;
|
||||||
|
this->lastAbstractOffset_ = offset;
|
||||||
|
this->overlap_.Offset = offset & 0xFFFFFFFF;
|
||||||
|
this->overlap_.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
|
||||||
|
auto ret = ::WriteFile(this->handle_->handle, buffer, length, NULL, &overlap_);
|
||||||
|
return TranslateNtStatus(this, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NtAsyncFileTransaction::DispatchCb()
|
||||||
|
{
|
||||||
|
if (std::exchange(this->latch_, true))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->sub_)
|
||||||
|
{
|
||||||
|
DWORD read {};
|
||||||
|
GetOverlappedResult(this->handle_->handle, &this->overlap_, &read, false);
|
||||||
|
this->sub_->OnAsyncFileOpFinished(this->lastAbstractOffset_, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NtAsyncFileTransaction::Complete()
|
||||||
|
{
|
||||||
|
auto ret = WaitForSingleObject(this->event_, 0);
|
||||||
|
if (ret == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
DispatchCb();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuUInt32 NtAsyncFileTransaction::GetLastPacketLength()
|
||||||
|
{
|
||||||
|
DWORD read {};
|
||||||
|
GetOverlappedResult(this->handle_->handle, &this->overlap_, &read, false);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NtAsyncFileTransaction::SetCallback(const AuSPtr<IAsyncFinishedSubscriber> &sub)
|
||||||
|
{
|
||||||
|
this->sub_ = sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NtAsyncFileTransaction::Wait(AuUInt32 timeout)
|
||||||
|
{
|
||||||
|
auto ret = WaitForSingleObject(this->event_, timeout ? timeout : INFINITE);
|
||||||
|
if (ret == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
DispatchCb();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE NtAsyncFileTransaction::GetHandle()
|
||||||
|
{
|
||||||
|
return this->event_;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM IAsyncFileStream *OpenAsyncNew(const AuString &path, bool readOnly, bool directIO)
|
||||||
|
{
|
||||||
|
auto fileHandle = AuMakeShared<FileHandle>();
|
||||||
|
if (!fileHandle->Init(path, readOnly, directIO))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stream = _new NtAsyncFileStream();
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->Init(fileHandle);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM void OpenAsyncRelease(IAsyncFileStream *handle)
|
||||||
|
{
|
||||||
|
SafeDelete<NtAsyncFileStream *>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM bool WaitMultiple(const AuList<AuSPtr<IAsyncTransaction>> &files, AuUInt32 timeout)
|
||||||
|
{
|
||||||
|
AuList<HANDLE> handles;
|
||||||
|
|
||||||
|
if (files.empty())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto & file : files)
|
||||||
|
{
|
||||||
|
handles.push_back(std::static_pointer_cast<NtAsyncFileTransaction>(file)->GetHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ret = WaitForMultipleObjects(handles.size(), handles.data(), false, timeout ? timeout : INFINITE);
|
||||||
|
|
||||||
|
for (const auto &file : files)
|
||||||
|
{
|
||||||
|
std::static_pointer_cast<NtAsyncFileTransaction>(file)->Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret != WAIT_TIMEOUT && ret != WAIT_FAILED;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: Async.NT.hpp
|
||||||
|
Date: 2021-9-13
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::IO::FS
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user