[*] Preemptive GetOverlappedResult fast-paths under WaitMultiple2 that rely on the alertable yield under next read/write cannot be trusted if the read count is zero.

Direct IO-specific quirk?
Windows 7 specific quirk?
Direct IO under Win7 specific quirk?
idk, but this fixes it
This commit is contained in:
Reece Wilson 2023-04-26 07:24:17 +01:00
parent 22c4d25759
commit 30b0c2e0ba
4 changed files with 32 additions and 13 deletions

View File

@ -279,6 +279,14 @@ namespace Aurora::IO::FS
this->overlap.hEvent = this->event = CreateEventW(nullptr, true, false, nullptr);
return this->overlap.hEvent != INVALID_HANDLE_VALUE;
}
void NtAsyncFileTransaction::ResetAIO()
{
auto hEvent = this->overlap.hEvent;
AuResetMember(this->overlap);
this->overlap.hEvent = hEvent;
}
static bool TranslateNtStatus(NtAsyncFileTransaction *that, BOOL val)
{
auto er = GetLastError();
@ -347,12 +355,9 @@ namespace Aurora::IO::FS
bool NtAsyncFileTransaction::IDontWannaUsePorts()
{
// TODO: maybe we could use a semaphore counter of read attempts
// to allow APC callbacks to drag behind
if (AuExchange(this->pPin, AuSharedFromThis()))
{
while (SleepEx(100, true) == WAIT_IO_COMPLETION)
while (SleepEx(0, true) == WAIT_IO_COMPLETION)
{
}
@ -407,6 +412,7 @@ namespace Aurora::IO::FS
this->dwLastAbstractOffset = offset;
this->dwLastBytes = 0;
this->ResetAIO();
this->overlap.Offset = AuBitsToLower(offset);
this->overlap.OffsetHigh = AuBitsToHigher(offset);
@ -453,7 +459,8 @@ namespace Aurora::IO::FS
this->dwLastBytes = 0;
this->dwLastAbstractStat = memoryView->length;
this->dwLastAbstractOffset = offset;
this->ResetAIO();
this->overlap.Offset = AuBitsToLower(offset);
this->overlap.OffsetHigh = AuBitsToHigher(offset);
auto ret = ::WriteFileEx(this->pHandle_->writeHandle, memoryView->ptr, memoryView->length, &this->overlap, FileOperationCompletion);
@ -533,10 +540,10 @@ namespace Aurora::IO::FS
if (::GetOverlappedResult(this->pHandle_->handle,
&this->overlap,
&read,
false))
false) && read)
{
DispatchCb(read);
return read;
return true;
}
}
else

View File

@ -51,6 +51,7 @@ namespace Aurora::IO::FS
~NtAsyncFileTransaction();
bool Init(const AuSPtr<FileHandle> &handle);
void ResetAIO();
bool StartRead(AuUInt64 offset, const AuSPtr<AuMemoryViewWrite> &memoryView) override;
bool StartWrite(AuUInt64 offset, const AuSPtr<AuMemoryViewRead> &memoryView) override;

View File

@ -300,10 +300,15 @@ namespace Aurora::IO::Net
return true;
}
if (::GetOverlappedResult((HANDLE)this->GetSocket(), &this->overlap, &read, false))
if (!this->pMemoryHold)
{
return false;
}
if (::GetOverlappedResult((HANDLE)this->GetSocket(), &this->overlap, &read, false) && read)
{
DispatchCb(read);
return read;
return true;
}
}
else
@ -397,7 +402,7 @@ namespace Aurora::IO::Net
{
if (AuExchange(this->pPin, AuSharedFromThis()))
{
while (SleepEx(100, true) == WAIT_IO_COMPLETION)
while (SleepEx(0, true) == WAIT_IO_COMPLETION)
{
}

View File

@ -52,14 +52,18 @@ namespace Aurora::IO
{
return {};
}
AuDebug::AddMemoryCrunch();
retTransasctions.reserve(transactions.size());
AuTryReserve(retTransasctions, transactions.size());
for (const auto &file : transactions)
{
AuTryInsert(handles, AuStaticPointerCast<FS::NtAsyncFileTransaction>(file)->GetHandle());
SysAssert(AuTryInsert(handles, AuStaticPointerCast<FS::NtAsyncFileTransaction>(file)->GetHandle()));
}
AuDebug::DecMemoryCrunch();
auto ret = WaitForMultipleObjectsEx(handles.size(), handles.data(), false, timeoutMs ? timeoutMs : INFINITE, TRUE);
if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED)
@ -71,7 +75,9 @@ namespace Aurora::IO
{
if (AuStaticPointerCast<FS::NtAsyncFileTransaction>(file)->Complete())
{
AuTryInsert(retTransasctions, file);
AuDebug::AddMemoryCrunch();
SysAssert(AuTryInsert(retTransasctions, file));
AuDebug::DecMemoryCrunch();
}
}