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 <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson 2014-09-14 03:44:20 +02:00
parent 29b7f91165
commit 08b7f57c98

View File

@ -18,20 +18,75 @@
* ever read sources, credits must appear in the documentation. * ever read sources, credits must appear in the documentation.
* 4. This notice may not be removed or altered. * 4. This notice may not be removed or altered.
*/ */
#include <errno.h>
#include "editline.h" #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. */ /* Prefer termios over the others since it is likely the most portable. */
#if defined(HAVE_TCGETATTR) #if defined(HAVE_TCGETATTR)
#include <termios.h> #include <termios.h>
/* 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) void rl_ttyset(int Reset)
{ {
static struct termios old; static struct termios old;
struct termios new; struct termios new;
if (!Reset) { if (!Reset) {
if (-1 == tcgetattr(0, &old)) if (-1 == getattr(0, &old))
perror("Failed tcgetattr"); perror("Failed tcgetattr()");
rl_erase = old.c_cc[VERASE]; rl_erase = old.c_cc[VERASE];
rl_kill = old.c_cc[VKILL]; rl_kill = old.c_cc[VKILL];
rl_eof = old.c_cc[VEOF]; rl_eof = old.c_cc[VEOF];
@ -50,11 +105,11 @@ void rl_ttyset(int Reset)
new.c_iflag &= ~ISTRIP; new.c_iflag &= ~ISTRIP;
new.c_cc[VMIN] = 1; new.c_cc[VMIN] = 1;
new.c_cc[VTIME] = 0; new.c_cc[VTIME] = 0;
if (-1 == tcsetattr(0, TCSADRAIN, &new)) if (-1 == setattr(0, TCSADRAIN, &new))
perror("Failed tcsetattr"); perror("Failed tcsetattr(TCSADRAIN)");
} else { } else {
if (-1 == tcsetattr(0, TCSADRAIN, &old)) if (-1 == setattr(0, TCSADRAIN, &old))
perror("Failed tcsetattr"); perror("Failed tcsetattr(TCSADRAIN)");
} }
} }
@ -67,7 +122,7 @@ void rl_ttyset(int Reset)
struct termio new; struct termio new;
if (!Reset) { if (!Reset) {
if (-1 == ioctl(0, TCGETA, &old)) if (-1 == ioctl_wrap(0, TCGETA, &old))
perror("Failed ioctl(TCGETA)"); perror("Failed ioctl(TCGETA)");
rl_erase = old.c_cc[VERASE]; rl_erase = old.c_cc[VERASE];
rl_kill = old.c_cc[VKILL]; rl_kill = old.c_cc[VKILL];
@ -88,10 +143,10 @@ void rl_ttyset(int Reset)
new.c_cc[VMIN] = 1; new.c_cc[VMIN] = 1;
new.c_cc[VTIME] = 0; new.c_cc[VTIME] = 0;
if (-1 == ioctl(0, TCSETAW, &new)) if (-1 == ioctl_wrap(0, TCSETAW, &new))
perror("Failed ioctl(TCSETAW)"); perror("Failed ioctl(TCSETAW)");
} else { } else {
if (-1 == ioctl(0, TCSETAW, &old)) if (-1 == ioctl_wrap(0, TCSETAW, &old))
perror("Failed ioctl(TCSETAW)"); perror("Failed ioctl(TCSETAW)");
} }
} }
@ -110,19 +165,19 @@ void rl_ttyset(int Reset)
#endif #endif
if (!Reset) { if (!Reset) {
if (-1 == ioctl(0, TIOCGETP, &old_sgttyb)) if (-1 == ioctl_wrap(0, TIOCGETP, &old_sgttyb))
perror("Failed TIOCGETP"); perror("Failed TIOCGETP");
rl_erase = old_sgttyb.sg_erase; rl_erase = old_sgttyb.sg_erase;
rl_kill = old_sgttyb.sg_kill; rl_kill = old_sgttyb.sg_kill;
if (-1 == ioctl(0, TIOCGETC, &old_tchars)) if (-1 == ioctl_wrap(0, TIOCGETC, &old_tchars))
perror("Failed TIOCGETC"); perror("Failed TIOCGETC");
rl_eof = old_tchars.t_eofc; rl_eof = old_tchars.t_eofc;
rl_intr = old_tchars.t_intrc; rl_intr = old_tchars.t_intrc;
rl_quit = old_tchars.t_quitc; rl_quit = old_tchars.t_quitc;
#ifdef CONFIG_SIGSTOP #ifdef CONFIG_SIGSTOP
if (-1 == ioctl(0, TIOCGLTC, &old_ltchars)) if (-1 == ioctl_wrap(0, TIOCGLTC, &old_ltchars))
perror("Failed TIOCGLTC"); perror("Failed TIOCGLTC");
rl_susp = old_ltchars.t_suspc; rl_susp = old_ltchars.t_suspc;
#endif #endif
@ -134,17 +189,17 @@ void rl_ttyset(int Reset)
new_sgttyb.sg_flags &= ~PASS8; new_sgttyb.sg_flags &= ~PASS8;
else else
new_sgttyb.sg_flags |= PASS8; new_sgttyb.sg_flags |= PASS8;
if (-1 == ioctl(0, TIOCSETP, &new_sgttyb)) if (-1 == ioctl_wrap(0, TIOCSETP, &new_sgttyb))
perror("Failed TIOCSETP"); perror("Failed TIOCSETP");
new_tchars = old_tchars; new_tchars = old_tchars;
new_tchars.t_intrc = -1; new_tchars.t_intrc = -1;
new_tchars.t_quitc = -1; new_tchars.t_quitc = -1;
if (-1 == ioctl(0, TIOCSETC, &new_tchars)) if (-1 == ioctl_wrap(0, TIOCSETC, &new_tchars))
perror("Failed TIOCSETC"); perror("Failed TIOCSETC");
} else { } else {
if (-1 == ioctl(0, TIOCSETP, &old_sgttyb)) if (-1 == ioctl_wrap(0, TIOCSETP, &old_sgttyb))
perror("Failed TIOCSETP"); perror("Failed TIOCSETP");
if (-1 == ioctl(0, TIOCSETC, &old_tchars)) if (-1 == ioctl_wrap(0, TIOCSETC, &old_tchars))
perror("Failed TIOCSETC"); perror("Failed TIOCSETC");
} }
} }