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:
Stefan Hajnoczi 2022-10-13 13:55:38 -04:00
commit 644eb9ceb4
7 changed files with 171 additions and 140 deletions

View File

@ -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
}; };

View File

@ -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) {

View File

@ -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,

View File

@ -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();
} }

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }