From 75ee59252d49dffb017905125cdf826f89a6baf9 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Tue, 12 Apr 2016 16:49:31 +0100 Subject: [PATCH] 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 * 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 | 8 ++++++++ gdb/ser-base.c | 20 +++++++++++++++++--- gdb/ser-unix.c | 12 +----------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ac6c2819df2..8fa4b02bfc1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2016-04-12 Pedro Alves + + * 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 * remote.c (remote_pass_ctrlc): New function. diff --git a/gdb/ser-base.c b/gdb/ser-base.c index 21d52cd928e..25af66a91f6 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 c54b2e10f27..562e98b2f5e 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); } -- 2.30.2