mirror of https://github.com/xemu-project/xemu.git
win32-related misc patches
-----BEGIN PGP SIGNATURE----- iQJPBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmNG488cHG1hcmNhbmRy ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5eQTD/j/rEcONwL4gZn/Rcp8 aJlr39GEHo0JxBAF3eoxCLJlebPcdaUQ4pu/FTegS1A4abPaajDH7rdtcA58ciAG rCQjUOrobHzxmI9XaTIPT4PQh3DA4HB58rTpAvb/6P/UDRc0MpkcvaOkGlJVhi+7 WB63+gnQOBEjcieNcQtmRwYRkx7K5/9G4qEESl0i2E+SE4DM+/vcVa7lfqEZ+6HS bsDy2BslxtPFmHj1UElwXjTbCs4Y7pfTFd+9z8ySsGL1Komf45MZs0iS4FmZLqL/ 7Cuj+xRWibnPN9jnAc+Sdua3FAFZbqmfPQaH6DN6SICZ6Txf2hxFkAgTahagcxYX 9EiKGHZzI4L3l/YAxFg9RfK+AsF44ZLPId58AVvUnG1jWwxl3nRaTmvtvHaEwJuZ PgnbAdsNzQAJjLnk8ndpTq4mQFM+9/mrQo+iaOCwmB5s07woyEq+L+KJHMUgyk2D lECn3vlqVGGb6GA6MS5gSXh0TDRxPxLyr9ofIG5i5YaTo4nH56S80tHrzZMUYNKD xe2yUrEZ7UjeV4/6M19xdw3haPOdrG3BoBshb61vI1bF/4iQxYNo8AxptCRhzNNM 5Jrn/gyt47SEgMYpGIvHa/qo1lQiLsQAVKAK3O2QWd5T58V6J1a804zhTuT7T45O kZS2c8XEdAiBtUAkYNgFxwGM =Lpqm -----END PGP SIGNATURE----- Merge tag 'win32-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging win32-related misc patches # -----BEGIN PGP SIGNATURE----- # # iQJPBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmNG488cHG1hcmNhbmRy # ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5eQTD/j/rEcONwL4gZn/Rcp8 # aJlr39GEHo0JxBAF3eoxCLJlebPcdaUQ4pu/FTegS1A4abPaajDH7rdtcA58ciAG # rCQjUOrobHzxmI9XaTIPT4PQh3DA4HB58rTpAvb/6P/UDRc0MpkcvaOkGlJVhi+7 # WB63+gnQOBEjcieNcQtmRwYRkx7K5/9G4qEESl0i2E+SE4DM+/vcVa7lfqEZ+6HS # bsDy2BslxtPFmHj1UElwXjTbCs4Y7pfTFd+9z8ySsGL1Komf45MZs0iS4FmZLqL/ # 7Cuj+xRWibnPN9jnAc+Sdua3FAFZbqmfPQaH6DN6SICZ6Txf2hxFkAgTahagcxYX # 9EiKGHZzI4L3l/YAxFg9RfK+AsF44ZLPId58AVvUnG1jWwxl3nRaTmvtvHaEwJuZ # PgnbAdsNzQAJjLnk8ndpTq4mQFM+9/mrQo+iaOCwmB5s07woyEq+L+KJHMUgyk2D # lECn3vlqVGGb6GA6MS5gSXh0TDRxPxLyr9ofIG5i5YaTo4nH56S80tHrzZMUYNKD # xe2yUrEZ7UjeV4/6M19xdw3haPOdrG3BoBshb61vI1bF/4iQxYNo8AxptCRhzNNM # 5Jrn/gyt47SEgMYpGIvHa/qo1lQiLsQAVKAK3O2QWd5T58V6J1a804zhTuT7T45O # kZS2c8XEdAiBtUAkYNgFxwGM # =Lpqm # -----END PGP SIGNATURE----- # gpg: Signature made Wed 12 Oct 2022 11:57:03 EDT # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * tag 'win32-pull-request' of https://gitlab.com/marcandre.lureau/qemu: tests/unit: make test-io-channel-command work on win32 io/command: implement support for win32 io/command: use glib GSpawn, instead of open-coding fork/exec tests/channel-helper: set blocking in main thread util: make do_send_recv work with partial send/recv osdep: make readv_writev() work with partial read/write win32: set threads name Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
644eb9ceb4
|
@ -41,7 +41,10 @@ struct QIOChannelCommand {
|
||||||
QIOChannel parent;
|
QIOChannel parent;
|
||||||
int writefd;
|
int writefd;
|
||||||
int readfd;
|
int readfd;
|
||||||
pid_t pid;
|
GPid pid;
|
||||||
|
#ifdef WIN32
|
||||||
|
bool blocking;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,11 @@
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
/**
|
/**
|
||||||
* qio_channel_command_new_pid:
|
* qio_channel_command_new_pid:
|
||||||
* @writefd: the FD connected to the command's stdin
|
* @writefd: the FD connected to the command's stdin
|
||||||
* @readfd: the FD connected to the command's stdout
|
* @readfd: the FD connected to the command's stdout
|
||||||
* @pid: the PID of the running child command
|
* @pid: the PID/HANDLE of the running child command
|
||||||
* @errp: pointer to a NULL-initialized error object
|
* @errp: pointer to a NULL-initialized error object
|
||||||
*
|
*
|
||||||
* Create a channel for performing I/O with the
|
* Create a channel for performing I/O with the
|
||||||
|
@ -50,7 +49,7 @@
|
||||||
static QIOChannelCommand *
|
static QIOChannelCommand *
|
||||||
qio_channel_command_new_pid(int writefd,
|
qio_channel_command_new_pid(int writefd,
|
||||||
int readfd,
|
int readfd,
|
||||||
pid_t pid)
|
GPid pid)
|
||||||
{
|
{
|
||||||
QIOChannelCommand *ioc;
|
QIOChannelCommand *ioc;
|
||||||
|
|
||||||
|
@ -60,7 +59,13 @@ qio_channel_command_new_pid(int writefd,
|
||||||
ioc->writefd = writefd;
|
ioc->writefd = writefd;
|
||||||
ioc->pid = pid;
|
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;
|
return ioc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,108 +74,26 @@ qio_channel_command_new_spawn(const char *const argv[],
|
||||||
int flags,
|
int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
pid_t pid = -1;
|
g_autoptr(GError) err = NULL;
|
||||||
int stdinfd[2] = { -1, -1 };
|
GPid pid = 0;
|
||||||
int stdoutfd[2] = { -1, -1 };
|
GSpawnFlags gflags = G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD;
|
||||||
int devnull = -1;
|
int stdinfd = -1, stdoutfd = -1;
|
||||||
bool stdinnull = false, stdoutnull = false;
|
|
||||||
QIOChannelCommand *ioc;
|
|
||||||
|
|
||||||
flags = flags & O_ACCMODE;
|
flags = flags & O_ACCMODE;
|
||||||
|
gflags |= flags == O_WRONLY ? G_SPAWN_STDOUT_TO_DEV_NULL : 0;
|
||||||
|
|
||||||
if (flags == O_RDONLY) {
|
if (!g_spawn_async_with_pipes(NULL, (char **)argv, NULL, gflags, NULL, NULL,
|
||||||
stdinnull = true;
|
&pid,
|
||||||
}
|
flags == O_RDONLY ? NULL : &stdinfd,
|
||||||
if (flags == O_WRONLY) {
|
flags == O_WRONLY ? NULL : &stdoutfd,
|
||||||
stdoutnull = true;
|
NULL, &err)) {
|
||||||
|
error_setg(errp, "%s", err->message);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stdinnull || stdoutnull) {
|
return qio_channel_command_new_pid(stdinfd, stdoutfd, pid);
|
||||||
devnull = open("/dev/null", O_RDWR);
|
|
||||||
if (devnull < 0) {
|
|
||||||
error_setg_errno(errp, errno,
|
|
||||||
"Unable to open /dev/null");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!stdinnull && !g_unix_open_pipe(stdinfd, FD_CLOEXEC, NULL)) ||
|
|
||||||
(!stdoutnull && !g_unix_open_pipe(stdoutfd, FD_CLOEXEC, NULL))) {
|
|
||||||
error_setg_errno(errp, errno,
|
|
||||||
"Unable to open pipe");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = qemu_fork(errp);
|
|
||||||
if (pid < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid == 0) { /* child */
|
|
||||||
dup2(stdinnull ? devnull : stdinfd[0], STDIN_FILENO);
|
|
||||||
dup2(stdoutnull ? devnull : stdoutfd[1], STDOUT_FILENO);
|
|
||||||
/* Leave stderr connected to qemu's stderr */
|
|
||||||
|
|
||||||
if (!stdinnull) {
|
|
||||||
close(stdinfd[0]);
|
|
||||||
close(stdinfd[1]);
|
|
||||||
}
|
|
||||||
if (!stdoutnull) {
|
|
||||||
close(stdoutfd[0]);
|
|
||||||
close(stdoutfd[1]);
|
|
||||||
}
|
|
||||||
if (devnull != -1) {
|
|
||||||
close(devnull);
|
|
||||||
}
|
|
||||||
|
|
||||||
execv(argv[0], (char * const *)argv);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stdinnull) {
|
|
||||||
close(stdinfd[0]);
|
|
||||||
}
|
|
||||||
if (!stdoutnull) {
|
|
||||||
close(stdoutfd[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ioc = qio_channel_command_new_pid(stdinnull ? devnull : stdinfd[1],
|
|
||||||
stdoutnull ? devnull : stdoutfd[0],
|
|
||||||
pid);
|
|
||||||
trace_qio_channel_command_new_spawn(ioc, argv[0], flags);
|
|
||||||
return ioc;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (devnull != -1) {
|
|
||||||
close(devnull);
|
|
||||||
}
|
|
||||||
if (stdinfd[0] != -1) {
|
|
||||||
close(stdinfd[0]);
|
|
||||||
}
|
|
||||||
if (stdinfd[1] != -1) {
|
|
||||||
close(stdinfd[1]);
|
|
||||||
}
|
|
||||||
if (stdoutfd[0] != -1) {
|
|
||||||
close(stdoutfd[0]);
|
|
||||||
}
|
|
||||||
if (stdoutfd[1] != -1) {
|
|
||||||
close(stdoutfd[1]);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
#ifndef WIN32
|
||||||
static int qio_channel_command_abort(QIOChannelCommand *ioc,
|
static int qio_channel_command_abort(QIOChannelCommand *ioc,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
|
@ -213,6 +136,23 @@ static int qio_channel_command_abort(QIOChannelCommand *ioc,
|
||||||
|
|
||||||
return 0;
|
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 */
|
#endif /* ! WIN32 */
|
||||||
|
|
||||||
|
|
||||||
|
@ -221,7 +161,7 @@ static void qio_channel_command_init(Object *obj)
|
||||||
QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj);
|
QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj);
|
||||||
ioc->readfd = -1;
|
ioc->readfd = -1;
|
||||||
ioc->writefd = -1;
|
ioc->writefd = -1;
|
||||||
ioc->pid = -1;
|
ioc->pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qio_channel_command_finalize(Object *obj)
|
static void qio_channel_command_finalize(Object *obj)
|
||||||
|
@ -236,12 +176,27 @@ static void qio_channel_command_finalize(Object *obj)
|
||||||
}
|
}
|
||||||
ioc->writefd = ioc->readfd = -1;
|
ioc->writefd = ioc->readfd = -1;
|
||||||
if (ioc->pid > 0) {
|
if (ioc->pid > 0) {
|
||||||
#ifndef WIN32
|
|
||||||
qio_channel_command_abort(ioc, NULL);
|
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,
|
static ssize_t qio_channel_command_readv(QIOChannel *ioc,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
|
@ -253,6 +208,12 @@ static ssize_t qio_channel_command_readv(QIOChannel *ioc,
|
||||||
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
|
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (!cioc->blocking && !win32_fd_poll(cioc->readfd, G_IO_IN)) {
|
||||||
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
ret = readv(cioc->readfd, iov, niov);
|
ret = readv(cioc->readfd, iov, niov);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -282,6 +243,12 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc,
|
||||||
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
|
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (!cioc->blocking && !win32_fd_poll(cioc->writefd, G_IO_OUT)) {
|
||||||
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
ret = writev(cioc->writefd, iov, niov);
|
ret = writev(cioc->writefd, iov, niov);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
|
@ -302,14 +269,14 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
|
||||||
bool enabled,
|
bool enabled,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
|
||||||
/* command spawn is not supported on win32 */
|
|
||||||
g_assert_not_reached();
|
|
||||||
#else
|
|
||||||
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
|
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
|
||||||
|
|
||||||
if (!g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL) ||
|
#ifdef WIN32
|
||||||
!g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL)) {
|
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");
|
error_setg_errno(errp, errno, "Failed to set FD nonblocking");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -350,6 +317,8 @@ static int qio_channel_command_close(QIOChannel *ioc,
|
||||||
(unsigned long long)cioc->pid);
|
(unsigned long long)cioc->pid);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
WaitForSingleObject(cioc->pid, INFINITE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
struct QIOChannelTest {
|
struct QIOChannelTest {
|
||||||
QIOChannel *src;
|
QIOChannel *src;
|
||||||
QIOChannel *dst;
|
QIOChannel *dst;
|
||||||
bool blocking;
|
|
||||||
size_t len;
|
size_t len;
|
||||||
size_t niov;
|
size_t niov;
|
||||||
char *input;
|
char *input;
|
||||||
|
@ -42,8 +41,6 @@ static gpointer test_io_thread_writer(gpointer opaque)
|
||||||
{
|
{
|
||||||
QIOChannelTest *data = opaque;
|
QIOChannelTest *data = opaque;
|
||||||
|
|
||||||
qio_channel_set_blocking(data->src, data->blocking, NULL);
|
|
||||||
|
|
||||||
qio_channel_writev_all(data->src,
|
qio_channel_writev_all(data->src,
|
||||||
data->inputv,
|
data->inputv,
|
||||||
data->niov,
|
data->niov,
|
||||||
|
@ -58,8 +55,6 @@ static gpointer test_io_thread_reader(gpointer opaque)
|
||||||
{
|
{
|
||||||
QIOChannelTest *data = opaque;
|
QIOChannelTest *data = opaque;
|
||||||
|
|
||||||
qio_channel_set_blocking(data->dst, data->blocking, NULL);
|
|
||||||
|
|
||||||
qio_channel_readv_all(data->dst,
|
qio_channel_readv_all(data->dst,
|
||||||
data->outputv,
|
data->outputv,
|
||||||
data->niov,
|
data->niov,
|
||||||
|
@ -113,7 +108,9 @@ void qio_channel_test_run_threads(QIOChannelTest *test,
|
||||||
|
|
||||||
test->src = src;
|
test->src = src;
|
||||||
test->dst = dst;
|
test->dst = dst;
|
||||||
test->blocking = blocking;
|
|
||||||
|
qio_channel_set_blocking(test->dst, blocking, NULL);
|
||||||
|
qio_channel_set_blocking(test->src, blocking, NULL);
|
||||||
|
|
||||||
reader = g_thread_new("reader",
|
reader = g_thread_new("reader",
|
||||||
test_io_thread_reader,
|
test_io_thread_reader,
|
||||||
|
|
|
@ -24,29 +24,30 @@
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
|
|
||||||
#ifndef WIN32
|
#define TEST_FIFO "test-io-channel-command.fifo"
|
||||||
|
|
||||||
|
#define SOCAT_SRC "PIPE:" TEST_FIFO ",wronly"
|
||||||
|
#define SOCAT_DST "PIPE:" TEST_FIFO ",rdonly"
|
||||||
|
|
||||||
|
static char *socat = NULL;
|
||||||
|
|
||||||
static void test_io_channel_command_fifo(bool async)
|
static void test_io_channel_command_fifo(bool async)
|
||||||
{
|
{
|
||||||
#define TEST_FIFO "tests/test-io-channel-command.fifo"
|
|
||||||
QIOChannel *src, *dst;
|
QIOChannel *src, *dst;
|
||||||
QIOChannelTest *test;
|
QIOChannelTest *test;
|
||||||
const char *srcfifo = "PIPE:" TEST_FIFO ",wronly";
|
|
||||||
const char *dstfifo = "PIPE:" TEST_FIFO ",rdonly";
|
|
||||||
const char *srcargv[] = {
|
const char *srcargv[] = {
|
||||||
"/bin/socat", "-", srcfifo, NULL,
|
socat, "-", SOCAT_SRC, NULL,
|
||||||
};
|
};
|
||||||
const char *dstargv[] = {
|
const char *dstargv[] = {
|
||||||
"/bin/socat", dstfifo, "-", NULL,
|
socat, SOCAT_DST, "-", NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
unlink(TEST_FIFO);
|
if (!socat) {
|
||||||
if (access("/bin/socat", X_OK) < 0) {
|
g_test_skip("socat is not found in PATH");
|
||||||
g_test_skip("socat is missing");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mkfifo(TEST_FIFO, 0600) < 0) {
|
|
||||||
abort();
|
unlink(TEST_FIFO);
|
||||||
}
|
|
||||||
src = QIO_CHANNEL(qio_channel_command_new_spawn(srcargv,
|
src = QIO_CHANNEL(qio_channel_command_new_spawn(srcargv,
|
||||||
O_WRONLY,
|
O_WRONLY,
|
||||||
&error_abort));
|
&error_abort));
|
||||||
|
@ -81,11 +82,12 @@ static void test_io_channel_command_echo(bool async)
|
||||||
QIOChannel *ioc;
|
QIOChannel *ioc;
|
||||||
QIOChannelTest *test;
|
QIOChannelTest *test;
|
||||||
const char *socatargv[] = {
|
const char *socatargv[] = {
|
||||||
"/bin/socat", "-", "-", NULL,
|
socat, "-", "-", NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (access("/bin/socat", X_OK) < 0) {
|
if (!socat) {
|
||||||
return; /* Pretend success if socat is not present */
|
g_test_skip("socat is not found in PATH");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(socatargv,
|
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(socatargv,
|
||||||
|
@ -108,7 +110,6 @@ static void test_io_channel_command_echo_sync(void)
|
||||||
{
|
{
|
||||||
test_io_channel_command_echo(false);
|
test_io_channel_command_echo(false);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -116,7 +117,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
|
||||||
#ifndef WIN32
|
socat = g_find_program_in_path("socat");
|
||||||
|
|
||||||
g_test_add_func("/io/channel/command/fifo/sync",
|
g_test_add_func("/io/channel/command/fifo/sync",
|
||||||
test_io_channel_command_fifo_sync);
|
test_io_channel_command_fifo_sync);
|
||||||
g_test_add_func("/io/channel/command/fifo/async",
|
g_test_add_func("/io/channel/command/fifo/async",
|
||||||
|
@ -125,7 +127,6 @@ int main(int argc, char **argv)
|
||||||
test_io_channel_command_echo_sync);
|
test_io_channel_command_echo_sync);
|
||||||
g_test_add_func("/io/channel/command/echo/async",
|
g_test_add_func("/io/channel/command/echo/async",
|
||||||
test_io_channel_command_echo_async);
|
test_io_channel_command_echo_async);
|
||||||
#endif
|
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|
10
util/iov.c
10
util/iov.c
|
@ -111,12 +111,17 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||||
/*XXX Note: windows has WSASend() and WSARecv() */
|
/*XXX Note: windows has WSASend() and WSARecv() */
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
|
ssize_t off = 0;
|
||||||
while (i < iov_cnt) {
|
while (i < iov_cnt) {
|
||||||
ssize_t r = do_send
|
ssize_t r = do_send
|
||||||
? send(sockfd, iov[i].iov_base, iov[i].iov_len, 0)
|
? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0)
|
||||||
: recv(sockfd, iov[i].iov_base, iov[i].iov_len, 0);
|
: recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0);
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
ret += r;
|
ret += r;
|
||||||
|
off += r;
|
||||||
|
if (off < iov[i].iov_len) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else if (!r) {
|
} else if (!r) {
|
||||||
break;
|
break;
|
||||||
} else if (errno == EINTR) {
|
} else if (errno == EINTR) {
|
||||||
|
@ -129,6 +134,7 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
off = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
11
util/osdep.c
11
util/osdep.c
|
@ -538,18 +538,22 @@ int socket_init(void)
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIG_IOVEC
|
#ifndef CONFIG_IOVEC
|
||||||
/* helper function for iov_send_recv() */
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
|
readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
|
||||||
{
|
{
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
|
ssize_t off = 0;
|
||||||
while (i < iov_cnt) {
|
while (i < iov_cnt) {
|
||||||
ssize_t r = do_write
|
ssize_t r = do_write
|
||||||
? write(fd, iov[i].iov_base, iov[i].iov_len)
|
? write(fd, iov[i].iov_base + off, iov[i].iov_len - off)
|
||||||
: read(fd, iov[i].iov_base, iov[i].iov_len);
|
: read(fd, iov[i].iov_base + off, iov[i].iov_len - off);
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
ret += r;
|
ret += r;
|
||||||
|
off += r;
|
||||||
|
if (off < iov[i].iov_len) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else if (!r) {
|
} else if (!r) {
|
||||||
break;
|
break;
|
||||||
} else if (errno == EINTR) {
|
} else if (errno == EINTR) {
|
||||||
|
@ -562,6 +566,7 @@ readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
off = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -19,12 +19,39 @@
|
||||||
|
|
||||||
static bool name_threads;
|
static bool name_threads;
|
||||||
|
|
||||||
|
typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread,
|
||||||
|
PCWSTR lpThreadDescription);
|
||||||
|
static pSetThreadDescription SetThreadDescriptionFunc;
|
||||||
|
static HMODULE kernel32_module;
|
||||||
|
|
||||||
|
static bool load_set_thread_description(void)
|
||||||
|
{
|
||||||
|
static gsize _init_once = 0;
|
||||||
|
|
||||||
|
if (g_once_init_enter(&_init_once)) {
|
||||||
|
kernel32_module = LoadLibrary("kernel32.dll");
|
||||||
|
if (kernel32_module) {
|
||||||
|
SetThreadDescriptionFunc =
|
||||||
|
(pSetThreadDescription)GetProcAddress(kernel32_module,
|
||||||
|
"SetThreadDescription");
|
||||||
|
if (!SetThreadDescriptionFunc) {
|
||||||
|
FreeLibrary(kernel32_module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_once_init_leave(&_init_once, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!SetThreadDescriptionFunc;
|
||||||
|
}
|
||||||
|
|
||||||
void qemu_thread_naming(bool enable)
|
void qemu_thread_naming(bool enable)
|
||||||
{
|
{
|
||||||
/* But note we don't actually name them on Windows yet */
|
|
||||||
name_threads = enable;
|
name_threads = enable;
|
||||||
|
|
||||||
fprintf(stderr, "qemu: thread naming not supported on this host\n");
|
if (enable && !load_set_thread_description()) {
|
||||||
|
fprintf(stderr, "qemu: thread naming not supported on this host\n");
|
||||||
|
name_threads = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void error_exit(int err, const char *msg)
|
static void error_exit(int err, const char *msg)
|
||||||
|
@ -400,6 +427,25 @@ void *qemu_thread_join(QemuThread *thread)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool set_thread_description(HANDLE h, const char *name)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
g_autofree wchar_t *namew = NULL;
|
||||||
|
|
||||||
|
if (!load_set_thread_description()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
namew = g_utf8_to_utf16(name, -1, NULL, NULL, NULL);
|
||||||
|
if (!namew) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = SetThreadDescriptionFunc(h, namew);
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
void qemu_thread_create(QemuThread *thread, const char *name,
|
void qemu_thread_create(QemuThread *thread, const char *name,
|
||||||
void *(*start_routine)(void *),
|
void *(*start_routine)(void *),
|
||||||
void *arg, int mode)
|
void *arg, int mode)
|
||||||
|
@ -423,7 +469,11 @@ void qemu_thread_create(QemuThread *thread, const char *name,
|
||||||
if (!hThread) {
|
if (!hThread) {
|
||||||
error_exit(GetLastError(), __func__);
|
error_exit(GetLastError(), __func__);
|
||||||
}
|
}
|
||||||
|
if (name_threads && name && !set_thread_description(hThread, name)) {
|
||||||
|
fprintf(stderr, "qemu: failed to set thread description: %s\n", name);
|
||||||
|
}
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
|
|
||||||
thread->data = data;
|
thread->data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue