diff --git a/include/io/channel-command.h b/include/io/channel-command.h index 8dc58273c0..98934e6d9e 100644 --- a/include/io/channel-command.h +++ b/include/io/channel-command.h @@ -42,6 +42,9 @@ struct QIOChannelCommand { int writefd; int readfd; GPid pid; +#ifdef WIN32 + bool blocking; +#endif }; diff --git a/io/channel-command.c b/io/channel-command.c index f84d1f03a0..74516252ba 100644 --- a/io/channel-command.c +++ b/io/channel-command.c @@ -26,7 +26,6 @@ #include "qemu/sockets.h" #include "trace.h" -#ifndef WIN32 /** * qio_channel_command_new_pid: * @writefd: the FD connected to the command's stdin @@ -60,7 +59,13 @@ qio_channel_command_new_pid(int writefd, ioc->writefd = writefd; ioc->pid = pid; - trace_qio_channel_command_new_pid(ioc, writefd, readfd, pid); + trace_qio_channel_command_new_pid(ioc, writefd, readfd, +#ifdef WIN32 + GetProcessId(pid) +#else + pid +#endif + ); return ioc; } @@ -89,18 +94,6 @@ qio_channel_command_new_spawn(const char *const argv[], return qio_channel_command_new_pid(stdinfd, stdoutfd, pid); } -#else /* WIN32 */ -QIOChannelCommand * -qio_channel_command_new_spawn(const char *const argv[], - int flags, - Error **errp) -{ - error_setg_errno(errp, ENOSYS, - "Command spawn not supported on this platform"); - return NULL; -} -#endif /* WIN32 */ - #ifndef WIN32 static int qio_channel_command_abort(QIOChannelCommand *ioc, Error **errp) @@ -143,6 +136,23 @@ static int qio_channel_command_abort(QIOChannelCommand *ioc, return 0; } +#else +static int qio_channel_command_abort(QIOChannelCommand *ioc, + Error **errp) +{ + DWORD ret; + + TerminateProcess(ioc->pid, 0); + ret = WaitForSingleObject(ioc->pid, 1000); + if (ret != WAIT_OBJECT_0) { + error_setg(errp, + "Process %llu refused to die", + (unsigned long long)GetProcessId(ioc->pid)); + return -1; + } + + return 0; +} #endif /* ! WIN32 */ @@ -166,13 +176,27 @@ static void qio_channel_command_finalize(Object *obj) } ioc->writefd = ioc->readfd = -1; if (ioc->pid > 0) { -#ifndef WIN32 qio_channel_command_abort(ioc, NULL); -#endif g_spawn_close_pid(ioc->pid); } } +#ifdef WIN32 +static bool win32_fd_poll(int fd, gushort events) +{ + GPollFD pfd = { .fd = _get_osfhandle(fd), .events = events }; + int res; + + do { + res = g_poll(&pfd, 1, 0); + } while (res < 0 && errno == EINTR); + if (res == 0) { + return false; + } + + return true; +} +#endif static ssize_t qio_channel_command_readv(QIOChannel *ioc, const struct iovec *iov, @@ -184,6 +208,12 @@ static ssize_t qio_channel_command_readv(QIOChannel *ioc, QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); ssize_t ret; +#ifdef WIN32 + if (!cioc->blocking && !win32_fd_poll(cioc->readfd, G_IO_IN)) { + return QIO_CHANNEL_ERR_BLOCK; + } +#endif + retry: ret = readv(cioc->readfd, iov, niov); if (ret < 0) { @@ -213,6 +243,12 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc, QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); ssize_t ret; +#ifdef WIN32 + if (!cioc->blocking && !win32_fd_poll(cioc->writefd, G_IO_OUT)) { + return QIO_CHANNEL_ERR_BLOCK; + } +#endif + retry: ret = writev(cioc->writefd, iov, niov); if (ret <= 0) { @@ -233,14 +269,14 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc, bool enabled, Error **errp) { -#ifdef WIN32 - /* command spawn is not supported on win32 */ - g_assert_not_reached(); -#else QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); - if (!g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL) || - !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL)) { +#ifdef WIN32 + cioc->blocking = enabled; +#else + + if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) || + (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) { error_setg_errno(errp, errno, "Failed to set FD nonblocking"); return -1; } @@ -281,6 +317,8 @@ static int qio_channel_command_close(QIOChannel *ioc, (unsigned long long)cioc->pid); return -1; } +#else + WaitForSingleObject(cioc->pid, INFINITE); #endif if (rv < 0) {