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;
}