mirror of
https://github.com/mpv-player/mpv
synced 2024-12-27 01:22:30 +00:00
7558d1ed7b
libwaio was added due to the complete inability to cancel synchronous
I/O cleanly using the public Windows API in Windows XP. Even calling
TerminateThread on the thread performing I/O was a bad solution, because
the TerminateThread function in XP would leak the thread's stack.
In Vista and up, however, this is no longer a problem. CancelIoEx can
cancel synchronous I/O running on other threads, allowing the thread to
exit cleanly, so replace libwaio usage with native Vista API functions.
It should be noted that this change also removes the hack added in
8a27025
for preventing a deadlock that only seemed to happen in Windows
XP. KB2009703 says that Vista and up are not affected by this, due to a
change in the implementation of GetFileType, so the hack should not be
needed anymore.
111 lines
3.0 KiB
C
111 lines
3.0 KiB
C
/*
|
|
* This file is part of mpv.
|
|
*
|
|
* mpv is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* mpv is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
|
|
#include "common/msg.h"
|
|
#include "osdep/atomics.h"
|
|
#include "osdep/io.h"
|
|
#include "input.h"
|
|
|
|
struct priv {
|
|
atomic_bool cancel_requested;
|
|
int fd;
|
|
bool close_fd;
|
|
HANDLE file;
|
|
HANDLE thread;
|
|
};
|
|
|
|
static void request_cancel(struct mp_input_src *src)
|
|
{
|
|
struct priv *p = src->priv;
|
|
|
|
MP_VERBOSE(src, "Exiting...\n");
|
|
atomic_store(&p->cancel_requested, true);
|
|
|
|
// The thread might not be peforming I/O at the exact moment when
|
|
// CancelIoEx is called, so call it in a loop until it succeeds or the
|
|
// thread exits
|
|
do {
|
|
if (CancelIoEx(p->file, NULL))
|
|
break;
|
|
} while (WaitForSingleObject(p->thread, 1) != WAIT_OBJECT_0);
|
|
}
|
|
|
|
static void uninit(struct mp_input_src *src)
|
|
{
|
|
struct priv *p = src->priv;
|
|
|
|
CloseHandle(p->thread);
|
|
if (p->close_fd)
|
|
close(p->fd);
|
|
|
|
MP_VERBOSE(src, "Exited.\n");
|
|
}
|
|
|
|
static void read_pipe_thread(struct mp_input_src *src, void *param)
|
|
{
|
|
char *filename = talloc_strdup(src, param);
|
|
struct priv *p = talloc_zero(src, struct priv);
|
|
|
|
p->fd = -1;
|
|
p->close_fd = true;
|
|
if (strcmp(filename, "/dev/stdin") == 0) { // for symmetry with unix
|
|
p->fd = STDIN_FILENO;
|
|
p->close_fd = false;
|
|
}
|
|
if (p->fd < 0)
|
|
p->fd = open(filename, O_RDONLY);
|
|
if (p->fd < 0) {
|
|
MP_ERR(src, "Can't open %s.\n", filename);
|
|
return;
|
|
}
|
|
|
|
p->file = (HANDLE)_get_osfhandle(p->fd);
|
|
if (!p->file || p->file == INVALID_HANDLE_VALUE) {
|
|
MP_ERR(src, "Can't open %s.\n", filename);
|
|
return;
|
|
}
|
|
|
|
atomic_store(&p->cancel_requested, false);
|
|
if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
|
GetCurrentProcess(), &p->thread, SYNCHRONIZE, FALSE, 0))
|
|
return;
|
|
|
|
src->priv = p;
|
|
src->cancel = request_cancel;
|
|
src->uninit = uninit;
|
|
mp_input_src_init_done(src);
|
|
|
|
char buffer[4096];
|
|
while (!atomic_load(&p->cancel_requested)) {
|
|
DWORD r;
|
|
if (!ReadFile(p->file, buffer, 4096, &r, NULL)) {
|
|
if (GetLastError() != ERROR_OPERATION_ABORTED)
|
|
MP_ERR(src, "Read operation failed.\n");
|
|
break;
|
|
}
|
|
mp_input_src_feed_cmd_text(src, buffer, r);
|
|
}
|
|
}
|
|
|
|
void mp_input_pipe_add(struct input_ctx *ictx, const char *filename)
|
|
{
|
|
mp_input_add_thread_src(ictx, (void *)filename, read_pipe_thread);
|
|
}
|