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
;
95 if (tc
->init_cpu_bitmap
) {
96 error_setg(errp
, "Mixing CPU and node affinity not supported");
100 visit_type_uint16List(v
, name
, &host_cpus
, &err
);
102 error_propagate(errp
, err
);
107 error_setg(errp
, "CPU list is empty");
111 for (l
= host_cpus
; l
; l
= l
->next
) {
112 nbits
= MAX(nbits
, l
->value
+ 1);
114 bitmap
= bitmap_new(nbits
);
115 for (l
= host_cpus
; l
; l
= l
->next
) {
116 set_bit(l
->value
, bitmap
);
119 if (tc
->thread_id
!= -1) {
121 * Note: we won't be adjusting the affinity of any thread that is still
122 * around, but only the affinity of the context thread.
124 ret
= qemu_thread_set_affinity(&tc
->thread
, bitmap
, nbits
);
126 error_setg(errp
, "Setting CPU affinity failed: %s", strerror(ret
));
129 tc
->init_cpu_bitmap
= bitmap
;
131 tc
->init_cpu_nbits
= nbits
;
135 qapi_free_uint16List(host_cpus
);
138 static void thread_context_get_cpu_affinity(Object
*obj
, Visitor
*v
,
139 const char *name
, void *opaque
,
142 unsigned long *bitmap
, nbits
, value
;
143 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
144 uint16List
*host_cpus
= NULL
;
145 uint16List
**tail
= &host_cpus
;
148 if (tc
->thread_id
== -1) {
149 error_setg(errp
, "Object not initialized yet");
153 ret
= qemu_thread_get_affinity(&tc
->thread
, &bitmap
, &nbits
);
155 error_setg(errp
, "Getting CPU affinity failed: %s", strerror(ret
));
159 value
= find_first_bit(bitmap
, nbits
);
160 while (value
< nbits
) {
161 QAPI_LIST_APPEND(tail
, value
);
163 value
= find_next_bit(bitmap
, nbits
, value
+ 1);
167 visit_type_uint16List(v
, name
, &host_cpus
, errp
);
168 qapi_free_uint16List(host_cpus
);
171 static void thread_context_set_node_affinity(Object
*obj
, Visitor
*v
,
172 const char *name
, void *opaque
,
176 const int nbits
= numa_num_possible_cpus();
177 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
178 uint16List
*l
, *host_nodes
= NULL
;
179 unsigned long *bitmap
= NULL
;
180 struct bitmask
*tmp_cpus
;
184 if (tc
->init_cpu_bitmap
) {
185 error_setg(errp
, "Mixing CPU and node affinity not supported");
189 visit_type_uint16List(v
, name
, &host_nodes
, &err
);
191 error_propagate(errp
, err
);
196 error_setg(errp
, "Node list is empty");
200 bitmap
= bitmap_new(nbits
);
201 tmp_cpus
= numa_allocate_cpumask();
202 for (l
= host_nodes
; l
; l
= l
->next
) {
203 numa_bitmask_clearall(tmp_cpus
);
204 ret
= numa_node_to_cpus(l
->value
, tmp_cpus
);
206 /* We ignore any errors, such as impossible nodes. */
209 for (i
= 0; i
< nbits
; i
++) {
210 if (numa_bitmask_isbitset(tmp_cpus
, i
)) {
215 numa_free_cpumask(tmp_cpus
);
217 if (bitmap_empty(bitmap
, nbits
)) {
218 error_setg(errp
, "The nodes select no CPUs");
222 if (tc
->thread_id
!= -1) {
224 * Note: we won't be adjusting the affinity of any thread that is still
225 * around for now, but only the affinity of the context thread.
227 ret
= qemu_thread_set_affinity(&tc
->thread
, bitmap
, nbits
);
229 error_setg(errp
, "Setting CPU affinity failed: %s", strerror(ret
));
232 tc
->init_cpu_bitmap
= bitmap
;
234 tc
->init_cpu_nbits
= nbits
;
238 qapi_free_uint16List(host_nodes
);
240 error_setg(errp
, "NUMA node affinity is not supported by this QEMU");
244 static void thread_context_get_thread_id(Object
*obj
, Visitor
*v
,
245 const char *name
, void *opaque
,
248 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
249 uint64_t value
= tc
->thread_id
;
251 visit_type_uint64(v
, name
, &value
, errp
);
254 static void thread_context_instance_complete(UserCreatable
*uc
, Error
**errp
)
256 ThreadContext
*tc
= THREAD_CONTEXT(uc
);
260 thread_name
= g_strdup_printf("TC %s",
261 object_get_canonical_path_component(OBJECT(uc
)));
262 qemu_thread_create(&tc
->thread
, thread_name
, thread_context_run
, tc
,
263 QEMU_THREAD_JOINABLE
);
266 /* Wait until initialization of the thread is done. */
267 while (tc
->thread_id
== -1) {
268 qemu_sem_wait(&tc
->sem
);
271 if (tc
->init_cpu_bitmap
) {
272 ret
= qemu_thread_set_affinity(&tc
->thread
, tc
->init_cpu_bitmap
,
275 error_setg(errp
, "Setting CPU affinity failed: %s", strerror(ret
));
277 g_free(tc
->init_cpu_bitmap
);
278 tc
->init_cpu_bitmap
= NULL
;
282 static void thread_context_class_init(ObjectClass
*oc
, void *data
)
284 UserCreatableClass
*ucc
= USER_CREATABLE_CLASS(oc
);
286 ucc
->complete
= thread_context_instance_complete
;
287 object_class_property_add(oc
, "thread-id", "int",
288 thread_context_get_thread_id
, NULL
, NULL
,
290 object_class_property_add(oc
, "cpu-affinity", "int",
291 thread_context_get_cpu_affinity
,
292 thread_context_set_cpu_affinity
, NULL
, NULL
);
293 object_class_property_add(oc
, "node-affinity", "int", NULL
,
294 thread_context_set_node_affinity
, NULL
, NULL
);
297 static void thread_context_instance_init(Object
*obj
)
299 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
302 qemu_sem_init(&tc
->sem
, 0);
303 qemu_sem_init(&tc
->sem_thread
, 0);
304 qemu_mutex_init(&tc
->mutex
);
307 static void thread_context_instance_finalize(Object
*obj
)
309 ThreadContext
*tc
= THREAD_CONTEXT(obj
);
311 if (tc
->thread_id
!= -1) {
312 tc
->thread_cmd
= TC_CMD_STOP
;
313 qemu_sem_post(&tc
->sem_thread
);
314 qemu_thread_join(&tc
->thread
);
316 qemu_sem_destroy(&tc
->sem
);
317 qemu_sem_destroy(&tc
->sem_thread
);
318 qemu_mutex_destroy(&tc
->mutex
);
321 static const TypeInfo thread_context_info
= {
322 .name
= TYPE_THREAD_CONTEXT
,
323 .parent
= TYPE_OBJECT
,
324 .class_init
= thread_context_class_init
,
325 .instance_size
= sizeof(ThreadContext
),
326 .instance_init
= thread_context_instance_init
,
327 .instance_finalize
= thread_context_instance_finalize
,
328 .interfaces
= (InterfaceInfo
[]) {
329 { TYPE_USER_CREATABLE
},
334 static void thread_context_register_types(void)
336 type_register_static(&thread_context_info
);
338 type_init(thread_context_register_types
)
340 void thread_context_create_thread(ThreadContext
*tc
, QemuThread
*thread
,
342 void *(*start_routine
)(void *), void *arg
,
345 ThreadContextCmdNew data
= {
348 .start_routine
= start_routine
,
353 qemu_mutex_lock(&tc
->mutex
);
354 tc
->thread_cmd
= TC_CMD_NEW
;
355 tc
->thread_cmd_data
= &data
;
356 qemu_sem_post(&tc
->sem_thread
);
358 while (tc
->thread_cmd
!= TC_CMD_NONE
) {
359 qemu_sem_wait(&tc
->sem
);
361 qemu_mutex_unlock(&tc
->mutex
);