input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#ifndef __MINGW32__
|
|
|
|
#include <poll.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "common/msg.h"
|
2014-08-29 10:09:04 +00:00
|
|
|
#include "misc/bstr.h"
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
#include "osdep/io.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "cmd_parse.h"
|
|
|
|
|
|
|
|
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
struct priv {
|
|
|
|
struct mp_log *log;
|
|
|
|
char *filename;
|
|
|
|
struct mp_input_src *src;
|
|
|
|
int wakeup_pipe[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *reader_thread(void *ctx)
|
|
|
|
{
|
|
|
|
struct priv *p = ctx;
|
|
|
|
pthread_detach(pthread_self());
|
|
|
|
|
|
|
|
int mode = O_RDONLY;
|
|
|
|
#ifndef __MINGW32__
|
|
|
|
// Use RDWR for FIFOs to ensure they stay open over multiple accesses.
|
|
|
|
// Note that on Windows due to how the API works, using RDONLY should
|
|
|
|
// be ok.
|
|
|
|
struct stat st;
|
|
|
|
if (stat(p->filename, &st) == 0 && S_ISFIFO(st.st_mode))
|
|
|
|
mode = O_RDWR;
|
|
|
|
#endif
|
|
|
|
int fd = -1;
|
|
|
|
bool close_fd = true;
|
|
|
|
if (strcmp(p->filename, "/dev/stdin") == 0) { // mainly for win32
|
2014-08-28 04:22:13 +00:00
|
|
|
fd = STDIN_FILENO;
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
close_fd = false;
|
|
|
|
}
|
|
|
|
if (fd < 0)
|
|
|
|
fd = open(p->filename, mode);
|
|
|
|
if (fd < 0) {
|
|
|
|
MP_ERR(p, "Can't open %s.\n", p->filename);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
#ifndef __MINGW32__
|
|
|
|
struct pollfd fds[2] = {
|
|
|
|
{ .fd = fd, .events = POLLIN },
|
|
|
|
{ .fd = p->wakeup_pipe[0], .events = POLLIN },
|
|
|
|
};
|
|
|
|
poll(fds, 2, -1);
|
|
|
|
if (!(fds[0].revents & POLLIN))
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
char buffer[128];
|
|
|
|
int r = read(fd, buffer, sizeof(buffer));
|
|
|
|
if (r <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&lock);
|
|
|
|
if (!p->src) {
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mp_input_src_feed_cmd_text(p->src, buffer, r);
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close_fd)
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
done:
|
|
|
|
pthread_mutex_lock(&lock);
|
|
|
|
if (p->src)
|
|
|
|
p->src->priv = NULL;
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
close(p->wakeup_pipe[0]);
|
|
|
|
close(p->wakeup_pipe[1]);
|
|
|
|
talloc_free(p);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void close_pipe(struct mp_input_src *src)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&lock);
|
|
|
|
struct priv *p = src->priv;
|
|
|
|
// Windows pipe have a severe problem: they can't be made non-blocking (not
|
|
|
|
// after creation), and you can't wait on them. The only things that work
|
|
|
|
// are cancellation (Vista+, broken in wine) or forceful thread termination.
|
|
|
|
// So don't bother with "correct" termination, and just abandon the reader
|
|
|
|
// thread.
|
|
|
|
// On Unix, we interrupt it using the wakeup pipe.
|
|
|
|
if (p) {
|
|
|
|
#ifndef __MINGW32__
|
|
|
|
write(p->wakeup_pipe[1], &(char){0}, 1);
|
|
|
|
#endif
|
|
|
|
p->src = NULL;
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_add_pipe(struct input_ctx *ictx, const char *filename)
|
|
|
|
{
|
|
|
|
struct mp_input_src *src = mp_input_add_src(ictx);
|
|
|
|
if (!src)
|
|
|
|
return;
|
|
|
|
|
|
|
|
struct priv *p = talloc_zero(NULL, struct priv);
|
|
|
|
src->priv = p;
|
|
|
|
p->filename = talloc_strdup(p, filename);
|
|
|
|
p->src = src;
|
|
|
|
p->log = mp_log_new(p, src->log, NULL);
|
|
|
|
mp_make_wakeup_pipe(p->wakeup_pipe);
|
|
|
|
|
|
|
|
pthread_t thread;
|
|
|
|
if (pthread_create(&thread, NULL, reader_thread, p)) {
|
|
|
|
close(p->wakeup_pipe[0]);
|
|
|
|
close(p->wakeup_pipe[1]);
|
|
|
|
talloc_free(p);
|
|
|
|
mp_input_src_kill(src);
|
|
|
|
} else {
|
|
|
|
src->close = close_pipe;
|
|
|
|
}
|
|
|
|
}
|