aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-04-12 16:49:31 +0100
committerPedro Alves <palves@redhat.com>2016-04-12 16:57:33 +0100
commit75ee59252d49dffb017905125cdf826f89a6baf9 (patch)
tree0b083ce32e0dd3fba3fe169f3fbc15a0232dde81
parent93692b589dc7017d5a2fbdffdfad5f84f597d8f1 (diff)
downloadbinutils-75ee59252d49dffb017905125cdf826f89a6baf9.zip
binutils-75ee59252d49dffb017905125cdf826f89a6baf9.tar.gz
binutils-75ee59252d49dffb017905125cdf826f89a6baf9.tar.bz2
Fix inconsistent handling of EINTR in ser-*.c backends
- 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.
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/ser-base.c20
-rw-r--r--gdb/ser-unix.c12
3 files changed, 26 insertions, 14 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ac6c281..8fa4b02 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
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.
(init_remote_ops): Install it.
* target.c (target_terminal_inferior): Pass pending Ctrl-C to the
diff --git a/gdb/ser-base.c b/gdb/ser-base.c
index 21d52cd..25af66a 100644
--- a/gdb/ser-base.c
+++ b/gdb/ser-base.c
@@ -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;
}
diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c
index c54b2e1..562e98b 100644
--- a/gdb/ser-unix.c
+++ b/gdb/ser-unix.c
@@ -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);
}