From: Christian Seiler Date: Sat, 31 Aug 2024 20:27:23 +0000 (+0200) Subject: Windows: don't fail if WaitCommEvent was aborted due to thread exit X-Git-Tag: libserialport-0.1.2~5 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=1136d76fd38d6b916f286419c152fed207d93e3f;p=libserialport.git Windows: don't fail if WaitCommEvent was aborted due to thread exit This is a partial fix for #1603. --- diff --git a/libserialport_internal.h b/libserialport_internal.h index f1d0d85..57346d6 100644 --- a/libserialport_internal.h +++ b/libserialport_internal.h @@ -158,6 +158,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 1135c36..b3b9249 100644 --- a/serialport.c +++ b/serialport.c @@ -420,19 +420,35 @@ SP_API void sp_free_port_list(struct sp_port **list) /** To be called after port receive buffer is emptied. */ static enum sp_return restart_wait(struct sp_port *port) { - DWORD wait_result, last_error_code; + DWORD wait_result; if (port->wait_running) { /* Check status of running wait operation. */ 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 ((last_error_code = GetLastError()) == ERROR_OPERATION_ABORTED) { - DEBUG("Previous wait aborted"); + } 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 (last_error_code == ERROR_IO_INCOMPLETE) { + } else if (GetLastError() == ERROR_IO_INCOMPLETE) { DEBUG("Previous wait still running"); + port->last_wait_thread_exited = FALSE; RETURN_OK(); } else { RETURN_FAIL("GetOverlappedResult() failed"); @@ -1029,7 +1045,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)