]> sigrok.org Git - libserialport.git/blobdiff - serialport.c
Handle EINTR from tcdrain() in sp_drain().
[libserialport.git] / serialport.c
index e2cf48abd33df6785a6930c39b5f4742f7cce2fa..bbb53bdc64941d9aac6bab6a484d031a4653303b 100644 (file)
@@ -799,13 +799,23 @@ enum sp_return sp_drain(struct sp_port *port)
        /* Returns non-zero upon success, 0 upon failure. */
        if (FlushFileBuffers(port->hdl) == 0)
                RETURN_FAIL("FlushFileBuffers() failed");
+       RETURN_OK();
 #else
-       /* Returns 0 upon success, -1 upon failure. */
-       if (tcdrain(port->fd) < 0)
-               RETURN_FAIL("tcdrain() failed");
+       int result;
+       while (1) {
+               result = tcdrain(port->fd);
+               if (result < 0) {
+                       if (errno == EINTR) {
+                               DEBUG("tcdrain() was interrupted");
+                               continue;
+                       } else {
+                               RETURN_FAIL("tcdrain() failed");
+                       }
+               } else {
+                       RETURN_OK();
+               }
+       }
 #endif
-
-       RETURN_OK();
 }
 
 enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout)
@@ -870,7 +880,7 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c
                gettimeofday(&start, NULL);
                /* Define duration of timeout. */
                delta.tv_sec = timeout / 1000;
-               delta.tv_usec = timeout % 1000;
+               delta.tv_usec = (timeout % 1000) * 1000;
                /* Calculate time at which we should give up. */
                timeradd(&start, &delta, &end);
        }
@@ -890,9 +900,14 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c
                        timersub(&end, &now, &delta);
                }
                result = select(port->fd + 1, NULL, &fds, NULL, timeout ? &delta : NULL);
-               if (result < 0)
-                       RETURN_FAIL("select() failed");
-               if (result == 0) {
+               if (result < 0) {
+                       if (errno == EINTR) {
+                               DEBUG("select() call was interrupted, repeating");
+                               continue;
+                       } else {
+                               RETURN_FAIL("select() failed");
+                       }
+               } else if (result == 0) {
                        DEBUG("write timed out");
                        RETURN_VALUE("%d", bytes_written);
                }
@@ -1041,7 +1056,7 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u
                gettimeofday(&start, NULL);
                /* Define duration of timeout. */
                delta.tv_sec = timeout / 1000;
-               delta.tv_usec = timeout % 1000;
+               delta.tv_usec = (timeout % 1000) * 1000;
                /* Calculate time at which we should give up. */
                timeradd(&start, &delta, &end);
        }
@@ -1060,9 +1075,14 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u
                        timersub(&end, &now, &delta);
                }
                result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL);
-               if (result < 0)
-                       RETURN_FAIL("select() failed");
-               if (result == 0) {
+               if (result < 0) {
+                       if (errno == EINTR) {
+                               DEBUG("select() call was interrupted, repeating");
+                               continue;
+                       } else {
+                               RETURN_FAIL("select() failed");
+                       }
+               } else if (result == 0) {
                        DEBUG("read timed out");
                        RETURN_VALUE("%d", bytes_read);
                }
@@ -1131,6 +1151,52 @@ enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count
 #endif
 }
 
+enum sp_return sp_input_waiting(struct sp_port *port)
+{
+       TRACE("%p", port);
+
+       CHECK_OPEN_PORT();
+
+       DEBUG("Checking input bytes waiting on port %s", port->name);
+
+#ifdef _WIN32
+       DWORD errors;
+       COMSTAT comstat;
+
+       if (ClearCommError(port->hdl, &errors, &comstat) == 0)
+               RETURN_FAIL("ClearComError() failed");
+       RETURN_VALUE("%d", comstat.cbInQue);
+#else
+       int bytes_waiting;
+       if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0)
+               RETURN_FAIL("TIOCINQ ioctl failed");
+       RETURN_VALUE("%d", bytes_waiting);
+#endif
+}
+
+enum sp_return sp_output_waiting(struct sp_port *port)
+{
+       TRACE("%p", port);
+
+       CHECK_OPEN_PORT();
+
+       DEBUG("Checking output bytes waiting on port %s", port->name);
+
+#ifdef _WIN32
+       DWORD errors;
+       COMSTAT comstat;
+
+       if (ClearCommError(port->hdl, &errors, &comstat) == 0)
+               RETURN_FAIL("ClearComError() failed");
+       RETURN_VALUE("%d", comstat.cbOutQue);
+#else
+       int bytes_waiting;
+       if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0)
+               RETURN_FAIL("TIOCOUTQ ioctl failed");
+       RETURN_VALUE("%d", bytes_waiting);
+#endif
+}
+
 #ifdef __linux__
 static enum sp_return get_baudrate(int fd, int *baudrate)
 {