]> sigrok.org Git - libserialport.git/commitdiff
Windows: don't fail if WaitCommEvent was aborted due to thread exit
authorChristian Seiler <redacted>
Sat, 31 Aug 2024 20:27:23 +0000 (22:27 +0200)
committerSoeren Apel <redacted>
Sat, 31 Aug 2024 20:30:25 +0000 (22:30 +0200)
This is a partial fix for #1603.

libserialport_internal.h
serialport.c

index f1d0d8505494c7949af7e60c98589c74309e0a49..57346d653ad369636a769e35858ef36138686b8c 100644 (file)
@@ -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
index 1135c36b4978328a7c42a9c23006641a3f8185ff..b3b9249a37c70b70ce3d75be0bd92ec355a2d21c 100644 (file)
@@ -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)