4 * Copyright Red Hat Inc., 2022
7 * David Hildenbrand <david@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "qemu/thread-context.h"
15 #include "qapi/error.h"
16 #include "qapi/qapi-builtin-visit.h"
17 #include "qapi/visitor.h"
18 #include "qemu/config-file.h"
19 #include "qapi/qapi-builtin-visit.h"
20 #include "qom/object_interfaces.h"
21 #include "qemu/module.h"
22 #include "qemu/bitmap.h"
34 typedef struct ThreadContextCmdNew
{
37 void *(*start_routine
)(void *);
40 } ThreadContextCmdNew
;
42 static void *thread_context_run(void *opaque
)
44 ThreadContext
*tc
= opaque
;
46 tc
->thread_id
= qemu_get_thread_id();
47 qemu_sem_post(&tc
->sem
);
51 * Threads inherit the CPU affinity of the creating thread. For this
52 * reason, we create new (especially short-lived) threads from our
53 * persistent context thread.
55 * Especially when QEMU is not allowed to set the affinity itself,
56 * management tools can simply set the affinity of the context thread
57 * after creating the context, to have new threads created via
58 * the context inherit the CPU affinity automatically.
60 switch (tc
->thread_cmd
) {
64 tc
->thread_cmd
= TC_CMD_NONE
;
65 qemu_sem_post(&tc
->sem
);
68 ThreadContextCmdNew
*cmd_new
= tc
->thread_cmd_data
;
70 qemu_thread_create(cmd_new
->thread
, cmd_new
->name
,
71 cmd_new
->start_routine
, cmd_new
->arg
,
73 tc
->thread_cmd
= TC_CMD_NONE
;
74 tc
->thread_cmd_data
= NULL
;
75 qemu_sem_post(&tc
->sem
);
79 g_assert_not_reached();
81 qemu_sem_wait(&tc
->sem_thread
);
85 static void thread_context_set_cpu_affinity(Object
*obj
, Visitor
*v
,
86 const char *name
, void *opaque
,
89 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
90 uint16List
*l
, *host_cpus
= NULL
;
91 unsigned long *bitmap
= NULL
;
94 if (tc
->init_cpu_bitmap
) {
95 error_setg(errp
, "Mixing CPU and node affinity not supported");
99 if (!visit_type_uint16List(v
, name
, &host_cpus
, errp
)) {
104 error_setg(errp
, "CPU list is empty");
108 for (l
= host_cpus
; l
; l
= l
->next
) {
109 nbits
= MAX(nbits
, l
->value
+ 1);
111 bitmap
= bitmap_new(nbits
);
112 for (l
= host_cpus
; l
; l
= l
->next
) {
113 set_bit(l
->value
, bitmap
);
116 if (tc
->thread_id
!= -1) {
118 * Note: we won't be adjusting the affinity of any thread that is still
119 * around, but only the affinity of the context thread.
121 ret
= qemu_thread_set_affinity(&tc
->thread
, bitmap
, nbits
);
123 error_setg(errp
, "Setting CPU affinity failed: %s", strerror(ret
));
126 tc
->init_cpu_bitmap
= bitmap
;
128 tc
->init_cpu_nbits
= nbits
;
132 qapi_free_uint16List(host_cpus
);
135 static void thread_context_get_cpu_affinity(Object
*obj
, Visitor
*v
,
136 const char *name
, void *opaque
,
139 unsigned long *bitmap
, nbits
, value
;
140 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
141 uint16List
*host_cpus
= NULL
;
142 uint16List
**tail
= &host_cpus
;
145 if (tc
->thread_id
== -1) {
146 error_setg(errp
, "Object not initialized yet");
150 ret
= qemu_thread_get_affinity(&tc
->thread
, &bitmap
, &nbits
);
152 error_setg(errp
, "Getting CPU affinity failed: %s", strerror(ret
));
156 value
= find_first_bit(bitmap
, nbits
);
157 while (value
< nbits
) {
158 QAPI_LIST_APPEND(tail
, value
);
160 value
= find_next_bit(bitmap
, nbits
, value
+ 1);
164 visit_type_uint16List(v
, name
, &host_cpus
, errp
);
165 qapi_free_uint16List(host_cpus
);
168 static void thread_context_set_node_affinity(Object
*obj
, Visitor
*v
,
169 const char *name
, void *opaque
,
173 const int nbits
= numa_num_possible_cpus();
174 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
175 uint16List
*l
, *host_nodes
= NULL
;
176 unsigned long *bitmap
= NULL
;
177 struct bitmask
*tmp_cpus
;
180 if (tc
->init_cpu_bitmap
) {
181 error_setg(errp
, "Mixing CPU and node affinity not supported");
185 if (!visit_type_uint16List(v
, name
, &host_nodes
, errp
)) {
190 error_setg(errp
, "Node list is empty");
194 bitmap
= bitmap_new(nbits
);
195 tmp_cpus
= numa_allocate_cpumask();
196 for (l
= host_nodes
; l
; l
= l
->next
) {
197 numa_bitmask_clearall(tmp_cpus
);
198 ret
= numa_node_to_cpus(l
->value
, tmp_cpus
);
200 /* We ignore any errors, such as impossible nodes. */
203 for (i
= 0; i
< nbits
; i
++) {
204 if (numa_bitmask_isbitset(tmp_cpus
, i
)) {
209 numa_free_cpumask(tmp_cpus
);
211 if (bitmap_empty(bitmap
, nbits
)) {
212 error_setg(errp
, "The nodes select no CPUs");
216 if (tc
->thread_id
!= -1) {
218 * Note: we won't be adjusting the affinity of any thread that is still
219 * around for now, but only the affinity of the context thread.
221 ret
= qemu_thread_set_affinity(&tc
->thread
, bitmap
, nbits
);
223 error_setg(errp
, "Setting CPU affinity failed: %s", strerror(ret
));
226 tc
->init_cpu_bitmap
= bitmap
;
228 tc
->init_cpu_nbits
= nbits
;
232 qapi_free_uint16List(host_nodes
);
234 error_setg(errp
, "NUMA node affinity is not supported by this QEMU");
238 static void thread_context_get_thread_id(Object
*obj
, Visitor
*v
,
239 const char *name
, void *opaque
,
242 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
243 uint64_t value
= tc
->thread_id
;
245 visit_type_uint64(v
, name
, &value
, errp
);
248 static void thread_context_instance_complete(UserCreatable
*uc
, Error
**errp
)
250 ThreadContext
*tc
= THREAD_CONTEXT(uc
);
254 thread_name
= g_strdup_printf("TC %s",
255 object_get_canonical_path_component(OBJECT(uc
)));
256 qemu_thread_create(&tc
->thread
, thread_name
, thread_context_run
, tc
,
257 QEMU_THREAD_JOINABLE
);
260 /* Wait until initialization of the thread is done. */
261 while (tc
->thread_id
== -1) {
262 qemu_sem_wait(&tc
->sem
);
265 if (tc
->init_cpu_bitmap
) {
266 ret
= qemu_thread_set_affinity(&tc
->thread
, tc
->init_cpu_bitmap
,
269 error_setg(errp
, "Setting CPU affinity failed: %s", strerror(ret
));
271 g_free(tc
->init_cpu_bitmap
);
272 tc
->init_cpu_bitmap
= NULL
;
276 static void thread_context_class_init(ObjectClass
*oc
, void *data
)
278 UserCreatableClass
*ucc
= USER_CREATABLE_CLASS(oc
);
280 ucc
->complete
= thread_context_instance_complete
;
281 object_class_property_add(oc
, "thread-id", "int",
282 thread_context_get_thread_id
, NULL
, NULL
,
284 object_class_property_add(oc
, "cpu-affinity", "int",
285 thread_context_get_cpu_affinity
,
286 thread_context_set_cpu_affinity
, NULL
, NULL
);
287 object_class_property_add(oc
, "node-affinity", "int", NULL
,
288 thread_context_set_node_affinity
, NULL
, NULL
);
291 static void thread_context_instance_init(Object
*obj
)
293 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
296 qemu_sem_init(&tc
->sem
, 0);
297 qemu_sem_init(&tc
->sem_thread
, 0);
298 qemu_mutex_init(&tc
->mutex
);
301 static void thread_context_instance_finalize(Object
*obj
)
303 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
305 if (tc
->thread_id
!= -1) {
306 tc
->thread_cmd
= TC_CMD_STOP
;
307 qemu_sem_post(&tc
->sem_thread
);
308 qemu_thread_join(&tc
->thread
);
310 qemu_sem_destroy(&tc
->sem
);
311 qemu_sem_destroy(&tc
->sem_thread
);
312 qemu_mutex_destroy(&tc
->mutex
);
315 static const TypeInfo thread_context_info
= {
316 .name
= TYPE_THREAD_CONTEXT
,
317 .parent
= TYPE_OBJECT
,
318 .class_init
= thread_context_class_init
,
319 .instance_size
= sizeof(ThreadContext
),
320 .instance_init
= thread_context_instance_init
,
321 .instance_finalize
= thread_context_instance_finalize
,
322 .interfaces
= (InterfaceInfo
[]) {
323 { TYPE_USER_CREATABLE
},
328 static void thread_context_register_types(void)
330 type_register_static(&thread_context_info
);
332 type_init(thread_context_register_types
)
334 void thread_context_create_thread(ThreadContext
*tc
, QemuThread
*thread
,
336 void *(*start_routine
)(void *), void *arg
,
339 ThreadContextCmdNew data
= {
342 .start_routine
= start_routine
,
347 qemu_mutex_lock(&tc
->mutex
);
348 tc
->thread_cmd
= TC_CMD_NEW
;
349 tc
->thread_cmd_data
= &data
;
350 qemu_sem_post(&tc
->sem_thread
);
352 while (tc
->thread_cmd
!= TC_CMD_NONE
) {
353 qemu_sem_wait(&tc
->sem
);
355 qemu_mutex_unlock(&tc
->mutex
);