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:
wm4 2014-09-09 20:58:26 +02:00
parent d0b525121a
commit 28fc13977e
6 changed files with 74 additions and 63 deletions

View File

@ -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()))
{

View File

@ -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 */

View File

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

View File

@ -151,10 +151,6 @@ void terminal_setup_getch(struct input_ctx *ictx)
}
}
void getch2_poll(void)
{
}
void terminal_uninit(void)
{
if (running) {

View File

@ -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);

View File

@ -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();
}
}