[PATCH] linux: Retry VT ioctls while errno == EINTR
Aaron Plattner
aplattner at nvidia.com
Thu Apr 7 12:25:43 PDT 2011
When the smart scheduler is enabled, the VT ioctls (particularly
VT_WAITACTIVE) can be interrupted by the smart scheduler's SIGALRMs.
Previously, this caused the server to immediately continue on to
ScreenInit, almost certainly causing a crash or failure because the X
server that owned the VT hadn't finished cleaning up. As of commit
7ee965a300c9eddcc1acacf9414cfe3e589222a8, it causes a FatalError
instead.
Retrying the ioctl as long as it fails with errno == EINTR fixes the
problem and allows server regenerations to trigger VT switches that
actually succeed.
Signed-off-by: Aaron Plattner <aplattner at nvidia.com>
---
I don't know how many of these EINTR checks are really necessary, but I
figure it's better to be safe than to be sorry.
hw/xfree86/os-support/linux/lnx_init.c | 125 ++++++++++++++++++++------------
1 files changed, 80 insertions(+), 45 deletions(-)
diff --git a/hw/xfree86/os-support/linux/lnx_init.c b/hw/xfree86/os-support/linux/lnx_init.c
index 9c71a42..da4eac3 100644
--- a/hw/xfree86/os-support/linux/lnx_init.c
+++ b/hw/xfree86/os-support/linux/lnx_init.c
@@ -62,17 +62,21 @@ drain_console(int fd, void *closure)
static void
switch_to(int vt, const char *from)
{
- if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, vt) < 0)
- FatalError("%s: VT_ACTIVATE failed: %s\n", from, strerror(errno));
+ while (ioctl(xf86Info.consoleFd, VT_ACTIVATE, vt) < 0) {
+ if (errno != EINTR)
+ FatalError("%s: VT_ACTIVATE failed: %s\n", from, strerror(errno));
+ }
- if (ioctl(xf86Info.consoleFd, VT_WAITACTIVE, vt) < 0)
- FatalError("%s: VT_WAITACTIVE failed: %s\n", from, strerror(errno));
+ while (ioctl(xf86Info.consoleFd, VT_WAITACTIVE, vt) < 0) {
+ if (errno != EINTR)
+ FatalError("%s: VT_WAITACTIVE failed: %s\n", from, strerror(errno));
+ }
}
void
xf86OpenConsole(void)
{
- int i, fd = -1;
+ int i, fd = -1, ret;
struct vt_mode VT;
struct vt_stat vts;
MessageType from = X_PROBED;
@@ -107,17 +111,21 @@ xf86OpenConsole(void)
if (ShareVTs)
{
- if (ioctl(fd, VT_GETSTATE, &vts) == 0)
- xf86Info.vtno = vts.v_active;
- else
- FatalError("xf86OpenConsole: Cannot find the current"
- " VT (%s)\n", strerror(errno));
+ while (ioctl(fd, VT_GETSTATE, &vts) < 0) {
+ if (errno != EINTR)
+ FatalError("xf86OpenConsole: Cannot find the current"
+ " VT (%s)\n", strerror(errno));
+ }
+ xf86Info.vtno = vts.v_active;
} else {
- if ((ioctl(fd, VT_OPENQRY, &xf86Info.vtno) < 0) ||
- (xf86Info.vtno == -1))
- FatalError("xf86OpenConsole: Cannot find a free VT: %s\n",
- strerror(errno));
- }
+ while (ioctl(fd, VT_OPENQRY, &xf86Info.vtno) < 0) {
+ if (errno != EINTR)
+ FatalError("xf86OpenConsole: Cannot find a free VT: "
+ "%s\n", strerror(errno));
+ }
+ if (xf86Info.vtno == -1)
+ FatalError("xf86OpenConsole: Cannot find a free VT\n");
+ }
close(fd);
}
@@ -159,10 +167,14 @@ xf86OpenConsole(void)
* Linux doesn't switch to an active vt after the last close of a vt,
* so we do this ourselves by remembering which is active now.
*/
- if (ioctl(xf86Info.consoleFd, VT_GETSTATE, &vts) < 0)
- xf86Msg(X_WARNING,"xf86OpenConsole: VT_GETSTATE failed: %s\n",
- strerror(errno));
- else
+ while ((ret = ioctl(xf86Info.consoleFd, VT_GETSTATE, &vts)) < 0) {
+ if (errno != EINTR) {
+ xf86Msg(X_WARNING,"xf86OpenConsole: VT_GETSTATE failed: %s\n",
+ strerror(errno));
+ break;
+ }
+ }
+ if (ret == 0)
activeVT = vts.v_active;
#if 0
@@ -186,9 +198,11 @@ xf86OpenConsole(void)
*/
switch_to(xf86Info.vtno, "xf86OpenConsole");
- if (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) < 0)
- FatalError("xf86OpenConsole: VT_GETMODE failed %s\n",
- strerror(errno));
+ while (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) < 0) {
+ if (errno != EINTR)
+ FatalError("xf86OpenConsole: VT_GETMODE failed %s\n",
+ strerror(errno));
+ }
signal(SIGUSR1, xf86VTRequest);
@@ -196,20 +210,28 @@ xf86OpenConsole(void)
VT.relsig = SIGUSR1;
VT.acqsig = SIGUSR1;
- if (ioctl(xf86Info.consoleFd, VT_SETMODE, &VT) < 0)
- FatalError("xf86OpenConsole: VT_SETMODE VT_PROCESS failed: %s\n",
- strerror(errno));
-
- if (ioctl(xf86Info.consoleFd, KDSETMODE, KD_GRAPHICS) < 0)
- FatalError("xf86OpenConsole: KDSETMODE KD_GRAPHICS failed %s\n",
- strerror(errno));
+ while (ioctl(xf86Info.consoleFd, VT_SETMODE, &VT) < 0) {
+ if (errno != EINTR)
+ FatalError("xf86OpenConsole: VT_SETMODE VT_PROCESS failed: %s\n",
+ strerror(errno));
+ }
- tcgetattr(xf86Info.consoleFd, &tty_attr);
- ioctl(xf86Info.consoleFd, KDGKBMODE, &tty_mode);
+ while (ioctl(xf86Info.consoleFd, KDSETMODE, KD_GRAPHICS) < 0) {
+ if (errno != EINTR)
+ FatalError("xf86OpenConsole: KDSETMODE KD_GRAPHICS failed %s\n",
+ strerror(errno));
+ }
- if (ioctl(xf86Info.consoleFd, KDSKBMODE, K_RAW) < 0)
- FatalError("xf86OpenConsole: KDSKBMODE K_RAW failed %s\n",
- strerror(errno));
+ tcgetattr(xf86Info.consoleFd, &tty_attr);
+ while (ioctl(xf86Info.consoleFd, KDGKBMODE, &tty_mode) < 0 &&
+ errno == EINTR)
+ ;
+
+ while (ioctl(xf86Info.consoleFd, KDSKBMODE, K_RAW) < 0) {
+ if (errno != EINTR)
+ FatalError("xf86OpenConsole: KDSKBMODE K_RAW failed %s\n",
+ strerror(errno));
+ }
nTty = tty_attr;
nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
@@ -241,6 +263,7 @@ void
xf86CloseConsole(void)
{
struct vt_mode VT;
+ int ret;
if (ShareVTs) {
close(xf86Info.consoleFd);
@@ -253,22 +276,34 @@ xf86CloseConsole(void)
};
/* Back to text mode ... */
- if (ioctl(xf86Info.consoleFd, KDSETMODE, KD_TEXT) < 0)
- xf86Msg(X_WARNING, "xf86CloseConsole: KDSETMODE failed: %s\n",
- strerror(errno));
+ while (ioctl(xf86Info.consoleFd, KDSETMODE, KD_TEXT) < 0) {
+ if (errno != EINTR)
+ xf86Msg(X_WARNING, "xf86CloseConsole: KDSETMODE failed: %s\n",
+ strerror(errno));
+ }
- ioctl(xf86Info.consoleFd, KDSKBMODE, tty_mode);
+ while (ioctl(xf86Info.consoleFd, KDSKBMODE, tty_mode) < 0 &&
+ errno == EINTR)
+ ;
tcsetattr(xf86Info.consoleFd, TCSANOW, &tty_attr);
- if (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) < 0)
- xf86Msg(X_WARNING, "xf86CloseConsole: VT_GETMODE failed: %s\n",
- strerror(errno));
- else {
+ while ((ret = ioctl(xf86Info.consoleFd, VT_GETMODE, &VT)) < 0) {
+ if (errno != EINTR) {
+ xf86Msg(X_WARNING, "xf86CloseConsole: VT_GETMODE failed: %s\n",
+ strerror(errno));
+ break;
+ }
+ }
+ if (ret == 0) {
/* set dflt vt handling */
VT.mode = VT_AUTO;
- if (ioctl(xf86Info.consoleFd, VT_SETMODE, &VT) < 0)
- xf86Msg(X_WARNING, "xf86CloseConsole: VT_SETMODE failed: %s\n",
- strerror(errno));
+ while (ioctl(xf86Info.consoleFd, VT_SETMODE, &VT) < 0) {
+ if (errno != EINTR) {
+ xf86Msg(X_WARNING, "xf86CloseConsole: VT_SETMODE failed: %s\n",
+ strerror(errno));
+ break;
+ }
+ }
}
if (VTSwitch)
--
1.7.1
More information about the xorg-devel
mailing list