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;
|
||||
int writefd;
|
||||
int readfd;
|
||||
pid_t pid;
|
||||
GPid pid;
|
||||
#ifdef WIN32
|
||||
bool blocking;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -26,12 +26,11 @@
|
||||
#include "qemu/sockets.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifndef WIN32
|
||||
/**
|
||||
* qio_channel_command_new_pid:
|
||||
* @writefd: the FD connected to the command's stdin
|
||||
* @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
|
||||
*
|
||||
* Create a channel for performing I/O with the
|
||||
@ -50,7 +49,7 @@
|
||||
static QIOChannelCommand *
|
||||
qio_channel_command_new_pid(int writefd,
|
||||
int readfd,
|
||||
pid_t pid)
|
||||
GPid pid)
|
||||
{
|
||||
QIOChannelCommand *ioc;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -69,108 +74,26 @@ qio_channel_command_new_spawn(const char *const argv[],
|
||||
int flags,
|
||||
Error **errp)
|
||||
{
|
||||
pid_t pid = -1;
|
||||
int stdinfd[2] = { -1, -1 };
|
||||
int stdoutfd[2] = { -1, -1 };
|
||||
int devnull = -1;
|
||||
bool stdinnull = false, stdoutnull = false;
|
||||
QIOChannelCommand *ioc;
|
||||
g_autoptr(GError) err = NULL;
|
||||
GPid pid = 0;
|
||||
GSpawnFlags gflags = G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD;
|
||||
int stdinfd = -1, stdoutfd = -1;
|
||||
|
||||
flags = flags & O_ACCMODE;
|
||||
gflags |= flags == O_WRONLY ? G_SPAWN_STDOUT_TO_DEV_NULL : 0;
|
||||
|
||||
if (flags == O_RDONLY) {
|
||||
stdinnull = true;
|
||||
}
|
||||
if (flags == O_WRONLY) {
|
||||
stdoutnull = true;
|
||||
if (!g_spawn_async_with_pipes(NULL, (char **)argv, NULL, gflags, NULL, NULL,
|
||||
&pid,
|
||||
flags == O_RDONLY ? NULL : &stdinfd,
|
||||
flags == O_WRONLY ? NULL : &stdoutfd,
|
||||
NULL, &err)) {
|
||||
error_setg(errp, "%s", err->message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stdinnull || stdoutnull) {
|
||||
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;
|
||||
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)
|
||||
@ -213,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 */
|
||||
|
||||
|
||||
@ -221,7 +161,7 @@ static void qio_channel_command_init(Object *obj)
|
||||
QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj);
|
||||
ioc->readfd = -1;
|
||||
ioc->writefd = -1;
|
||||
ioc->pid = -1;
|
||||
ioc->pid = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
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,
|
||||
@ -253,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) {
|
||||
@ -282,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) {
|
||||
@ -302,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;
|
||||
}
|
||||
@ -350,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) {
|
||||
|
@ -25,7 +25,6 @@
|
||||
struct QIOChannelTest {
|
||||
QIOChannel *src;
|
||||
QIOChannel *dst;
|
||||
bool blocking;
|
||||
size_t len;
|
||||
size_t niov;
|
||||
char *input;
|
||||
@ -42,8 +41,6 @@ static gpointer test_io_thread_writer(gpointer opaque)
|
||||
{
|
||||
QIOChannelTest *data = opaque;
|
||||
|
||||
qio_channel_set_blocking(data->src, data->blocking, NULL);
|
||||
|
||||
qio_channel_writev_all(data->src,
|
||||
data->inputv,
|
||||
data->niov,
|
||||
@ -58,8 +55,6 @@ static gpointer test_io_thread_reader(gpointer opaque)
|
||||
{
|
||||
QIOChannelTest *data = opaque;
|
||||
|
||||
qio_channel_set_blocking(data->dst, data->blocking, NULL);
|
||||
|
||||
qio_channel_readv_all(data->dst,
|
||||
data->outputv,
|
||||
data->niov,
|
||||
@ -113,7 +108,9 @@ void qio_channel_test_run_threads(QIOChannelTest *test,
|
||||
|
||||
test->src = src;
|
||||
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",
|
||||
test_io_thread_reader,
|
||||
|
@ -24,29 +24,30 @@
|
||||
#include "qapi/error.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)
|
||||
{
|
||||
#define TEST_FIFO "tests/test-io-channel-command.fifo"
|
||||
QIOChannel *src, *dst;
|
||||
QIOChannelTest *test;
|
||||
const char *srcfifo = "PIPE:" TEST_FIFO ",wronly";
|
||||
const char *dstfifo = "PIPE:" TEST_FIFO ",rdonly";
|
||||
const char *srcargv[] = {
|
||||
"/bin/socat", "-", srcfifo, NULL,
|
||||
socat, "-", SOCAT_SRC, NULL,
|
||||
};
|
||||
const char *dstargv[] = {
|
||||
"/bin/socat", dstfifo, "-", NULL,
|
||||
socat, SOCAT_DST, "-", NULL,
|
||||
};
|
||||
|
||||
unlink(TEST_FIFO);
|
||||
if (access("/bin/socat", X_OK) < 0) {
|
||||
g_test_skip("socat is missing");
|
||||
if (!socat) {
|
||||
g_test_skip("socat is not found in PATH");
|
||||
return;
|
||||
}
|
||||
if (mkfifo(TEST_FIFO, 0600) < 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
unlink(TEST_FIFO);
|
||||
src = QIO_CHANNEL(qio_channel_command_new_spawn(srcargv,
|
||||
O_WRONLY,
|
||||
&error_abort));
|
||||
@ -81,11 +82,12 @@ static void test_io_channel_command_echo(bool async)
|
||||
QIOChannel *ioc;
|
||||
QIOChannelTest *test;
|
||||
const char *socatargv[] = {
|
||||
"/bin/socat", "-", "-", NULL,
|
||||
socat, "-", "-", NULL,
|
||||
};
|
||||
|
||||
if (access("/bin/socat", X_OK) < 0) {
|
||||
return; /* Pretend success if socat is not present */
|
||||
if (!socat) {
|
||||
g_test_skip("socat is not found in PATH");
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -116,7 +117,8 @@ int main(int argc, char **argv)
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
#ifndef WIN32
|
||||
socat = g_find_program_in_path("socat");
|
||||
|
||||
g_test_add_func("/io/channel/command/fifo/sync",
|
||||
test_io_channel_command_fifo_sync);
|
||||
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);
|
||||
g_test_add_func("/io/channel/command/echo/async",
|
||||
test_io_channel_command_echo_async);
|
||||
#endif
|
||||
|
||||
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() */
|
||||
unsigned i = 0;
|
||||
ssize_t ret = 0;
|
||||
ssize_t off = 0;
|
||||
while (i < iov_cnt) {
|
||||
ssize_t r = do_send
|
||||
? send(sockfd, iov[i].iov_base, iov[i].iov_len, 0)
|
||||
: recv(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 + off, iov[i].iov_len - off, 0);
|
||||
if (r > 0) {
|
||||
ret += r;
|
||||
off += r;
|
||||
if (off < iov[i].iov_len) {
|
||||
continue;
|
||||
}
|
||||
} else if (!r) {
|
||||
break;
|
||||
} else if (errno == EINTR) {
|
||||
@ -129,6 +134,7 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||
}
|
||||
break;
|
||||
}
|
||||
off = 0;
|
||||
i++;
|
||||
}
|
||||
return ret;
|
||||
|
11
util/osdep.c
11
util/osdep.c
@ -538,18 +538,22 @@ int socket_init(void)
|
||||
|
||||
|
||||
#ifndef CONFIG_IOVEC
|
||||
/* helper function for iov_send_recv() */
|
||||
static ssize_t
|
||||
readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
|
||||
{
|
||||
unsigned i = 0;
|
||||
ssize_t ret = 0;
|
||||
ssize_t off = 0;
|
||||
while (i < iov_cnt) {
|
||||
ssize_t r = do_write
|
||||
? write(fd, iov[i].iov_base, iov[i].iov_len)
|
||||
: read(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 + off, iov[i].iov_len - off);
|
||||
if (r > 0) {
|
||||
ret += r;
|
||||
off += r;
|
||||
if (off < iov[i].iov_len) {
|
||||
continue;
|
||||
}
|
||||
} else if (!r) {
|
||||
break;
|
||||
} else if (errno == EINTR) {
|
||||
@ -562,6 +566,7 @@ readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
|
||||
}
|
||||
break;
|
||||
}
|
||||
off = 0;
|
||||
i++;
|
||||
}
|
||||
return ret;
|
||||
|
@ -19,12 +19,39 @@
|
||||
|
||||
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)
|
||||
{
|
||||
/* But note we don't actually name them on Windows yet */
|
||||
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)
|
||||
@ -400,6 +427,25 @@ void *qemu_thread_join(QemuThread *thread)
|
||||
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 *(*start_routine)(void *),
|
||||
void *arg, int mode)
|
||||
@ -423,7 +469,11 @@ void qemu_thread_create(QemuThread *thread, const char *name,
|
||||
if (!hThread) {
|
||||
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);
|
||||
|
||||
thread->data = data;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user