[*] Thread-safety: harden io file streams and improve construction api of OpenBlockingFileStreamFromHandle

This commit is contained in:
Reece Wilson 2024-03-15 08:46:12 +00:00
parent ccc4116394
commit 25b1a9cad6
6 changed files with 77 additions and 23 deletions

View File

@ -9,7 +9,7 @@
namespace Aurora::IO::FS
{
// WARNING: there are no truncate write modes. IFileStream::WriteEoS must be called by the caller of Open[Write]s.
// WARNING: there are no truncate write modes. IFileStream::WriteEoS or IFileStream::SetWriteEoSOnClose must be called by the caller of `Open[Write]/Create`s.
AUKN_SHARED_API(Create, IFileStream, const AuString &path);
@ -19,5 +19,5 @@ namespace Aurora::IO::FS
AUKN_SHARED_API(Open, IFileStream, const AuString &path, EFileOpenMode mode = EFileOpenMode::eRead, EFileAdvisoryLockLevel successPostAdvisoryLevel = EFileAdvisoryLockLevel::eBlockReadWrite);
AUKN_SYM AuSPtr<IFileStream> OpenBlockingFileStreamFromHandle(AuSPtr<IIOHandle> pIOHandle);
AUKN_SHARED_API(OpenBlockingFileStreamFromHandle, IFileStream, const AuSPtr<IIOHandle> &pIOHandle);
}

View File

@ -9,7 +9,6 @@
namespace Aurora::IO::FS
{
// Thread-Local!
struct IFileStream
{
/**
@ -104,8 +103,14 @@ namespace Aurora::IO::FS
*/
virtual IO::IStreamWriter *ToStreamWriter() = 0;
/**
* @brief
*/
virtual IO::ISeekingReader *ToStreamSeekingReader() = 0;
/**
* @brief
*/
virtual IO::ISeekingWriter *ToStreamSeekingWriter() = 0;
AURT_ADD_USR_DATA;

View File

@ -38,6 +38,8 @@ namespace Aurora::IO::FS
AuUInt64 WinFileStream::GetOffset()
{
AU_LOCK_GUARD(this->mutex_);
LARGE_INTEGER distance {};
LARGE_INTEGER pos {};
HANDLE hHandle {};
@ -78,6 +80,8 @@ namespace Aurora::IO::FS
bool WinFileStream::SetOffset(AuUInt64 offset)
{
AU_LOCK_GUARD(this->mutex_);
LARGE_INTEGER distance {};
LARGE_INTEGER pos {};
HANDLE hHandle {};
@ -117,6 +121,8 @@ namespace Aurora::IO::FS
AuUInt64 WinFileStream::GetLength()
{
AU_LOCK_GUARD(this->mutex_);
LARGE_INTEGER length;
HANDLE hHandle {};
@ -153,6 +159,8 @@ namespace Aurora::IO::FS
bool WinFileStream::Read(const Memory::MemoryViewStreamWrite &parameters)
{
AU_LOCK_GUARD(this->mutex_);
OVERLAPPED overlapped {};
AuUInt64 uOffset {};
@ -270,6 +278,8 @@ namespace Aurora::IO::FS
bool WinFileStream::Write(const Memory::MemoryViewStreamRead &parameters)
{
AU_LOCK_GUARD(this->mutex_);
OVERLAPPED overlapped {};
AuUInt64 uOffset {};
@ -376,6 +386,8 @@ namespace Aurora::IO::FS
void WinFileStream::WriteEoS()
{
AU_LOCK_GUARD(this->mutex_);
auto hHandle = this->GetWin32Handle();
if (hHandle == INVALID_HANDLE_VALUE)
@ -389,6 +401,8 @@ namespace Aurora::IO::FS
void WinFileStream::Close()
{
AU_LOCK_GUARD(this->mutex_);
auto hHandle = this->GetWin32Handle();
bool bDeleteFailed {};
AuString path;
@ -444,6 +458,8 @@ namespace Aurora::IO::FS
bool WinFileStream::IsFlushOnClose() const
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
{
return pHandle->IsFlushOnClose();
@ -456,6 +472,8 @@ namespace Aurora::IO::FS
void WinFileStream::SetFlushOnClose(bool bFlushOnClose)
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
{
pHandle->SetFlushOnClose(bFlushOnClose);
@ -514,30 +532,40 @@ namespace Aurora::IO::FS
return INVALID_HANDLE_VALUE;
}
AUKN_SYM AuSPtr<IFileStream> OpenBlockingFileStreamFromHandle(AuSPtr<IIOHandle> pIOHandle)
AUKN_SYM IFileStream *OpenBlockingFileStreamFromHandleNew(const AuSPtr<IIOHandle> &pIOHandle)
{
SysCheckArgNotNull(pIOHandle, {});
auto pStream = AuMakeShared<WinFileStream>();
auto pStream = _new WinFileStream();
SysCheckNotNullMemory(pStream, {});
if (!AuStaticCast<AFileHandle>(pIOHandle)->pIPCPipe &&
AuStaticCast<AFileHandle>(pIOHandle)->ShouldClone())
{
auto pOld = pIOHandle;
pIOHandle = AuMakeShared<AFileHandle>();
SysCheckNotNullMemory(pIOHandle, {});
if (!pIOHandle->InitFromPair(pOld->GetOSReadHandleSafe(), pOld->GetOSWriteHandle()))
auto pIOHandle2 = AuMakeShared<AFileHandle>();
SysCheckNotNullMemory(pIOHandle2, {});
if (!pIOHandle2->InitFromPair(pIOHandle->GetOSReadHandleSafe(), pIOHandle->GetOSWriteHandle()))
{
SysPushErrorIOResourceFailure();
return {};
}
pStream->Init(pIOHandle2);
}
else
{
pStream->Init(pIOHandle);
}
pStream->Init(pIOHandle);
return pStream;
}
AUKN_SYM void OpenBlockingFileStreamFromHandleRelease(IFileStream *that)
{
AuSafeDelete<WinFileStream *>(that);
}
static IFileStream *OpenNewEx(const AuString &path,
EFileOpenMode openMode,
EFileAdvisoryLockLevel lock,

View File

@ -47,6 +47,7 @@ namespace Aurora::IO::FS
AuFS::FileWriter writer_;
AuFS::FileSeekableReader sreader_;
AuFS::FileSeekableWriter swriter_;
AuMutex mutex_;
};
}
#endif

View File

@ -47,7 +47,7 @@ namespace Aurora::IO::FS
AuUInt64 PosixFileStream::GetOffset()
{
AU_LOCK_GUARD(this->spinlock_);
AU_LOCK_GUARD(this->mutex_);
int fd {};
if (auto pHandle = this->pHandle_)
@ -79,7 +79,7 @@ namespace Aurora::IO::FS
bool PosixFileStream::SetOffset(AuUInt64 offset)
{
AU_LOCK_GUARD(this->spinlock_);
AU_LOCK_GUARD(this->mutex_);
int fd {};
if (auto pHandle = this->pHandle_)
@ -111,7 +111,7 @@ namespace Aurora::IO::FS
AuUInt64 PosixFileStream::GetLength()
{
AU_LOCK_GUARD(this->spinlock_);
AU_LOCK_GUARD(this->mutex_);
int fd {};
if (auto pHandle = this->pHandle_)
@ -147,7 +147,7 @@ namespace Aurora::IO::FS
bool PosixFileStream::Read(const Memory::MemoryViewStreamWrite &parameters)
{
AU_LOCK_GUARD(this->spinlock_);
AU_LOCK_GUARD(this->mutex_);
parameters.outVariable = 0;
@ -212,7 +212,7 @@ namespace Aurora::IO::FS
bool PosixFileStream::Write(const Memory::MemoryViewStreamRead &parameters)
{
AU_LOCK_GUARD(this->spinlock_);
AU_LOCK_GUARD(this->mutex_);
parameters.outVariable = 0;
@ -264,6 +264,8 @@ namespace Aurora::IO::FS
void PosixFileStream::Close()
{
AU_LOCK_GUARD(this->mutex_);
auto pHandle = this->pHandle_;
AuResetMember(this->pHandle_);
@ -283,6 +285,8 @@ namespace Aurora::IO::FS
bool PosixFileStream::IsFlushOnClose() const
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
{
return pHandle->IsFlushOnClose();
@ -295,6 +299,8 @@ namespace Aurora::IO::FS
void PosixFileStream::SetFlushOnClose(bool bFlushOnClose)
{
AU_LOCK_GUARD(this->mutex_);
if (auto pHandle = this->pHandle_)
{
pHandle->SetFlushOnClose(bFlushOnClose);
@ -313,6 +319,8 @@ namespace Aurora::IO::FS
void PosixFileStream::Flush()
{
AU_LOCK_GUARD(this->mutex_);
if (!this->pHandle_)
{
SysPushErrorUninitialized();
@ -331,6 +339,8 @@ namespace Aurora::IO::FS
void PosixFileStream::WriteEoS()
{
AU_LOCK_GUARD(this->mutex_);
if (!this->pHandle_)
{
SysPushErrorUninitialized();
@ -384,30 +394,40 @@ namespace Aurora::IO::FS
return &this->swriter_;
}
AUKN_SYM AuSPtr<IFileStream> OpenBlockingFileStreamFromHandle(AuSPtr<IIOHandle> pIOHandle)
AUKN_SYM IFileStream *OpenBlockingFileStreamFromHandleNew(const AuSPtr<IIOHandle> &pIOHandle)
{
SysCheckArgNotNull(pIOHandle, {});
auto pStream = AuMakeShared<PosixFileStream>();
auto pStream = _new PosixFileStream();
SysCheckNotNullMemory(pStream, {});
if (!AuStaticCast<AFileHandle>(pIOHandle)->pIPCPipe &&
AuStaticCast<AFileHandle>(pIOHandle)->ShouldClone())
{
auto pOld = pIOHandle;
pIOHandle = AuMakeShared<AFileHandle>();
SysCheckNotNullMemory(pIOHandle, {});
if (!pIOHandle->InitFromPair(pOld->GetOSReadHandleSafe(), pOld->GetOSWriteHandle()))
auto pIOHandle2 = AuMakeShared<AFileHandle>();
SysCheckNotNullMemory(pIOHandle2, {});
if (!pIOHandle2->InitFromPair(pIOHandle->GetOSReadHandleSafe(), pIOHandle->GetOSWriteHandle()))
{
SysPushErrorIOResourceFailure();
return {};
}
pStream->Init(pIOHandle2);
}
else
{
pStream->Init(pIOHandle);
}
pStream->Init(pIOHandle);
return pStream;
}
AUKN_SYM void OpenBlockingFileStreamFromHandleRelease(IFileStream *that)
{
AuSafeDelete<PosixFileStream *>(that);
}
static IFileStream *OpenNewEx(const AuString &path,
EFileOpenMode openMode,
EFileAdvisoryLockLevel lock,

View File

@ -42,7 +42,7 @@ namespace Aurora::IO::FS
private:
AuSPtr<IIOHandle> pHandle_;
AuString path_;
AuThreadPrimitives::SpinLock spinlock_;
AuMutex mutex_;
bool bMadeTemporary {}, bShouldWriteEoS {};
AuFS::FileReader reader_;
AuFS::FileWriter writer_;