diff --git a/libserialport_internal.h b/libserialport_internal.h index ecf8fe9..91e2078 100644 --- a/libserialport_internal.h +++ b/libserialport_internal.h @@ -155,6 +155,7 @@ struct sp_port { DWORD write_buf_size; BOOL writing; BOOL wait_running; + BOOL last_wait_thread_exited; #else int fd; #endif diff --git a/serialport.c b/serialport.c index e6097ee..3b2ca12 100644 --- a/serialport.c +++ b/serialport.c @@ -427,9 +427,28 @@ static enum sp_return restart_wait(struct sp_port *port) if (GetOverlappedResult(port->hdl, &port->wait_ovl, &wait_result, FALSE)) { DEBUG("Previous wait completed"); + port->last_wait_thread_exited = FALSE; + port->wait_running = FALSE; + } else if (GetLastError() == ERROR_OPERATION_ABORTED) { + /* This error is returned if the last thread that called + * restart_wait() has exited while WaitCommEvent() was + * still active. In that case we don't consider that to + * be an error. Just restart the wait procedure instead. + */ + DEBUG("Previous wait ended due to previous thread exiting"); + /* We need to record that the wait thread exited before + * we called WaitCommEvent(). This is because the exit of + * the previous thread always generates a spurious wakeup, + * and if no data has been received in the mean time, the + * WaitCommEvent() wouldn't be restarted a second time by + * restart_wait_if_needed() after a read call after the + * spurious wakeup. + */ + port->last_wait_thread_exited = TRUE; port->wait_running = FALSE; } else if (GetLastError() == ERROR_IO_INCOMPLETE) { DEBUG("Previous wait still running"); + port->last_wait_thread_exited = FALSE; RETURN_OK(); } else { RETURN_FAIL("GetOverlappedResult() failed"); @@ -1022,7 +1041,11 @@ static enum sp_return restart_wait_if_needed(struct sp_port *port, unsigned int DWORD errors; COMSTAT comstat; - if (bytes_read == 0) + /* Only skip restarting the wait operation if we didn't have a + * wakeup immediately following the exit of the last thread that + * re-initiated the wait loop. + */ + if (!port->last_wait_thread_exited && bytes_read == 0) RETURN_OK(); if (ClearCommError(port->hdl, &errors, &comstat) == 0)