mirror of https://github.com/mpv-player/mpv
terminal-unix: make stop/cont sighandlers pipe based
there are currently some silly data-races in the stop/cont sighandler due to the fact that the signal handler might get invoked in a different thread. this changes those sighandlers to a pipe-based approach similar to the existing "quit" sighandler.
This commit is contained in:
parent
c2d0a4a80f
commit
fa9e1f06ff
|
@ -272,8 +272,8 @@ static void process_input(struct input_ctx *input_ctx, bool timeout)
|
||||||
read_more: ; /* need more bytes */
|
read_more: ; /* need more bytes */
|
||||||
}
|
}
|
||||||
|
|
||||||
static volatile int getch2_active = 0;
|
static int getch2_active = 0;
|
||||||
static volatile int getch2_enabled = 0;
|
static int getch2_enabled = 0;
|
||||||
static bool read_terminal;
|
static bool read_terminal;
|
||||||
|
|
||||||
static void enable_kx(bool enable)
|
static void enable_kx(bool enable)
|
||||||
|
@ -349,10 +349,16 @@ static void getch2_poll(void)
|
||||||
do_deactivate_getch2();
|
do_deactivate_getch2();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static pthread_t input_thread;
|
||||||
|
static struct input_ctx *input_ctx;
|
||||||
|
static int death_pipe[2] = {-1, -1};
|
||||||
|
enum { PIPE_STOP, PIPE_CONT };
|
||||||
|
static int stop_cont_pipe[2] = {-1, -1};
|
||||||
|
|
||||||
static void stop_sighandler(int signum)
|
static void stop_sighandler(int signum)
|
||||||
{
|
{
|
||||||
int saved_errno = errno;
|
int saved_errno = errno;
|
||||||
do_deactivate_getch2();
|
(void)write(stop_cont_pipe[1], &(char){PIPE_STOP}, 1);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
|
|
||||||
// note: for this signal, we use SA_RESETHAND but do NOT mask signals
|
// note: for this signal, we use SA_RESETHAND but do NOT mask signals
|
||||||
|
@ -366,20 +372,22 @@ static void continue_sighandler(int signum)
|
||||||
// SA_RESETHAND has reset SIGTSTP, so we need to restore it here
|
// SA_RESETHAND has reset SIGTSTP, so we need to restore it here
|
||||||
setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false);
|
setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false);
|
||||||
|
|
||||||
getch2_poll();
|
(void)write(stop_cont_pipe[1], &(char){PIPE_CONT}, 1);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pthread_t input_thread;
|
static void safe_close(int *p)
|
||||||
static struct input_ctx *input_ctx;
|
{
|
||||||
static int death_pipe[2] = {-1, -1};
|
if (*p >= 0)
|
||||||
|
close(*p);
|
||||||
|
*p = -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void close_death_pipe(void)
|
static void close_sig_pipes(void)
|
||||||
{
|
{
|
||||||
for (int n = 0; n < 2; n++) {
|
for (int n = 0; n < 2; n++) {
|
||||||
if (death_pipe[n] >= 0)
|
safe_close(&death_pipe[n]);
|
||||||
close(death_pipe[n]);
|
safe_close(&stop_cont_pipe[n]);
|
||||||
death_pipe[n] = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,8 +412,9 @@ static void *terminal_thread(void *ptr)
|
||||||
bool stdin_ok = read_terminal; // if false, we still wait for SIGTERM
|
bool stdin_ok = read_terminal; // if false, we still wait for SIGTERM
|
||||||
while (1) {
|
while (1) {
|
||||||
getch2_poll();
|
getch2_poll();
|
||||||
struct pollfd fds[2] = {
|
struct pollfd fds[3] = {
|
||||||
{ .events = POLLIN, .fd = death_pipe[0] },
|
{ .events = POLLIN, .fd = death_pipe[0] },
|
||||||
|
{ .events = POLLIN, .fd = stop_cont_pipe[0] },
|
||||||
{ .events = POLLIN, .fd = tty_in }
|
{ .events = POLLIN, .fd = tty_in }
|
||||||
};
|
};
|
||||||
/*
|
/*
|
||||||
|
@ -419,12 +428,20 @@ static void *terminal_thread(void *ptr)
|
||||||
* care of it so it's fine.
|
* care of it so it's fine.
|
||||||
*/
|
*/
|
||||||
bool is_fg = tcgetpgrp(tty_in) == getpgrp();
|
bool is_fg = tcgetpgrp(tty_in) == getpgrp();
|
||||||
int r = polldev(fds, stdin_ok && is_fg ? 2 : 1, buf.len ? ESC_TIMEOUT : INPUT_TIMEOUT);
|
int r = polldev(fds, stdin_ok && is_fg ? 3 : 2, buf.len ? ESC_TIMEOUT : INPUT_TIMEOUT);
|
||||||
if (fds[0].revents) {
|
if (fds[0].revents) {
|
||||||
do_deactivate_getch2();
|
do_deactivate_getch2();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fds[1].revents) {
|
if (fds[1].revents & POLLIN) {
|
||||||
|
int8_t c = -1;
|
||||||
|
read(stop_cont_pipe[0], &c, 1);
|
||||||
|
if (c == PIPE_STOP)
|
||||||
|
do_deactivate_getch2();
|
||||||
|
else if (c == PIPE_CONT)
|
||||||
|
getch2_poll();
|
||||||
|
}
|
||||||
|
if (fds[2].revents) {
|
||||||
int retval = read(tty_in, &buf.b[buf.len], BUF_LEN - buf.len);
|
int retval = read(tty_in, &buf.b[buf.len], BUF_LEN - buf.len);
|
||||||
if (!retval || (retval == -1 && errno != EINTR && errno != EAGAIN && errno != EIO))
|
if (!retval || (retval == -1 && errno != EINTR && errno != EAGAIN && errno != EIO))
|
||||||
break; // EOF/closed
|
break; // EOF/closed
|
||||||
|
@ -454,6 +471,10 @@ void terminal_setup_getch(struct input_ctx *ictx)
|
||||||
|
|
||||||
if (mp_make_wakeup_pipe(death_pipe) < 0)
|
if (mp_make_wakeup_pipe(death_pipe) < 0)
|
||||||
return;
|
return;
|
||||||
|
if (mp_make_wakeup_pipe(stop_cont_pipe) < 0) {
|
||||||
|
close_sig_pipes();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Disable reading from the terminal even if stdout is not a tty, to make
|
// Disable reading from the terminal even if stdout is not a tty, to make
|
||||||
// mpv ... | less
|
// mpv ... | less
|
||||||
|
@ -464,7 +485,7 @@ void terminal_setup_getch(struct input_ctx *ictx)
|
||||||
|
|
||||||
if (pthread_create(&input_thread, NULL, terminal_thread, NULL)) {
|
if (pthread_create(&input_thread, NULL, terminal_thread, NULL)) {
|
||||||
input_ctx = NULL;
|
input_ctx = NULL;
|
||||||
close_death_pipe();
|
close_sig_pipes();
|
||||||
close_tty();
|
close_tty();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -491,7 +512,7 @@ void terminal_uninit(void)
|
||||||
if (input_ctx) {
|
if (input_ctx) {
|
||||||
(void)write(death_pipe[1], &(char){0}, 1);
|
(void)write(death_pipe[1], &(char){0}, 1);
|
||||||
pthread_join(input_thread, NULL);
|
pthread_join(input_thread, NULL);
|
||||||
close_death_pipe();
|
close_sig_pipes();
|
||||||
input_ctx = NULL;
|
input_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue