summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-09-09 20:58:26 +0200
committerwm4 <wm4@nowhere>2014-09-10 00:48:12 +0200
commit28fc13977e740769d11b17165016559505187486 (patch)
tree1ed04f39b6f852d0c9c9e9142094bf3738624854
parentd0b525121af63cc8cf19f2207a5ef384c78e61f6 (diff)
downloadmpv-28fc13977e740769d11b17165016559505187486.tar.bz2
mpv-28fc13977e740769d11b17165016559505187486.tar.xz
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().
-rw-r--r--input/input.c20
-rw-r--r--input/input.h2
-rw-r--r--osdep/terminal-unix.c103
-rw-r--r--osdep/terminal-win.c4
-rw-r--r--osdep/terminal.h3
-rw-r--r--player/playloop.c5
6 files changed, 74 insertions, 63 deletions
diff --git a/input/input.c b/input/input.c
index bf032e6ce2..31ce41ff57 100644
--- a/input/input.c
+++ b/input/input.c
@@ -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()))
{
diff --git a/input/input.h b/input/input.h
index 6ab1392111..1bd1410f66 100644
--- a/input/input.h
+++ b/input/input.h
@@ -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 */
diff --git a/osdep/terminal-unix.c b/osdep/terminal-unix.c
index b4890ee30c..a3cb82aa06 100644
--- a/osdep/terminal-unix.c
+++ b/osdep/terminal-unix.c
@@ -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;
}
diff --git a/osdep/terminal-win.c b/osdep/terminal-win.c
index 20077abc7e..9bfb97041b 100644
--- a/osdep/terminal-win.c
+++ b/osdep/terminal-win.c
@@ -151,10 +151,6 @@ void terminal_setup_getch(struct input_ctx *ictx)
}
}
-void getch2_poll(void)
-{
-}
-
void terminal_uninit(void)
{
if (running) {
diff --git a/osdep/terminal.h b/osdep/terminal.h
index b2336b68a8..fc98f0c469 100644
--- a/osdep/terminal.h
+++ b/osdep/terminal.h
@@ -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);
diff --git a/player/playloop.c b/player/playloop.c
index a06165dfce..d6451083ac 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -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();
}
}