Fix inconsistent handling of EINTR in ser-*.c backends
authorPedro Alves <palves@redhat.com>
Tue, 12 Apr 2016 15:49:31 +0000 (16:49 +0100)
committerPedro Alves <palves@redhat.com>
Tue, 12 Apr 2016 15:57:33 +0000 (16:57 +0100)
- If serial->write_prim returns EINTR, ser_bas_write returns it to the
  caller.  This just looks wrong to me -- part of the output may have
  already been sent, and there's no way for the caller to know that,
  and thus no way for a caller to handle a partial write correctly.

- While ser-unix.c:ser_unix_read_prim retries on EINTR,
  ser-tcp.c:net_read_prim does not.

This commit moves EINTR handling to the ser_base_write and
ser_base_readchar level, so all serial backends (at least those that
use it) end up handling EINTR consistently.

gdb/ChangeLog:
2016-04-12  Pedro Alves  <palves@redhat.com>

* ser-base.c (fd_event): Retry read_prim on EINTR.
(do_ser_base_readchar): Retry read_prim on EINTR.
(ser_base_write): Retry write_prim on EINTR.
* ser-unix.c (ser_unix_read_prim): Don't retry on EINTR here.
(ser_unix_write_prim): Remove comment.

gdb/ChangeLog
gdb/ser-base.c
gdb/ser-unix.c

index ac6c2819df25ce6b3355170f674a9fda0a308ab7..8fa4b02bfc117d83f22d86c7ecc45df6af7648d1 100644 (file)
@@ -1,3 +1,11 @@
+2016-04-12  Pedro Alves  <palves@redhat.com>
+
+       * ser-base.c (fd_event): Retry read_prim on EINTR.
+       (do_ser_base_readchar): Retry read_prim on EINTR.
+       (ser_base_write): Retry write_prim on EINTR.
+       * ser-unix.c (ser_unix_read_prim): Don't retry on EINTR here.
+       (ser_unix_write_prim): Remove comment.
+
 2016-04-12  Pedro Alves  <palves@redhat.com>
 
        * remote.c (remote_pass_ctrlc): New function.
index 21d52cd928eac21b73f8763bd8346a39f3517176..25af66a91f6223c70549f81e77113a746ccdbccb 100644 (file)
@@ -164,7 +164,13 @@ fd_event (int error, void *context)
          pull characters out of the buffer.  See also
          generic_readchar().  */
       int nr;
-      nr = scb->ops->read_prim (scb, BUFSIZ);
+
+      do
+       {
+         nr = scb->ops->read_prim (scb, BUFSIZ);
+       }
+      while (nr < 0 && errno == EINTR);
+
       if (nr == 0)
        {
          scb->bufcnt = SERIAL_EOF;
@@ -358,7 +364,11 @@ do_ser_base_readchar (struct serial *scb, int timeout)
   if (status < 0)
     return status;
 
-  status = scb->ops->read_prim (scb, BUFSIZ);
+  do
+    {
+      status = scb->ops->read_prim (scb, BUFSIZ);
+    }
+  while (status < 0 && errno == EINTR);
 
   if (status <= 0)
     {
@@ -448,7 +458,11 @@ ser_base_write (struct serial *scb, const void *buf, size_t count)
       cc = scb->ops->write_prim (scb, str, count);
 
       if (cc < 0)
-       return 1;
+       {
+         if (errno == EINTR)
+           continue;
+         return 1;
+       }
       count -= cc;
       str += cc;
     }
index c54b2e10f2781826efcaeeb8dfc8353f201f1cd2..562e98b2f5e5189f4aae45718c24385ce6ce7909 100644 (file)
@@ -1002,21 +1002,11 @@ when debugging using remote targets."),
 int
 ser_unix_read_prim (struct serial *scb, size_t count)
 {
-  int status;
-
-  while (1)
-    {
-      status = read (scb->fd, scb->buf, count);
-      if (status != -1 || errno != EINTR)
-       break;
-    }
-  return status;
+  return read (scb->fd, scb->buf, count);
 }
 
 int
 ser_unix_write_prim (struct serial *scb, const void *buf, size_t len)
 {
-  /* ??? Historically, GDB has not retried calls to "write" that
-     result in EINTR.  */
   return write (scb->fd, buf, len);
 }