From 08b7f57c980a8a4fefbb838b075ad0c914be1447 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 14 Sep 2014 03:44:20 +0200 Subject: [PATCH] src/sysunix.c: Restart syscalls on spurious EINTR Handle tcgetattr(), tcsetattr() and ioctl() by wrapping them in a retry-loop and restarting them when receiving EINTR. Should fix problem with sporadic error messages on the console like this one: 'Failed tcsetattr: Interrupted system call' Signed-off-by: Joachim Nilsson --- src/sysunix.c | 87 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/src/sysunix.c b/src/sysunix.c index 7d38eb7..ab3aaed 100644 --- a/src/sysunix.c +++ b/src/sysunix.c @@ -18,20 +18,75 @@ * ever read sources, credits must appear in the documentation. * 4. This notice may not be removed or altered. */ + +#include #include "editline.h" +#ifndef HAVE_TCGETATTR +/* Wrapper for ioctl syscalls to restart on signal */ +static int ioctl_wrap(int fd, int req, void *arg) +{ + int result, retries = 3; + + while (-1 == (result = ioctl(fd, req, arg)) && retries > 0) { + retries--; + + if (EINTR == errno) + continue; + + break; + } + + return result; +} +#endif + /* Prefer termios over the others since it is likely the most portable. */ #if defined(HAVE_TCGETATTR) #include +/* Wrapper for tcgetattr */ +static int getattr(int fd, struct termios *arg) +{ + int result, retries = 3; + + while (-1 == (result = tcgetattr(fd, arg)) && retries > 0) { + retries--; + + if (EINTR == errno) + continue; + + break; + } + + return result; +} + +/* Wrapper for tcgetattr */ +static int setattr(int fd, int opt, const struct termios *arg) +{ + int result, retries = 3; + + while (-1 == (result = tcsetattr(fd, opt, arg)) && retries > 0) { + retries--; + + if (EINTR == errno) + continue; + + break; + } + + return result; +} + void rl_ttyset(int Reset) { static struct termios old; struct termios new; if (!Reset) { - if (-1 == tcgetattr(0, &old)) - perror("Failed tcgetattr"); + if (-1 == getattr(0, &old)) + perror("Failed tcgetattr()"); rl_erase = old.c_cc[VERASE]; rl_kill = old.c_cc[VKILL]; rl_eof = old.c_cc[VEOF]; @@ -50,11 +105,11 @@ void rl_ttyset(int Reset) new.c_iflag &= ~ISTRIP; new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; - if (-1 == tcsetattr(0, TCSADRAIN, &new)) - perror("Failed tcsetattr"); + if (-1 == setattr(0, TCSADRAIN, &new)) + perror("Failed tcsetattr(TCSADRAIN)"); } else { - if (-1 == tcsetattr(0, TCSADRAIN, &old)) - perror("Failed tcsetattr"); + if (-1 == setattr(0, TCSADRAIN, &old)) + perror("Failed tcsetattr(TCSADRAIN)"); } } @@ -67,7 +122,7 @@ void rl_ttyset(int Reset) struct termio new; if (!Reset) { - if (-1 == ioctl(0, TCGETA, &old)) + if (-1 == ioctl_wrap(0, TCGETA, &old)) perror("Failed ioctl(TCGETA)"); rl_erase = old.c_cc[VERASE]; rl_kill = old.c_cc[VKILL]; @@ -88,10 +143,10 @@ void rl_ttyset(int Reset) new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; - if (-1 == ioctl(0, TCSETAW, &new)) + if (-1 == ioctl_wrap(0, TCSETAW, &new)) perror("Failed ioctl(TCSETAW)"); } else { - if (-1 == ioctl(0, TCSETAW, &old)) + if (-1 == ioctl_wrap(0, TCSETAW, &old)) perror("Failed ioctl(TCSETAW)"); } } @@ -110,19 +165,19 @@ void rl_ttyset(int Reset) #endif if (!Reset) { - if (-1 == ioctl(0, TIOCGETP, &old_sgttyb)) + if (-1 == ioctl_wrap(0, TIOCGETP, &old_sgttyb)) perror("Failed TIOCGETP"); rl_erase = old_sgttyb.sg_erase; rl_kill = old_sgttyb.sg_kill; - if (-1 == ioctl(0, TIOCGETC, &old_tchars)) + if (-1 == ioctl_wrap(0, TIOCGETC, &old_tchars)) perror("Failed TIOCGETC"); rl_eof = old_tchars.t_eofc; rl_intr = old_tchars.t_intrc; rl_quit = old_tchars.t_quitc; #ifdef CONFIG_SIGSTOP - if (-1 == ioctl(0, TIOCGLTC, &old_ltchars)) + if (-1 == ioctl_wrap(0, TIOCGLTC, &old_ltchars)) perror("Failed TIOCGLTC"); rl_susp = old_ltchars.t_suspc; #endif @@ -134,17 +189,17 @@ void rl_ttyset(int Reset) new_sgttyb.sg_flags &= ~PASS8; else new_sgttyb.sg_flags |= PASS8; - if (-1 == ioctl(0, TIOCSETP, &new_sgttyb)) + if (-1 == ioctl_wrap(0, TIOCSETP, &new_sgttyb)) perror("Failed TIOCSETP"); new_tchars = old_tchars; new_tchars.t_intrc = -1; new_tchars.t_quitc = -1; - if (-1 == ioctl(0, TIOCSETC, &new_tchars)) + if (-1 == ioctl_wrap(0, TIOCSETC, &new_tchars)) perror("Failed TIOCSETC"); } else { - if (-1 == ioctl(0, TIOCSETP, &old_sgttyb)) + if (-1 == ioctl_wrap(0, TIOCSETP, &old_sgttyb)) perror("Failed TIOCSETP"); - if (-1 == ioctl(0, TIOCSETC, &old_tchars)) + if (-1 == ioctl_wrap(0, TIOCSETC, &old_tchars)) perror("Failed TIOCSETC"); } }