使用 GetOverlappedResultEx 中的超时来模拟超时等待?
Using the timeout in GetOverlappedResultEx to simulate a wait with timeout?
当使用 GetOverlapedResult 获取重叠(即异步)I/O 操作的结果时,您可以请求 GetOverlappdResult 到 "wait":
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
这里要注意的部分是GetOverlappedResult
的最后一个参数:bWait
:
bWait
If this parameter is TRUE, and the Internal member of the lpOverlapped structure is STATUS_PENDING, the function does not return until the operation has been completed. If this parameter is FALSE and the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE.
对于我的代码,这意味着:
- 如果 I/O 快速完成,ReadFile returns true.
- 如果 I/O 仍然 待定 那么我 等待 完成
- 如果有其他错误,我会得到那个错误。
这一切都很好。
大多数情况下这一切都很好
我遇到一个问题,实际 ReadFile
操作需要 10 分钟 到 return .当它 return 时,它 returns:
The device is not ready (21)
这是一个众所周知的问题 one vendor's storage system.。
我想做的是使用 Windows 的 异步 功能来等待 - 但有超时。
我注意到 GetOverlappedResultEx,它有一种 timeout 参数:
BOOL GetOverlappedResultEx(
HANDLE hFile,
LPOVERLAPPED lpOverlapped,
LPDWORD lpNumberOfBytesTransferred,
DWORD dwMilliseconds, <----------
BOOL bAlertable
);
但是当我查看文档时,这是我了解 Windows 我不理解的编程细节的地方 - 排队的 APC,可变等待。但它仍然听起来像我想要的那样::
dwMilliseconds
The time-out interval, in milliseconds.
If dwMilliseconds is zero and the operation is still in progress, the
function returns immediately and the GetLastError function returns
ERROR_IO_INCOMPLETE.
If dwMilliseconds is nonzero and the operation is still in progress,
the function waits until the object is signaled, an I/O completion
routine or APC is queued, or the interval elapses before returning.
Use GetLastError to get extended error information.
If dwMilliseconds is INFINITE, the function returns only when the
object is signaled or an I/O completion routine or APC is queued.
所以我尝试改变我的功能:
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
//if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, False) //wait 5000 ms
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
除了对 GetOverlappedResultEx 的调用不会在 5 秒(5,000 毫秒)内 return。相反,存储子系统需要 10-20 分钟才能解决 return 故障。
所以我随机尝试一些东西
我看到 GetOverlappedResultsEx 的另一个参数:
`bAlertable`
If this parameter is **TRUE** and the calling thread is in the waiting state, the function returns when the system queues an I/O completion routine or APC. The calling thread then runs the routine or function. Otherwise, the function does not return, and the completion routine or APC function is not executed.
A completion routine is queued when the [ReadFileEx][5] or [WriteFileEx][5] function in which it was specified has completed. The function returns and the completion routine is called only if *bAlertable* is **TRUE**, and the calling thread is the thread that initiated the read or write operation. An APC is queued when you call [QueueUserAPC][5].
这听起来不像我的情况:
- 我没有使用
ReadFileEx
- 我不打电话
QueueUserAPC
但这并不能阻止我随机尝试并希望它们起作用:
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
//if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, False) //wait 5000 ms
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, True) //wait 5000 ms, alertable
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
但是没用。
所以我问 Whosebug
我可以使用 GetOverlappedResultEx
模拟同步 ReadFile
操作但 有 超时吗?
我确定我最终会遇到一个涉及消息传递计时器的漏洞黑客攻击(或者是线程计时器?还是可警报计时器?和事件?和我自己的事件?或者重叠的事件?)。但我宁愿使用 good 解决方案而不是 my 解决方案。
Can i simulate a synchronous ReadFile
operation but with a timeout,
using GetOverlappedResultEx
?
是的,你可以,就像你一样,已经尝试过了。这不是模拟。这将是完全同步的文件读取。因为同步读取 - 这是异步读取 + 在 I/O 完成时就地等待。所以代码可以是下一个:
ULONG ReadFileTimeout(HANDLE hFile,
PVOID lpBuffer,
ULONG nNumberOfBytesToRead,
PULONG lpNumberOfBytesRead,
PLARGE_INTEGER ByteOffset,
ULONG dwMilliseconds)
{
OVERLAPPED ov;
ov.Offset = ByteOffset->LowPart;
ov.OffsetHigh = ByteOffset->HighPart;
ULONG dwError = NOERROR;
if (ov.hEvent = CreateEvent(0, 0, 0, 0))
{
dwError = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, &ov) ? NOERROR : GetLastError();
if (dwError == ERROR_IO_PENDING)
{
dwError = GetOverlappedResultEx(0/*yes, not need hFile*/,
&ov, lpNumberOfBytesRead, dwMilliseconds, FALSE) ? NOERROR : GetLastError();
}
CloseHandle(ov.hEvent);
}
else
{
dwError = GetLastError();
}
return dwError;
}
请注意,您必须(在异步文件的情况下)始终显式使用字节偏移量,从那里读取数据。
GetOverlappedResultEx
通常下一步 - 检查 OVERLAPPED
- I/O 是否完整(只需将 Internal
与 STATUS_PENDING
进行比较),如果没有(仍然是 Internal == STATUS_PENDING
)并且你想要等待 - 它从 OVERLAPPED
调用 WaitForSingleObjectEx
和 hEvent
并转移 dwMilliseconds
和 bAlertable
。如果 hEvent
发出信号(WAIT_OBJECT_0
return 来自 WaitForSingleObjectEx
) GetOverlappedResultEx
决定 I/O 完成并且 return 来自 [=14] =], 否则相应错误 returned.
但万一 ReadFile
本身不是 return 控制和等待 - 这里不可能做某事。这意味着驱动程序开始等待您的线程。并且没有任何办法打破这个驱动程序等待。看起来这正是你的情况。当你使用异步文件时 - 驱动程序不能等待,但..有时(糟糕的驱动程序)这可能是
当使用 GetOverlapedResult 获取重叠(即异步)I/O 操作的结果时,您可以请求 GetOverlappdResult 到 "wait":
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
这里要注意的部分是GetOverlappedResult
的最后一个参数:bWait
:
bWait
If this parameter is TRUE, and the Internal member of the lpOverlapped structure is STATUS_PENDING, the function does not return until the operation has been completed. If this parameter is FALSE and the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE.
对于我的代码,这意味着:
- 如果 I/O 快速完成,ReadFile returns true.
- 如果 I/O 仍然 待定 那么我 等待 完成
- 如果有其他错误,我会得到那个错误。
这一切都很好。
大多数情况下这一切都很好
我遇到一个问题,实际 ReadFile
操作需要 10 分钟 到 return .当它 return 时,它 returns:
The device is not ready (21)
这是一个众所周知的问题 one vendor's storage system.。
我想做的是使用 Windows 的 异步 功能来等待 - 但有超时。
我注意到 GetOverlappedResultEx,它有一种 timeout 参数:
BOOL GetOverlappedResultEx(
HANDLE hFile,
LPOVERLAPPED lpOverlapped,
LPDWORD lpNumberOfBytesTransferred,
DWORD dwMilliseconds, <----------
BOOL bAlertable
);
但是当我查看文档时,这是我了解 Windows 我不理解的编程细节的地方 - 排队的 APC,可变等待。但它仍然听起来像我想要的那样::
dwMilliseconds
The time-out interval, in milliseconds.
If dwMilliseconds is zero and the operation is still in progress, the function returns immediately and the GetLastError function returns ERROR_IO_INCOMPLETE.
If dwMilliseconds is nonzero and the operation is still in progress, the function waits until the object is signaled, an I/O completion routine or APC is queued, or the interval elapses before returning. Use GetLastError to get extended error information.
If dwMilliseconds is INFINITE, the function returns only when the object is signaled or an I/O completion routine or APC is queued.
所以我尝试改变我的功能:
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
//if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, False) //wait 5000 ms
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
除了对 GetOverlappedResultEx 的调用不会在 5 秒(5,000 毫秒)内 return。相反,存储子系统需要 10-20 分钟才能解决 return 故障。
所以我随机尝试一些东西
我看到 GetOverlappedResultsEx 的另一个参数:
`bAlertable`
If this parameter is **TRUE** and the calling thread is in the waiting state, the function returns when the system queues an I/O completion routine or APC. The calling thread then runs the routine or function. Otherwise, the function does not return, and the completion routine or APC function is not executed.
A completion routine is queued when the [ReadFileEx][5] or [WriteFileEx][5] function in which it was specified has completed. The function returns and the completion routine is called only if *bAlertable* is **TRUE**, and the calling thread is the thread that initiated the read or write operation. An APC is queued when you call [QueueUserAPC][5].
这听起来不像我的情况:
- 我没有使用
ReadFileEx
- 我不打电话
QueueUserAPC
但这并不能阻止我随机尝试并希望它们起作用:
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
//if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, False) //wait 5000 ms
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, True) //wait 5000 ms, alertable
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
但是没用。
所以我问 Whosebug
我可以使用 GetOverlappedResultEx
模拟同步 ReadFile
操作但 有 超时吗?
我确定我最终会遇到一个涉及消息传递计时器的漏洞黑客攻击(或者是线程计时器?还是可警报计时器?和事件?和我自己的事件?或者重叠的事件?)。但我宁愿使用 good 解决方案而不是 my 解决方案。
Can i simulate a synchronous
ReadFile
operation but with a timeout, usingGetOverlappedResultEx
?
是的,你可以,就像你一样,已经尝试过了。这不是模拟。这将是完全同步的文件读取。因为同步读取 - 这是异步读取 + 在 I/O 完成时就地等待。所以代码可以是下一个:
ULONG ReadFileTimeout(HANDLE hFile,
PVOID lpBuffer,
ULONG nNumberOfBytesToRead,
PULONG lpNumberOfBytesRead,
PLARGE_INTEGER ByteOffset,
ULONG dwMilliseconds)
{
OVERLAPPED ov;
ov.Offset = ByteOffset->LowPart;
ov.OffsetHigh = ByteOffset->HighPart;
ULONG dwError = NOERROR;
if (ov.hEvent = CreateEvent(0, 0, 0, 0))
{
dwError = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, &ov) ? NOERROR : GetLastError();
if (dwError == ERROR_IO_PENDING)
{
dwError = GetOverlappedResultEx(0/*yes, not need hFile*/,
&ov, lpNumberOfBytesRead, dwMilliseconds, FALSE) ? NOERROR : GetLastError();
}
CloseHandle(ov.hEvent);
}
else
{
dwError = GetLastError();
}
return dwError;
}
请注意,您必须(在异步文件的情况下)始终显式使用字节偏移量,从那里读取数据。
GetOverlappedResultEx
通常下一步 - 检查 OVERLAPPED
- I/O 是否完整(只需将 Internal
与 STATUS_PENDING
进行比较),如果没有(仍然是 Internal == STATUS_PENDING
)并且你想要等待 - 它从 OVERLAPPED
调用 WaitForSingleObjectEx
和 hEvent
并转移 dwMilliseconds
和 bAlertable
。如果 hEvent
发出信号(WAIT_OBJECT_0
return 来自 WaitForSingleObjectEx
) GetOverlappedResultEx
决定 I/O 完成并且 return 来自 [=14] =], 否则相应错误 returned.
但万一 ReadFile
本身不是 return 控制和等待 - 这里不可能做某事。这意味着驱动程序开始等待您的线程。并且没有任何办法打破这个驱动程序等待。看起来这正是你的情况。当你使用异步文件时 - 驱动程序不能等待,但..有时(糟糕的驱动程序)这可能是