Implement ilufang's ERROR_IO_PENDING for empty serial reads

This commit is contained in:
Hay1tsme
2025-02-09 04:50:10 -05:00
parent 4633c51d58
commit dafd0aa336
3 changed files with 32 additions and 1 deletions
+1
View File
@@ -20,6 +20,7 @@ uint32_t hr_to_win32_error(HRESULT hr)
case E_NOINTERFACE: return ERROR_INVALID_FUNCTION;
case E_NOTIMPL: return ERROR_NOT_SUPPORTED;
case E_OUTOFMEMORY: return ERROR_OUTOFMEMORY;
case E_PENDING: return ERROR_IO_PENDING;
case E_POINTER: return ERROR_INVALID_ADDRESS;
case E_UNEXPECTED: return ERROR_INTERNAL_ERROR;
default: return ERROR_INTERNAL_ERROR;
+4 -1
View File
@@ -741,7 +741,10 @@ static BOOL WINAPI iohook_ReadFile(
hr = iohook_invoke_next(&irp);
if (FAILED(hr)) {
if (hr == E_PENDING) {
*lpNumberOfBytesRead = 0;
lpNumberOfBytesRead = NULL;
} else if (FAILED(hr)) {
return hr_propagate_win32(hr, FALSE);
}
+27
View File
@@ -197,6 +197,33 @@ static HRESULT uart_handle_close(struct uart *uart, struct irp *irp)
static HRESULT uart_handle_read(struct uart *uart, struct irp *irp)
{
int requested = irp->read.nbytes;
long timeout = uart->timeouts.ReadTotalTimeoutConstant + uart->timeouts.ReadTotalTimeoutMultiplier * requested;
if (timeout > 0) {
int interval_timeout = uart->timeouts.ReadIntervalTimeout;
int t0 = GetTickCount(), it0 = t0;
int last_avail = uart->readable.pos;
while (uart->readable.pos < requested) {
Sleep(1);
int t1 = GetTickCount();
if (t1 - t0 > timeout) {
break;
}
if (interval_timeout > 0) {
if (uart->readable.pos != last_avail) {
it0 = t1;
last_avail = uart->readable.pos;
} else if (t1 - it0 > interval_timeout) {
break;
}
}
}
}
if (uart->readable.pos == 0) {
return E_PENDING;
}
/* This does a memmove() under the covers. Less efficient than a ring
buffer, but I don't expect this to matter in the common case where the
entire buffer gets drained, particularly since UARTs are decidedly