xref: /openbmc/qemu/util/thread-context.c (revision d1c81c34)
1e2de2c49SDavid Hildenbrand /*
2e2de2c49SDavid Hildenbrand  * QEMU Thread Context
3e2de2c49SDavid Hildenbrand  *
4e2de2c49SDavid Hildenbrand  * Copyright Red Hat Inc., 2022
5e2de2c49SDavid Hildenbrand  *
6e2de2c49SDavid Hildenbrand  * Authors:
7e2de2c49SDavid Hildenbrand  *  David Hildenbrand <david@redhat.com>
8e2de2c49SDavid Hildenbrand  *
9e2de2c49SDavid Hildenbrand  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10e2de2c49SDavid Hildenbrand  * See the COPYING file in the top-level directory.
11e2de2c49SDavid Hildenbrand  */
12e2de2c49SDavid Hildenbrand 
13e2de2c49SDavid Hildenbrand #include "qemu/osdep.h"
14e2de2c49SDavid Hildenbrand #include "qemu/thread-context.h"
15e2de2c49SDavid Hildenbrand #include "qapi/error.h"
16e2de2c49SDavid Hildenbrand #include "qapi/qapi-builtin-visit.h"
17e2de2c49SDavid Hildenbrand #include "qapi/visitor.h"
18e2de2c49SDavid Hildenbrand #include "qemu/config-file.h"
19e2de2c49SDavid Hildenbrand #include "qapi/qapi-builtin-visit.h"
20e2de2c49SDavid Hildenbrand #include "qom/object_interfaces.h"
21e2de2c49SDavid Hildenbrand #include "qemu/module.h"
22e2de2c49SDavid Hildenbrand #include "qemu/bitmap.h"
23e2de2c49SDavid Hildenbrand 
2410218ae6SDavid Hildenbrand #ifdef CONFIG_NUMA
2510218ae6SDavid Hildenbrand #include <numa.h>
2610218ae6SDavid Hildenbrand #endif
2710218ae6SDavid Hildenbrand 
28e2de2c49SDavid Hildenbrand enum {
29e2de2c49SDavid Hildenbrand     TC_CMD_NONE = 0,
30e2de2c49SDavid Hildenbrand     TC_CMD_STOP,
31e2de2c49SDavid Hildenbrand     TC_CMD_NEW,
32e2de2c49SDavid Hildenbrand };
33e2de2c49SDavid Hildenbrand 
34e2de2c49SDavid Hildenbrand typedef struct ThreadContextCmdNew {
35e2de2c49SDavid Hildenbrand     QemuThread *thread;
36e2de2c49SDavid Hildenbrand     const char *name;
37e2de2c49SDavid Hildenbrand     void *(*start_routine)(void *);
38e2de2c49SDavid Hildenbrand     void *arg;
39e2de2c49SDavid Hildenbrand     int mode;
40e2de2c49SDavid Hildenbrand } ThreadContextCmdNew;
41e2de2c49SDavid Hildenbrand 
thread_context_run(void * opaque)42e2de2c49SDavid Hildenbrand static void *thread_context_run(void *opaque)
43e2de2c49SDavid Hildenbrand {
44e2de2c49SDavid Hildenbrand     ThreadContext *tc = opaque;
45e2de2c49SDavid Hildenbrand 
46e2de2c49SDavid Hildenbrand     tc->thread_id = qemu_get_thread_id();
47e2de2c49SDavid Hildenbrand     qemu_sem_post(&tc->sem);
48e2de2c49SDavid Hildenbrand 
49e2de2c49SDavid Hildenbrand     while (true) {
50e2de2c49SDavid Hildenbrand         /*
51e2de2c49SDavid Hildenbrand          * Threads inherit the CPU affinity of the creating thread. For this
52e2de2c49SDavid Hildenbrand          * reason, we create new (especially short-lived) threads from our
53e2de2c49SDavid Hildenbrand          * persistent context thread.
54e2de2c49SDavid Hildenbrand          *
55e2de2c49SDavid Hildenbrand          * Especially when QEMU is not allowed to set the affinity itself,
56e2de2c49SDavid Hildenbrand          * management tools can simply set the affinity of the context thread
57e2de2c49SDavid Hildenbrand          * after creating the context, to have new threads created via
58e2de2c49SDavid Hildenbrand          * the context inherit the CPU affinity automatically.
59e2de2c49SDavid Hildenbrand          */
60e2de2c49SDavid Hildenbrand         switch (tc->thread_cmd) {
61e2de2c49SDavid Hildenbrand         case TC_CMD_NONE:
62e2de2c49SDavid Hildenbrand             break;
63e2de2c49SDavid Hildenbrand         case TC_CMD_STOP:
64e2de2c49SDavid Hildenbrand             tc->thread_cmd = TC_CMD_NONE;
65e2de2c49SDavid Hildenbrand             qemu_sem_post(&tc->sem);
66e2de2c49SDavid Hildenbrand             return NULL;
67e2de2c49SDavid Hildenbrand         case TC_CMD_NEW: {
68e2de2c49SDavid Hildenbrand             ThreadContextCmdNew *cmd_new = tc->thread_cmd_data;
69e2de2c49SDavid Hildenbrand 
70e2de2c49SDavid Hildenbrand             qemu_thread_create(cmd_new->thread, cmd_new->name,
71e2de2c49SDavid Hildenbrand                                cmd_new->start_routine, cmd_new->arg,
72e2de2c49SDavid Hildenbrand                                cmd_new->mode);
73e2de2c49SDavid Hildenbrand             tc->thread_cmd = TC_CMD_NONE;
74e2de2c49SDavid Hildenbrand             tc->thread_cmd_data = NULL;
75e2de2c49SDavid Hildenbrand             qemu_sem_post(&tc->sem);
76e2de2c49SDavid Hildenbrand             break;
77e2de2c49SDavid Hildenbrand         }
78e2de2c49SDavid Hildenbrand         default:
79e2de2c49SDavid Hildenbrand             g_assert_not_reached();
80e2de2c49SDavid Hildenbrand         }
81e2de2c49SDavid Hildenbrand         qemu_sem_wait(&tc->sem_thread);
82e2de2c49SDavid Hildenbrand     }
83e2de2c49SDavid Hildenbrand }
84e2de2c49SDavid Hildenbrand 
thread_context_set_cpu_affinity(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)85e2de2c49SDavid Hildenbrand static void thread_context_set_cpu_affinity(Object *obj, Visitor *v,
86e2de2c49SDavid Hildenbrand                                             const char *name, void *opaque,
87e2de2c49SDavid Hildenbrand                                             Error **errp)
88e2de2c49SDavid Hildenbrand {
89e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
90e2de2c49SDavid Hildenbrand     uint16List *l, *host_cpus = NULL;
91e2de2c49SDavid Hildenbrand     unsigned long *bitmap = NULL;
92e2de2c49SDavid Hildenbrand     int nbits = 0, ret;
93e2de2c49SDavid Hildenbrand 
9410218ae6SDavid Hildenbrand     if (tc->init_cpu_bitmap) {
9510218ae6SDavid Hildenbrand         error_setg(errp, "Mixing CPU and node affinity not supported");
9610218ae6SDavid Hildenbrand         return;
9710218ae6SDavid Hildenbrand     }
9810218ae6SDavid Hildenbrand 
99*d1c81c34SMarkus Armbruster     if (!visit_type_uint16List(v, name, &host_cpus, errp)) {
100e2de2c49SDavid Hildenbrand         return;
101e2de2c49SDavid Hildenbrand     }
102e2de2c49SDavid Hildenbrand 
103e2de2c49SDavid Hildenbrand     if (!host_cpus) {
104e2de2c49SDavid Hildenbrand         error_setg(errp, "CPU list is empty");
105e2de2c49SDavid Hildenbrand         goto out;
106e2de2c49SDavid Hildenbrand     }
107e2de2c49SDavid Hildenbrand 
108e2de2c49SDavid Hildenbrand     for (l = host_cpus; l; l = l->next) {
109e2de2c49SDavid Hildenbrand         nbits = MAX(nbits, l->value + 1);
110e2de2c49SDavid Hildenbrand     }
111e2de2c49SDavid Hildenbrand     bitmap = bitmap_new(nbits);
112e2de2c49SDavid Hildenbrand     for (l = host_cpus; l; l = l->next) {
113e2de2c49SDavid Hildenbrand         set_bit(l->value, bitmap);
114e2de2c49SDavid Hildenbrand     }
115e2de2c49SDavid Hildenbrand 
116e2de2c49SDavid Hildenbrand     if (tc->thread_id != -1) {
117e2de2c49SDavid Hildenbrand         /*
118e2de2c49SDavid Hildenbrand          * Note: we won't be adjusting the affinity of any thread that is still
119e2de2c49SDavid Hildenbrand          * around, but only the affinity of the context thread.
120e2de2c49SDavid Hildenbrand          */
121e2de2c49SDavid Hildenbrand         ret = qemu_thread_set_affinity(&tc->thread, bitmap, nbits);
122e2de2c49SDavid Hildenbrand         if (ret) {
123e2de2c49SDavid Hildenbrand             error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret));
124e2de2c49SDavid Hildenbrand         }
125e2de2c49SDavid Hildenbrand     } else {
126e2de2c49SDavid Hildenbrand         tc->init_cpu_bitmap = bitmap;
127e2de2c49SDavid Hildenbrand         bitmap = NULL;
128e2de2c49SDavid Hildenbrand         tc->init_cpu_nbits = nbits;
129e2de2c49SDavid Hildenbrand     }
130e2de2c49SDavid Hildenbrand out:
131e2de2c49SDavid Hildenbrand     g_free(bitmap);
132e2de2c49SDavid Hildenbrand     qapi_free_uint16List(host_cpus);
133e2de2c49SDavid Hildenbrand }
134e2de2c49SDavid Hildenbrand 
thread_context_get_cpu_affinity(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)135e2de2c49SDavid Hildenbrand static void thread_context_get_cpu_affinity(Object *obj, Visitor *v,
136e2de2c49SDavid Hildenbrand                                             const char *name, void *opaque,
137e2de2c49SDavid Hildenbrand                                             Error **errp)
138e2de2c49SDavid Hildenbrand {
139e2de2c49SDavid Hildenbrand     unsigned long *bitmap, nbits, value;
140e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
141e2de2c49SDavid Hildenbrand     uint16List *host_cpus = NULL;
142e2de2c49SDavid Hildenbrand     uint16List **tail = &host_cpus;
143e2de2c49SDavid Hildenbrand     int ret;
144e2de2c49SDavid Hildenbrand 
145e2de2c49SDavid Hildenbrand     if (tc->thread_id == -1) {
146e2de2c49SDavid Hildenbrand         error_setg(errp, "Object not initialized yet");
147e2de2c49SDavid Hildenbrand         return;
148e2de2c49SDavid Hildenbrand     }
149e2de2c49SDavid Hildenbrand 
150e2de2c49SDavid Hildenbrand     ret = qemu_thread_get_affinity(&tc->thread, &bitmap, &nbits);
151e2de2c49SDavid Hildenbrand     if (ret) {
152e2de2c49SDavid Hildenbrand         error_setg(errp, "Getting CPU affinity failed: %s", strerror(ret));
153e2de2c49SDavid Hildenbrand         return;
154e2de2c49SDavid Hildenbrand     }
155e2de2c49SDavid Hildenbrand 
156e2de2c49SDavid Hildenbrand     value = find_first_bit(bitmap, nbits);
157e2de2c49SDavid Hildenbrand     while (value < nbits) {
158e2de2c49SDavid Hildenbrand         QAPI_LIST_APPEND(tail, value);
159e2de2c49SDavid Hildenbrand 
160e2de2c49SDavid Hildenbrand         value = find_next_bit(bitmap, nbits, value + 1);
161e2de2c49SDavid Hildenbrand     }
162e2de2c49SDavid Hildenbrand     g_free(bitmap);
163e2de2c49SDavid Hildenbrand 
164e2de2c49SDavid Hildenbrand     visit_type_uint16List(v, name, &host_cpus, errp);
165e2de2c49SDavid Hildenbrand     qapi_free_uint16List(host_cpus);
166e2de2c49SDavid Hildenbrand }
167e2de2c49SDavid Hildenbrand 
thread_context_set_node_affinity(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)16810218ae6SDavid Hildenbrand static void thread_context_set_node_affinity(Object *obj, Visitor *v,
16910218ae6SDavid Hildenbrand                                              const char *name, void *opaque,
17010218ae6SDavid Hildenbrand                                              Error **errp)
17110218ae6SDavid Hildenbrand {
17210218ae6SDavid Hildenbrand #ifdef CONFIG_NUMA
17310218ae6SDavid Hildenbrand     const int nbits = numa_num_possible_cpus();
17410218ae6SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
17510218ae6SDavid Hildenbrand     uint16List *l, *host_nodes = NULL;
17610218ae6SDavid Hildenbrand     unsigned long *bitmap = NULL;
17710218ae6SDavid Hildenbrand     struct bitmask *tmp_cpus;
17810218ae6SDavid Hildenbrand     int ret, i;
17910218ae6SDavid Hildenbrand 
18010218ae6SDavid Hildenbrand     if (tc->init_cpu_bitmap) {
18110218ae6SDavid Hildenbrand         error_setg(errp, "Mixing CPU and node affinity not supported");
18210218ae6SDavid Hildenbrand         return;
18310218ae6SDavid Hildenbrand     }
18410218ae6SDavid Hildenbrand 
185*d1c81c34SMarkus Armbruster     if (!visit_type_uint16List(v, name, &host_nodes, errp)) {
18610218ae6SDavid Hildenbrand         return;
18710218ae6SDavid Hildenbrand     }
18810218ae6SDavid Hildenbrand 
18910218ae6SDavid Hildenbrand     if (!host_nodes) {
19010218ae6SDavid Hildenbrand         error_setg(errp, "Node list is empty");
19110218ae6SDavid Hildenbrand         goto out;
19210218ae6SDavid Hildenbrand     }
19310218ae6SDavid Hildenbrand 
19410218ae6SDavid Hildenbrand     bitmap = bitmap_new(nbits);
19510218ae6SDavid Hildenbrand     tmp_cpus = numa_allocate_cpumask();
19610218ae6SDavid Hildenbrand     for (l = host_nodes; l; l = l->next) {
19710218ae6SDavid Hildenbrand         numa_bitmask_clearall(tmp_cpus);
19810218ae6SDavid Hildenbrand         ret = numa_node_to_cpus(l->value, tmp_cpus);
19910218ae6SDavid Hildenbrand         if (ret) {
20010218ae6SDavid Hildenbrand             /* We ignore any errors, such as impossible nodes. */
20110218ae6SDavid Hildenbrand             continue;
20210218ae6SDavid Hildenbrand         }
20310218ae6SDavid Hildenbrand         for (i = 0; i < nbits; i++) {
20410218ae6SDavid Hildenbrand             if (numa_bitmask_isbitset(tmp_cpus, i)) {
20510218ae6SDavid Hildenbrand                 set_bit(i, bitmap);
20610218ae6SDavid Hildenbrand             }
20710218ae6SDavid Hildenbrand         }
20810218ae6SDavid Hildenbrand     }
20910218ae6SDavid Hildenbrand     numa_free_cpumask(tmp_cpus);
21010218ae6SDavid Hildenbrand 
21110218ae6SDavid Hildenbrand     if (bitmap_empty(bitmap, nbits)) {
21210218ae6SDavid Hildenbrand         error_setg(errp, "The nodes select no CPUs");
21310218ae6SDavid Hildenbrand         goto out;
21410218ae6SDavid Hildenbrand     }
21510218ae6SDavid Hildenbrand 
21610218ae6SDavid Hildenbrand     if (tc->thread_id != -1) {
21710218ae6SDavid Hildenbrand         /*
21810218ae6SDavid Hildenbrand          * Note: we won't be adjusting the affinity of any thread that is still
21910218ae6SDavid Hildenbrand          * around for now, but only the affinity of the context thread.
22010218ae6SDavid Hildenbrand          */
22110218ae6SDavid Hildenbrand         ret = qemu_thread_set_affinity(&tc->thread, bitmap, nbits);
22210218ae6SDavid Hildenbrand         if (ret) {
22310218ae6SDavid Hildenbrand             error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret));
22410218ae6SDavid Hildenbrand         }
22510218ae6SDavid Hildenbrand     } else {
22610218ae6SDavid Hildenbrand         tc->init_cpu_bitmap = bitmap;
22710218ae6SDavid Hildenbrand         bitmap = NULL;
22810218ae6SDavid Hildenbrand         tc->init_cpu_nbits = nbits;
22910218ae6SDavid Hildenbrand     }
23010218ae6SDavid Hildenbrand out:
23110218ae6SDavid Hildenbrand     g_free(bitmap);
23210218ae6SDavid Hildenbrand     qapi_free_uint16List(host_nodes);
23310218ae6SDavid Hildenbrand #else
23410218ae6SDavid Hildenbrand     error_setg(errp, "NUMA node affinity is not supported by this QEMU");
23510218ae6SDavid Hildenbrand #endif
23610218ae6SDavid Hildenbrand }
23710218ae6SDavid Hildenbrand 
thread_context_get_thread_id(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)238e2de2c49SDavid Hildenbrand static void thread_context_get_thread_id(Object *obj, Visitor *v,
239e2de2c49SDavid Hildenbrand                                          const char *name, void *opaque,
240e2de2c49SDavid Hildenbrand                                          Error **errp)
241e2de2c49SDavid Hildenbrand {
242e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
243e2de2c49SDavid Hildenbrand     uint64_t value = tc->thread_id;
244e2de2c49SDavid Hildenbrand 
245e2de2c49SDavid Hildenbrand     visit_type_uint64(v, name, &value, errp);
246e2de2c49SDavid Hildenbrand }
247e2de2c49SDavid Hildenbrand 
thread_context_instance_complete(UserCreatable * uc,Error ** errp)248e2de2c49SDavid Hildenbrand static void thread_context_instance_complete(UserCreatable *uc, Error **errp)
249e2de2c49SDavid Hildenbrand {
250e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(uc);
251e2de2c49SDavid Hildenbrand     char *thread_name;
252e2de2c49SDavid Hildenbrand     int ret;
253e2de2c49SDavid Hildenbrand 
254e2de2c49SDavid Hildenbrand     thread_name = g_strdup_printf("TC %s",
255e2de2c49SDavid Hildenbrand                                object_get_canonical_path_component(OBJECT(uc)));
256e2de2c49SDavid Hildenbrand     qemu_thread_create(&tc->thread, thread_name, thread_context_run, tc,
257e2de2c49SDavid Hildenbrand                        QEMU_THREAD_JOINABLE);
258e2de2c49SDavid Hildenbrand     g_free(thread_name);
259e2de2c49SDavid Hildenbrand 
260e2de2c49SDavid Hildenbrand     /* Wait until initialization of the thread is done. */
261e2de2c49SDavid Hildenbrand     while (tc->thread_id == -1) {
262e2de2c49SDavid Hildenbrand         qemu_sem_wait(&tc->sem);
263e2de2c49SDavid Hildenbrand     }
264e2de2c49SDavid Hildenbrand 
265e2de2c49SDavid Hildenbrand     if (tc->init_cpu_bitmap) {
266e2de2c49SDavid Hildenbrand         ret = qemu_thread_set_affinity(&tc->thread, tc->init_cpu_bitmap,
267e2de2c49SDavid Hildenbrand                                        tc->init_cpu_nbits);
268e2de2c49SDavid Hildenbrand         if (ret) {
269e2de2c49SDavid Hildenbrand             error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret));
270e2de2c49SDavid Hildenbrand         }
271e2de2c49SDavid Hildenbrand         g_free(tc->init_cpu_bitmap);
272e2de2c49SDavid Hildenbrand         tc->init_cpu_bitmap = NULL;
273e2de2c49SDavid Hildenbrand     }
274e2de2c49SDavid Hildenbrand }
275e2de2c49SDavid Hildenbrand 
thread_context_class_init(ObjectClass * oc,void * data)276e2de2c49SDavid Hildenbrand static void thread_context_class_init(ObjectClass *oc, void *data)
277e2de2c49SDavid Hildenbrand {
278e2de2c49SDavid Hildenbrand     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
279e2de2c49SDavid Hildenbrand 
280e2de2c49SDavid Hildenbrand     ucc->complete = thread_context_instance_complete;
281e2de2c49SDavid Hildenbrand     object_class_property_add(oc, "thread-id", "int",
282e2de2c49SDavid Hildenbrand                               thread_context_get_thread_id, NULL, NULL,
283e2de2c49SDavid Hildenbrand                               NULL);
284e2de2c49SDavid Hildenbrand     object_class_property_add(oc, "cpu-affinity", "int",
285e2de2c49SDavid Hildenbrand                               thread_context_get_cpu_affinity,
286e2de2c49SDavid Hildenbrand                               thread_context_set_cpu_affinity, NULL, NULL);
28710218ae6SDavid Hildenbrand     object_class_property_add(oc, "node-affinity", "int", NULL,
28810218ae6SDavid Hildenbrand                               thread_context_set_node_affinity, NULL, NULL);
289e2de2c49SDavid Hildenbrand }
290e2de2c49SDavid Hildenbrand 
thread_context_instance_init(Object * obj)291e2de2c49SDavid Hildenbrand static void thread_context_instance_init(Object *obj)
292e2de2c49SDavid Hildenbrand {
293e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
294e2de2c49SDavid Hildenbrand 
295e2de2c49SDavid Hildenbrand     tc->thread_id = -1;
296e2de2c49SDavid Hildenbrand     qemu_sem_init(&tc->sem, 0);
297e2de2c49SDavid Hildenbrand     qemu_sem_init(&tc->sem_thread, 0);
298e2de2c49SDavid Hildenbrand     qemu_mutex_init(&tc->mutex);
299e2de2c49SDavid Hildenbrand }
300e2de2c49SDavid Hildenbrand 
thread_context_instance_finalize(Object * obj)301e2de2c49SDavid Hildenbrand static void thread_context_instance_finalize(Object *obj)
302e2de2c49SDavid Hildenbrand {
303e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
304e2de2c49SDavid Hildenbrand 
305e2de2c49SDavid Hildenbrand     if (tc->thread_id != -1) {
306e2de2c49SDavid Hildenbrand         tc->thread_cmd = TC_CMD_STOP;
307e2de2c49SDavid Hildenbrand         qemu_sem_post(&tc->sem_thread);
308e2de2c49SDavid Hildenbrand         qemu_thread_join(&tc->thread);
309e2de2c49SDavid Hildenbrand     }
310e2de2c49SDavid Hildenbrand     qemu_sem_destroy(&tc->sem);
311e2de2c49SDavid Hildenbrand     qemu_sem_destroy(&tc->sem_thread);
312e2de2c49SDavid Hildenbrand     qemu_mutex_destroy(&tc->mutex);
313e2de2c49SDavid Hildenbrand }
314e2de2c49SDavid Hildenbrand 
315e2de2c49SDavid Hildenbrand static const TypeInfo thread_context_info = {
316e2de2c49SDavid Hildenbrand     .name = TYPE_THREAD_CONTEXT,
317e2de2c49SDavid Hildenbrand     .parent = TYPE_OBJECT,
318e2de2c49SDavid Hildenbrand     .class_init = thread_context_class_init,
319e2de2c49SDavid Hildenbrand     .instance_size = sizeof(ThreadContext),
320e2de2c49SDavid Hildenbrand     .instance_init = thread_context_instance_init,
321e2de2c49SDavid Hildenbrand     .instance_finalize = thread_context_instance_finalize,
322e2de2c49SDavid Hildenbrand     .interfaces = (InterfaceInfo[]) {
323e2de2c49SDavid Hildenbrand         { TYPE_USER_CREATABLE },
324e2de2c49SDavid Hildenbrand         { }
325e2de2c49SDavid Hildenbrand     }
326e2de2c49SDavid Hildenbrand };
327e2de2c49SDavid Hildenbrand 
thread_context_register_types(void)328e2de2c49SDavid Hildenbrand static void thread_context_register_types(void)
329e2de2c49SDavid Hildenbrand {
330e2de2c49SDavid Hildenbrand     type_register_static(&thread_context_info);
331e2de2c49SDavid Hildenbrand }
type_init(thread_context_register_types)332e2de2c49SDavid Hildenbrand type_init(thread_context_register_types)
333e2de2c49SDavid Hildenbrand 
334e2de2c49SDavid Hildenbrand void thread_context_create_thread(ThreadContext *tc, QemuThread *thread,
335e2de2c49SDavid Hildenbrand                                   const char *name,
336e2de2c49SDavid Hildenbrand                                   void *(*start_routine)(void *), void *arg,
337e2de2c49SDavid Hildenbrand                                   int mode)
338e2de2c49SDavid Hildenbrand {
339e2de2c49SDavid Hildenbrand     ThreadContextCmdNew data = {
340e2de2c49SDavid Hildenbrand         .thread = thread,
341e2de2c49SDavid Hildenbrand         .name = name,
342e2de2c49SDavid Hildenbrand         .start_routine = start_routine,
343e2de2c49SDavid Hildenbrand         .arg = arg,
344e2de2c49SDavid Hildenbrand         .mode = mode,
345e2de2c49SDavid Hildenbrand     };
346e2de2c49SDavid Hildenbrand 
347e2de2c49SDavid Hildenbrand     qemu_mutex_lock(&tc->mutex);
348e2de2c49SDavid Hildenbrand     tc->thread_cmd = TC_CMD_NEW;
349e2de2c49SDavid Hildenbrand     tc->thread_cmd_data = &data;
350e2de2c49SDavid Hildenbrand     qemu_sem_post(&tc->sem_thread);
351e2de2c49SDavid Hildenbrand 
352e2de2c49SDavid Hildenbrand     while (tc->thread_cmd != TC_CMD_NONE) {
353e2de2c49SDavid Hildenbrand         qemu_sem_wait(&tc->sem);
354e2de2c49SDavid Hildenbrand     }
355e2de2c49SDavid Hildenbrand     qemu_mutex_unlock(&tc->mutex);
356e2de2c49SDavid Hildenbrand }
357