mirror of https://github.com/mpv-player/mpv
terminal-unix: move to thread
Do terminal input with a thread, instead of using the central select() loop. This also changes some details how SIGTERM is handled. Part of my crusade against mp_input_add_fd().
This commit is contained in:
parent
d0b525121a
commit
28fc13977e
|
@ -187,8 +187,6 @@ struct input_ctx {
|
|||
int wakeup_pipe[2];
|
||||
};
|
||||
|
||||
int async_quit_request;
|
||||
|
||||
static int parse_config(struct input_ctx *ictx, bool builtin, bstr data,
|
||||
const char *location, const char *restrict_section);
|
||||
static void close_input_sources(struct input_ctx *ictx);
|
||||
|
@ -296,12 +294,6 @@ static void queue_remove(struct cmd_queue *queue, struct mp_cmd *cmd)
|
|||
*p_prev = cmd->queue_next;
|
||||
}
|
||||
|
||||
static void queue_add_head(struct cmd_queue *queue, struct mp_cmd *cmd)
|
||||
{
|
||||
cmd->queue_next = queue->first;
|
||||
queue->first = cmd;
|
||||
}
|
||||
|
||||
static void queue_add_tail(struct cmd_queue *queue, struct mp_cmd *cmd)
|
||||
{
|
||||
struct mp_cmd **p_prev = &queue->first;
|
||||
|
@ -1159,11 +1151,6 @@ mp_cmd_t *mp_input_read_cmd(struct input_ctx *ictx)
|
|||
{
|
||||
input_lock(ictx);
|
||||
read_events(ictx, 0);
|
||||
if (async_quit_request && !queue_has_abort_cmds(&ictx->cmd_queue)) {
|
||||
struct mp_cmd *cmd = mp_input_parse_cmd(ictx, bstr0("quit"), "");
|
||||
queue_add_head(&ictx->cmd_queue, cmd);
|
||||
async_quit_request = 0;
|
||||
}
|
||||
struct cmd_queue *queue = &ictx->cmd_queue;
|
||||
if (!queue->first) {
|
||||
struct mp_cmd *repeated = check_autorepeat(ictx);
|
||||
|
@ -1664,11 +1651,6 @@ void mp_input_wakeup_nolock(struct input_ctx *ictx)
|
|||
}
|
||||
}
|
||||
|
||||
static bool test_abort(struct input_ctx *ictx)
|
||||
{
|
||||
return async_quit_request || queue_has_abort_cmds(&ictx->cmd_queue);
|
||||
}
|
||||
|
||||
void mp_input_set_main_thread(struct input_ctx *ictx)
|
||||
{
|
||||
ictx->mainthread = pthread_self();
|
||||
|
@ -1678,7 +1660,7 @@ void mp_input_set_main_thread(struct input_ctx *ictx)
|
|||
bool mp_input_check_interrupt(struct input_ctx *ictx)
|
||||
{
|
||||
input_lock(ictx);
|
||||
bool res = test_abort(ictx);
|
||||
bool res = queue_has_abort_cmds(&ictx->cmd_queue);
|
||||
if (!res && ictx->mainthread_set &&
|
||||
pthread_equal(ictx->mainthread, pthread_self()))
|
||||
{
|
||||
|
|
|
@ -260,6 +260,4 @@ void mp_input_add_pipe(struct input_ctx *ictx, const char *filename);
|
|||
|
||||
void mp_input_set_main_thread(struct input_ctx *ictx);
|
||||
|
||||
extern int async_quit_request;
|
||||
|
||||
#endif /* MPLAYER_INPUT_H */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if HAVE_TERMIOS
|
||||
|
@ -41,6 +42,9 @@
|
|||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "osdep/io.h"
|
||||
|
||||
#include "common/common.h"
|
||||
#include "misc/bstr.h"
|
||||
|
@ -185,7 +189,7 @@ static bool getch2(struct input_ctx *input_ctx)
|
|||
/* Return false on EOF to stop running select() on the FD, as it'd
|
||||
* trigger all the time. Note that it's possible to get temporary
|
||||
* EOF on terminal if the user presses ctrl-d, but that shouldn't
|
||||
* happen if the terminal state change done in getch2_enable()
|
||||
* happen if the terminal state change done in terminal_init()
|
||||
* works.
|
||||
*/
|
||||
if (retval == 0)
|
||||
|
@ -570,7 +574,7 @@ static bool getch2(struct input_ctx *input_ctx)
|
|||
/* Return false on EOF to stop running select() on the FD, as it'd
|
||||
* trigger all the time. Note that it's possible to get temporary
|
||||
* EOF on terminal if the user presses ctrl-d, but that shouldn't
|
||||
* happen if the terminal state change done in getch2_enable()
|
||||
* happen if the terminal state change done in terminal_init()
|
||||
* works.
|
||||
*/
|
||||
if (retval == 0)
|
||||
|
@ -645,23 +649,9 @@ static bool getch2(struct input_ctx *input_ctx)
|
|||
|
||||
#endif /* terminfo/termcap */
|
||||
|
||||
static int read_keys(void *ctx, int fd)
|
||||
{
|
||||
if (getch2(ctx))
|
||||
return MP_INPUT_NOTHING;
|
||||
return MP_INPUT_DEAD;
|
||||
}
|
||||
|
||||
static volatile int getch2_active = 0;
|
||||
static volatile int getch2_enabled = 0;
|
||||
|
||||
void terminal_setup_getch(struct input_ctx *ictx)
|
||||
{
|
||||
if (!getch2_enabled)
|
||||
return;
|
||||
mp_input_add_fd(ictx, 0, 1, NULL, read_keys, NULL, ictx);
|
||||
}
|
||||
|
||||
static void do_activate_getch2(void)
|
||||
{
|
||||
if (getch2_active || !isatty(STDOUT_FILENO))
|
||||
|
@ -721,7 +711,8 @@ static int setsigaction(int signo, void (*handler) (int),
|
|||
return sigaction(signo, &sa, NULL);
|
||||
}
|
||||
|
||||
void getch2_poll(void){
|
||||
static void getch2_poll(void)
|
||||
{
|
||||
if (!getch2_enabled)
|
||||
return;
|
||||
|
||||
|
@ -752,29 +743,62 @@ static void continue_sighandler(int signum)
|
|||
getch2_poll();
|
||||
}
|
||||
|
||||
static pthread_t input_thread;
|
||||
static struct input_ctx *input_ctx;
|
||||
static int death_pipe[2];
|
||||
|
||||
static void quit_request_sighandler(int signum)
|
||||
{
|
||||
do_deactivate_getch2();
|
||||
|
||||
async_quit_request = 1;
|
||||
write(death_pipe[1], &(char){0}, 1);
|
||||
}
|
||||
|
||||
static void getch2_enable(void)
|
||||
static void *terminal_thread(void *ptr)
|
||||
{
|
||||
assert(!getch2_enabled);
|
||||
bool stdin_ok = true; // if false, we still wait for SIGTERM
|
||||
while (1) {
|
||||
struct pollfd fds[2] = {
|
||||
{.events = POLLIN, .fd = death_pipe[0]},
|
||||
{.events = POLLIN, .fd = STDIN_FILENO},
|
||||
};
|
||||
// Wait with some timeout, so we can call getch2_poll() frequently.
|
||||
poll(fds, stdin_ok ? 2 : 1, 1000);
|
||||
if (fds[0].revents)
|
||||
break;
|
||||
if (fds[1].revents)
|
||||
stdin_ok = getch2(input_ctx);
|
||||
getch2_poll();
|
||||
}
|
||||
// Important if we received SIGTERM, rather than regular quit.
|
||||
struct mp_cmd *cmd = mp_input_parse_cmd(input_ctx, bstr0("quit"), "");
|
||||
if (cmd)
|
||||
mp_input_queue_cmd(input_ctx, cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void terminal_setup_getch(struct input_ctx *ictx)
|
||||
{
|
||||
if (!getch2_enabled)
|
||||
return;
|
||||
|
||||
assert(!input_ctx); // already setup
|
||||
|
||||
if (mp_make_wakeup_pipe(death_pipe) < 0)
|
||||
return;
|
||||
|
||||
input_ctx = ictx;
|
||||
|
||||
if (pthread_create(&input_thread, NULL, terminal_thread, NULL)) {
|
||||
input_ctx = NULL;
|
||||
close(death_pipe[0]);
|
||||
close(death_pipe[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// handlers to fix terminal settings
|
||||
setsigaction(SIGCONT, continue_sighandler, 0, true);
|
||||
setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false);
|
||||
setsigaction(SIGINT, quit_request_sighandler, SA_RESETHAND, false);
|
||||
setsigaction(SIGQUIT, quit_request_sighandler, SA_RESETHAND, false);
|
||||
setsigaction(SIGTERM, quit_request_sighandler, SA_RESETHAND, false);
|
||||
setsigaction(SIGTTIN, SIG_IGN, 0, true);
|
||||
setsigaction(SIGTTOU, SIG_IGN, 0, true);
|
||||
|
||||
do_activate_getch2();
|
||||
|
||||
getch2_enabled = 1;
|
||||
}
|
||||
|
||||
void terminal_uninit(void)
|
||||
|
@ -793,6 +817,14 @@ void terminal_uninit(void)
|
|||
|
||||
do_deactivate_getch2();
|
||||
|
||||
if (input_ctx) {
|
||||
write(death_pipe[1], &(char){0}, 1);
|
||||
pthread_join(input_thread, NULL);
|
||||
close(death_pipe[0]);
|
||||
close(death_pipe[1]);
|
||||
input_ctx = NULL;
|
||||
}
|
||||
|
||||
getch2_enabled = 0;
|
||||
}
|
||||
|
||||
|
@ -815,6 +847,17 @@ int terminal_init(void)
|
|||
{
|
||||
if (isatty(STDOUT_FILENO))
|
||||
load_termcap();
|
||||
getch2_enable();
|
||||
|
||||
assert(!getch2_enabled);
|
||||
|
||||
// handlers to fix terminal settings
|
||||
setsigaction(SIGCONT, continue_sighandler, 0, true);
|
||||
setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false);
|
||||
setsigaction(SIGTTIN, SIG_IGN, 0, true);
|
||||
setsigaction(SIGTTOU, SIG_IGN, 0, true);
|
||||
|
||||
do_activate_getch2();
|
||||
|
||||
getch2_enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -151,10 +151,6 @@ void terminal_setup_getch(struct input_ctx *ictx)
|
|||
}
|
||||
}
|
||||
|
||||
void getch2_poll(void)
|
||||
{
|
||||
}
|
||||
|
||||
void terminal_uninit(void)
|
||||
{
|
||||
if (running) {
|
||||
|
|
|
@ -44,9 +44,6 @@ bool terminal_in_background(void);
|
|||
/* Get terminal-size in columns/rows. */
|
||||
void terminal_get_size(int *w, int *h);
|
||||
|
||||
/* Enable and disable STDIN line-buffering */
|
||||
void getch2_poll(void);
|
||||
|
||||
// Windows only.
|
||||
void mp_write_console_ansi(void *wstream, char *buf);
|
||||
|
||||
|
|
|
@ -961,9 +961,6 @@ void run_playloop(struct MPContext *mpctx)
|
|||
handle_force_window(mpctx, false);
|
||||
|
||||
execute_queued_seek(mpctx);
|
||||
|
||||
if (mpctx->opts->use_terminal)
|
||||
getch2_poll();
|
||||
}
|
||||
|
||||
// Waiting for the slave master to send us a new file to play.
|
||||
|
@ -989,7 +986,5 @@ void idle_loop(struct MPContext *mpctx)
|
|||
mp_process_input(mpctx);
|
||||
mp_wait_events(mpctx, mpctx->sleeptime);
|
||||
mpctx->sleeptime = 100.0;
|
||||
if (mpctx->opts->use_terminal)
|
||||
getch2_poll();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue