ext/libuv/src/unix/tty.c in libuv-0.10.2 vs ext/libuv/src/unix/tty.c in libuv-0.10.3

- old
+ new

@@ -19,20 +19,21 @@ * IN THE SOFTWARE. */ #include "uv.h" #include "internal.h" +#include "spinlock.h" #include <assert.h> #include <unistd.h> #include <termios.h> #include <errno.h> #include <sys/ioctl.h> - static int orig_termios_fd = -1; static struct termios orig_termios; +static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY); @@ -62,52 +63,43 @@ struct termios raw; int fd; fd = uv__stream_fd(tty); - if (mode && tty->mode == 0) { - /* on */ + if (mode && tty->mode == 0) { /* on */ + if (tcgetattr(fd, &tty->orig_termios)) + return -errno; - if (tcgetattr(fd, &tty->orig_termios)) { - goto fatal; - } - /* This is used for uv_tty_reset_mode() */ + uv_spinlock_lock(&termios_spinlock); if (orig_termios_fd == -1) { orig_termios = tty->orig_termios; orig_termios_fd = fd; } + uv_spinlock_unlock(&termios_spinlock); raw = tty->orig_termios; raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); raw.c_oflag |= (ONLCR); raw.c_cflag |= (CS8); raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* Put terminal in raw mode after draining */ - if (tcsetattr(fd, TCSADRAIN, &raw)) { - goto fatal; - } + if (tcsetattr(fd, TCSADRAIN, &raw)) + return -errno; tty->mode = 1; - return 0; - } else if (mode == 0 && tty->mode) { - /* off */ - + } else if (mode == 0 && tty->mode) { /* off */ /* Put terminal in original mode after flushing */ - if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios)) { - goto fatal; - } - + if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios)) + return -errno; tty->mode = 0; - return 0; } -fatal: - return -errno; + return 0; } int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { struct winsize ws; @@ -170,10 +162,23 @@ return UV_UNKNOWN_HANDLE; } -void uv_tty_reset_mode(void) { - if (orig_termios_fd >= 0) { - tcsetattr(orig_termios_fd, TCSANOW, &orig_termios); - } +/* This function is async signal-safe, meaning that it's safe to call from + * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s + * critical section when the signal was raised. + */ +int uv_tty_reset_mode(void) { + int err; + + if (!uv_spinlock_trylock(&termios_spinlock)) + return -EBUSY; /* In uv_tty_set_mode(). */ + + err = 0; + if (orig_termios_fd != -1) + if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) + err = -errno; + + uv_spinlock_unlock(&termios_spinlock); + return err; }