This will be used to include the thread name in error reports
in a later patch. It returns a const string stored in a thread
local to avoid memory allocation when it is called repeatedly
in a single thread. The thread name should be set at the very
start of the thread execution, which is the case when using
qemu_thread_create.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
include/qemu/thread.h | 1 +
meson.build | 21 +++++++++++++++++
util/qemu-thread-posix.c | 33 ++++++++++++++++++++++++++-
util/qemu-thread-win32.c | 49 ++++++++++++++++++++++++++++++++++++----
4 files changed, 99 insertions(+), 5 deletions(-)
diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index 27b888ab0a..98cc5c41ac 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -216,6 +216,7 @@ void qemu_thread_get_self(QemuThread *thread);
bool qemu_thread_is_self(QemuThread *thread);
G_NORETURN void qemu_thread_exit(void *retval);
void qemu_thread_set_name(const char *name);
+const char *qemu_thread_get_name(void);
struct Notifier;
/**
diff --git a/meson.build b/meson.build
index db87358d62..eb27aca329 100644
--- a/meson.build
+++ b/meson.build
@@ -2874,6 +2874,27 @@ config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(osdep_prefix + '''
pthread_set_name_np(thread, "QEMU");
return 0;
}''', dependencies: threads))
+
+config_host_data.set('CONFIG_PTHREAD_GETNAME_NP', cc.links(osdep_prefix + '''
+ #include <pthread.h>
+
+ int main(void)
+ {
+ char buf[16];
+ pthread_getname_np(pthread_self(), buf, sizeof(buf));
+ return 0;
+ }''', dependencies: threads))
+config_host_data.set('CONFIG_PTHREAD_GET_NAME_NP', cc.links(osdep_prefix + '''
+ #include <pthread.h>
+ #include <pthread_np.h>
+
+ int main(void)
+ {
+ char buf[16];
+ pthread_get_name_np(pthread_self(), buf, sizeof(buf));
+ return 0;
+ }''', dependencies: threads))
+
config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(osdep_prefix + '''
#include <pthread.h>
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index afeac9ecad..47156b60ce 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -18,7 +18,7 @@
#include "qemu/tsan.h"
#include "qemu/bitmap.h"
-#ifdef CONFIG_PTHREAD_SET_NAME_NP
+#if defined(CONFIG_PTHREAD_SET_NAME_NP) || defined(CONFIG_PTHREAD_GET_NAME_NP)
#include <pthread_np.h>
#endif
@@ -532,3 +532,34 @@ void *qemu_thread_join(QemuThread *thread)
}
return ret;
}
+
+/*
+ * This is not defined on Linux, but the man page indicates
+ * the buffer must be at least 16 bytes, including the NUL
+ * terminator
+ */
+#ifndef PTHREAD_MAX_NAMELEN_NP
+#define PTHREAD_MAX_NAMELEN_NP 16
+#endif
+
+static __thread char namebuf[PTHREAD_MAX_NAMELEN_NP];
+
+const char *qemu_thread_get_name(void)
+{
+ int rv;
+ if (namebuf[0] != '\0') {
+ return namebuf;
+ }
+
+# if defined(CONFIG_PTHREAD_GETNAME_NP)
+ rv = pthread_getname_np(pthread_self(), namebuf, sizeof(namebuf));
+# elif defined(CONFIG_PTHREAD_GET_NAME_NP)
+ rv = pthread_get_name_np(pthread_self(), namebuf, sizeof(namebuf));
+# else
+ rv = -1;
+# endif
+ if (rv != 0) {
+ g_strlcpy(namebuf, "unnamed", G_N_ELEMENTS(namebuf));
+ }
+ return namebuf;
+}
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index 8ca6429ad3..082a38c7d5 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -19,7 +19,10 @@
typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread,
PCWSTR lpThreadDescription);
+typedef HRESULT (WINAPI *pGetThreadDescription) (HANDLE hThread,
+ PWSTR *lpThreadDescription);
static pSetThreadDescription SetThreadDescriptionFunc;
+static pGetThreadDescription GetThreadDescriptionFunc;
static HMODULE kernel32_module;
static void __attribute__((__constructor__(QEMU_CONSTRUCTOR_EARLY)))
@@ -28,7 +31,7 @@ qemu_thread_init(void)
qemu_thread_set_name("main");
}
-static bool load_set_thread_description(void)
+static bool load_thread_description(void)
{
static gsize _init_once = 0;
@@ -38,14 +41,17 @@ static bool load_set_thread_description(void)
SetThreadDescriptionFunc =
(pSetThreadDescription)GetProcAddress(kernel32_module,
"SetThreadDescription");
- if (!SetThreadDescriptionFunc) {
+ GetThreadDescriptionFunc =
+ (pGetThreadDescription)GetProcAddress(kernel32_module,
+ "GetThreadDescription");
+ if (!SetThreadDescriptionFunc || !GetThreadDescriptionFunc) {
FreeLibrary(kernel32_module);
}
}
g_once_init_leave(&_init_once, 1);
}
- return !!SetThreadDescriptionFunc;
+ return (SetThreadDescriptionFunc && GetThreadDescriptionFunc);
}
static void error_exit(int err, const char *msg)
@@ -331,7 +337,7 @@ void qemu_thread_set_name(const char *name)
{
g_autofree wchar_t *namew = NULL;
- if (!load_set_thread_description()) {
+ if (!load_thread_description()) {
return;
}
@@ -415,3 +421,38 @@ bool qemu_thread_is_self(QemuThread *thread)
{
return GetCurrentThreadId() == thread->tid;
}
+
+static __thread char namebuf[64];
+
+const char *qemu_thread_get_name(void)
+{
+ HRESULT hr;
+ wchar_t *namew = NULL;
+ g_autofree char *name = NULL;
+
+ if (namebuf[0] != '\0') {
+ return namebuf;
+ }
+
+ if (!load_thread_description()) {
+ goto error;
+ }
+
+ hr = GetThreadDescriptionFunc(GetCurrentThread(), &namew);
+ if (!SUCCEEDED(hr)) {
+ goto error;
+ }
+
+ name = g_utf16_to_utf8(namew, -1, NULL, NULL, NULL);
+ LocalFree(namew);
+ if (!name) {
+ goto error;
+ }
+
+ g_strlcpy(namebuf, name, G_N_ELEMENTS(namebuf));
+ return namebuf;
+
+ error:
+ g_strlcpy(namebuf, "unnamed", G_N_ELEMENTS(namebuf));
+ return namebuf;
+}
--
2.52.0
Daniel P. Berrangé <berrange@redhat.com> writes: > This will be used to include the thread name in error reports > in a later patch. It returns a const string stored in a thread > local to avoid memory allocation when it is called repeatedly > in a single thread. The thread name should be set at the very > start of the thread execution, which is the case when using > qemu_thread_create. > > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> > --- > include/qemu/thread.h | 1 + > meson.build | 21 +++++++++++++++++ > util/qemu-thread-posix.c | 33 ++++++++++++++++++++++++++- > util/qemu-thread-win32.c | 49 ++++++++++++++++++++++++++++++++++++---- > 4 files changed, 99 insertions(+), 5 deletions(-) Tempted to store the thread name in TLS and call it a day.
On Tue, Jan 13, 2026 at 10:27:04AM +0100, Markus Armbruster wrote: > Daniel P. Berrangé <berrange@redhat.com> writes: > > > This will be used to include the thread name in error reports > > in a later patch. It returns a const string stored in a thread > > local to avoid memory allocation when it is called repeatedly > > in a single thread. The thread name should be set at the very > > start of the thread execution, which is the case when using > > qemu_thread_create. > > > > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> > > --- > > include/qemu/thread.h | 1 + > > meson.build | 21 +++++++++++++++++ > > util/qemu-thread-posix.c | 33 ++++++++++++++++++++++++++- > > util/qemu-thread-win32.c | 49 ++++++++++++++++++++++++++++++++++++---- > > 4 files changed, 99 insertions(+), 5 deletions(-) > > Tempted to store the thread name in TLS and call it a day. Using the official APIs in this way ensures that the thread name is visible outside QEMU. For example when debugging in GDB, which IMHO is an important benefit. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Daniel P. Berrangé <berrange@redhat.com> writes: > On Tue, Jan 13, 2026 at 10:27:04AM +0100, Markus Armbruster wrote: >> Daniel P. Berrangé <berrange@redhat.com> writes: >> >> > This will be used to include the thread name in error reports >> > in a later patch. It returns a const string stored in a thread >> > local to avoid memory allocation when it is called repeatedly >> > in a single thread. The thread name should be set at the very >> > start of the thread execution, which is the case when using >> > qemu_thread_create. >> > >> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> >> > --- >> > include/qemu/thread.h | 1 + >> > meson.build | 21 +++++++++++++++++ >> > util/qemu-thread-posix.c | 33 ++++++++++++++++++++++++++- >> > util/qemu-thread-win32.c | 49 ++++++++++++++++++++++++++++++++++++---- >> > 4 files changed, 99 insertions(+), 5 deletions(-) >> >> Tempted to store the thread name in TLS and call it a day. > > Using the official APIs in this way ensures that the thread name is > visible outside QEMU. For example when debugging in GDB, which IMHO > is an important benefit. I didn't mean to suggest not to set the "official" thread name. This patch retrieves the "official" thread name back. Takes a bit of system-specific code, including Meson magic. We could instead hold on to our own copy, and just use that.
On Tue, Jan 13, 2026 at 02:00:35PM +0100, Markus Armbruster wrote: > Daniel P. Berrangé <berrange@redhat.com> writes: > > > On Tue, Jan 13, 2026 at 10:27:04AM +0100, Markus Armbruster wrote: > >> Daniel P. Berrangé <berrange@redhat.com> writes: > >> > >> > This will be used to include the thread name in error reports > >> > in a later patch. It returns a const string stored in a thread > >> > local to avoid memory allocation when it is called repeatedly > >> > in a single thread. The thread name should be set at the very > >> > start of the thread execution, which is the case when using > >> > qemu_thread_create. > >> > > >> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> > >> > --- > >> > include/qemu/thread.h | 1 + > >> > meson.build | 21 +++++++++++++++++ > >> > util/qemu-thread-posix.c | 33 ++++++++++++++++++++++++++- > >> > util/qemu-thread-win32.c | 49 ++++++++++++++++++++++++++++++++++++---- > >> > 4 files changed, 99 insertions(+), 5 deletions(-) > >> > >> Tempted to store the thread name in TLS and call it a day. > > > > Using the official APIs in this way ensures that the thread name is > > visible outside QEMU. For example when debugging in GDB, which IMHO > > is an important benefit. > > I didn't mean to suggest not to set the "official" thread name. > > This patch retrieves the "official" thread name back. Takes a bit of > system-specific code, including Meson magic. We could instead hold on > to our own copy, and just use that. That would mean we don't get any names for threads which are spawned indirectly. There are quite a lot of libraries that QEMU can use, which can spawn threads behind QEMU's back, and these threads can still be running QEMU code through callbacks. spice, gstreamer, jack and librbd are some I know that spawn threads, but there are likely quite a few more. In the the jack case we hook into its thread creation to set a name ourselves, but we can't rely on that in general, and these libraries may well have set thread names we should use. I want to maximise the cases where we can retrieve a thread name. While the code is more verbose than I'd like, it exists now so I don't think its good to throw it away to put into a worse solution. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On Tue, Jan 13, 2026 at 2:00 PM Markus Armbruster <armbru@redhat.com> wrote: > > > Tempted to store the thread name in TLS and call it a day. > > > > Using the official APIs in this way ensures that the thread name is > > visible outside QEMU. For example when debugging in GDB, which IMHO > > is an important benefit. > > I didn't mean to suggest not to set the "official" thread name. > > This patch retrieves the "official" thread name back. Takes a bit of > system-specific code, including Meson magic. We could instead hold on > to our own copy, and just use that. Yes, I think that's what we're going to do anyway due to my remark on patch 7/24. Paolo
On Tue, Jan 13, 2026 at 04:49:53PM +0100, Paolo Bonzini wrote: > On Tue, Jan 13, 2026 at 2:00 PM Markus Armbruster <armbru@redhat.com> wrote: > > > > Tempted to store the thread name in TLS and call it a day. > > > > > > Using the official APIs in this way ensures that the thread name is > > > visible outside QEMU. For example when debugging in GDB, which IMHO > > > is an important benefit. > > > > I didn't mean to suggest not to set the "official" thread name. > > > > This patch retrieves the "official" thread name back. Takes a bit of > > system-specific code, including Meson magic. We could instead hold on > > to our own copy, and just use that. > > Yes, I think that's what we're going to do anyway due to my remark on > patch 7/24. That doesn't alter things. The constructor merely initialzies the name for the main thread. We'll still use pthread APIs for all other threads. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On 1/8/26 18:03, Daniel P. Berrangé wrote: > +static __thread char namebuf[PTHREAD_MAX_NAMELEN_NP]; ... you can instead of the previous patch, add a constructor here that just sets namebuf to "main" with strcpy. For Windows on the other hand it should be okay to call SetThreadDescription if available. Paolo
On Fri, Jan 09, 2026 at 12:49:20PM +0100, Paolo Bonzini wrote:
> On 1/8/26 18:03, Daniel P. Berrangé wrote:
> > +static __thread char namebuf[PTHREAD_MAX_NAMELEN_NP];
>
> ... you can instead of the previous patch, add a constructor here that just
> sets namebuf to "main" with strcpy.
How about just a static initializer
static __thread char namebuf[PTHREAD_MAX_NAMELEN_NP] = { 'm', 'a', 'i', 'n', '\0' };
or is there some interaction with __thread that makes that undesirable ?
The downside is that I wanted the nice thread names to appear in GDB
too, but I guess we can live with the main thread being unnamed in
GDB.
>
> For Windows on the other hand it should be okay to call SetThreadDescription
> if available.
>
> Paolo
>
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On 1/9/26 12:56, Daniel P. Berrangé wrote:
> On Fri, Jan 09, 2026 at 12:49:20PM +0100, Paolo Bonzini wrote:
>> On 1/8/26 18:03, Daniel P. Berrangé wrote:
>>> +static __thread char namebuf[PTHREAD_MAX_NAMELEN_NP];
>>
>> ... you can instead of the previous patch, add a constructor here that just
>> sets namebuf to "main" with strcpy.
>
> How about just a static initializer
>
> static __thread char namebuf[PTHREAD_MAX_NAMELEN_NP] = { 'm', 'a', 'i', 'n', '\0' };
>
> or is there some interaction with __thread that makes that undesirable ?
This would break here:
if (namebuf[0] != '\0') {
return namebuf;
}
and every thread would have "main" as the name, because static
initializers for __thread apply to all threads.
Thanks,
Paolo
© 2016 - 2026 Red Hat, Inc.