xref: /openbmc/qemu/util/thread-context.c (revision 10218ae6)
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 
24*10218ae6SDavid Hildenbrand #ifdef CONFIG_NUMA
25*10218ae6SDavid Hildenbrand #include <numa.h>
26*10218ae6SDavid Hildenbrand #endif
27*10218ae6SDavid 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 
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 
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     Error *err = NULL;
94e2de2c49SDavid Hildenbrand 
95*10218ae6SDavid Hildenbrand     if (tc->init_cpu_bitmap) {
96*10218ae6SDavid Hildenbrand         error_setg(errp, "Mixing CPU and node affinity not supported");
97*10218ae6SDavid Hildenbrand         return;
98*10218ae6SDavid Hildenbrand     }
99*10218ae6SDavid Hildenbrand 
100e2de2c49SDavid Hildenbrand     visit_type_uint16List(v, name, &host_cpus, &err);
101e2de2c49SDavid Hildenbrand     if (err) {
102e2de2c49SDavid Hildenbrand         error_propagate(errp, err);
103e2de2c49SDavid Hildenbrand         return;
104e2de2c49SDavid Hildenbrand     }
105e2de2c49SDavid Hildenbrand 
106e2de2c49SDavid Hildenbrand     if (!host_cpus) {
107e2de2c49SDavid Hildenbrand         error_setg(errp, "CPU list is empty");
108e2de2c49SDavid Hildenbrand         goto out;
109e2de2c49SDavid Hildenbrand     }
110e2de2c49SDavid Hildenbrand 
111e2de2c49SDavid Hildenbrand     for (l = host_cpus; l; l = l->next) {
112e2de2c49SDavid Hildenbrand         nbits = MAX(nbits, l->value + 1);
113e2de2c49SDavid Hildenbrand     }
114e2de2c49SDavid Hildenbrand     bitmap = bitmap_new(nbits);
115e2de2c49SDavid Hildenbrand     for (l = host_cpus; l; l = l->next) {
116e2de2c49SDavid Hildenbrand         set_bit(l->value, bitmap);
117e2de2c49SDavid Hildenbrand     }
118e2de2c49SDavid Hildenbrand 
119e2de2c49SDavid Hildenbrand     if (tc->thread_id != -1) {
120e2de2c49SDavid Hildenbrand         /*
121e2de2c49SDavid Hildenbrand          * Note: we won't be adjusting the affinity of any thread that is still
122e2de2c49SDavid Hildenbrand          * around, but only the affinity of the context thread.
123e2de2c49SDavid Hildenbrand          */
124e2de2c49SDavid Hildenbrand         ret = qemu_thread_set_affinity(&tc->thread, bitmap, nbits);
125e2de2c49SDavid Hildenbrand         if (ret) {
126e2de2c49SDavid Hildenbrand             error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret));
127e2de2c49SDavid Hildenbrand         }
128e2de2c49SDavid Hildenbrand     } else {
129e2de2c49SDavid Hildenbrand         tc->init_cpu_bitmap = bitmap;
130e2de2c49SDavid Hildenbrand         bitmap = NULL;
131e2de2c49SDavid Hildenbrand         tc->init_cpu_nbits = nbits;
132e2de2c49SDavid Hildenbrand     }
133e2de2c49SDavid Hildenbrand out:
134e2de2c49SDavid Hildenbrand     g_free(bitmap);
135e2de2c49SDavid Hildenbrand     qapi_free_uint16List(host_cpus);
136e2de2c49SDavid Hildenbrand }
137e2de2c49SDavid Hildenbrand 
138e2de2c49SDavid Hildenbrand static void thread_context_get_cpu_affinity(Object *obj, Visitor *v,
139e2de2c49SDavid Hildenbrand                                             const char *name, void *opaque,
140e2de2c49SDavid Hildenbrand                                             Error **errp)
141e2de2c49SDavid Hildenbrand {
142e2de2c49SDavid Hildenbrand     unsigned long *bitmap, nbits, value;
143e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
144e2de2c49SDavid Hildenbrand     uint16List *host_cpus = NULL;
145e2de2c49SDavid Hildenbrand     uint16List **tail = &host_cpus;
146e2de2c49SDavid Hildenbrand     int ret;
147e2de2c49SDavid Hildenbrand 
148e2de2c49SDavid Hildenbrand     if (tc->thread_id == -1) {
149e2de2c49SDavid Hildenbrand         error_setg(errp, "Object not initialized yet");
150e2de2c49SDavid Hildenbrand         return;
151e2de2c49SDavid Hildenbrand     }
152e2de2c49SDavid Hildenbrand 
153e2de2c49SDavid Hildenbrand     ret = qemu_thread_get_affinity(&tc->thread, &bitmap, &nbits);
154e2de2c49SDavid Hildenbrand     if (ret) {
155e2de2c49SDavid Hildenbrand         error_setg(errp, "Getting CPU affinity failed: %s", strerror(ret));
156e2de2c49SDavid Hildenbrand         return;
157e2de2c49SDavid Hildenbrand     }
158e2de2c49SDavid Hildenbrand 
159e2de2c49SDavid Hildenbrand     value = find_first_bit(bitmap, nbits);
160e2de2c49SDavid Hildenbrand     while (value < nbits) {
161e2de2c49SDavid Hildenbrand         QAPI_LIST_APPEND(tail, value);
162e2de2c49SDavid Hildenbrand 
163e2de2c49SDavid Hildenbrand         value = find_next_bit(bitmap, nbits, value + 1);
164e2de2c49SDavid Hildenbrand     }
165e2de2c49SDavid Hildenbrand     g_free(bitmap);
166e2de2c49SDavid Hildenbrand 
167e2de2c49SDavid Hildenbrand     visit_type_uint16List(v, name, &host_cpus, errp);
168e2de2c49SDavid Hildenbrand     qapi_free_uint16List(host_cpus);
169e2de2c49SDavid Hildenbrand }
170e2de2c49SDavid Hildenbrand 
171*10218ae6SDavid Hildenbrand static void thread_context_set_node_affinity(Object *obj, Visitor *v,
172*10218ae6SDavid Hildenbrand                                              const char *name, void *opaque,
173*10218ae6SDavid Hildenbrand                                              Error **errp)
174*10218ae6SDavid Hildenbrand {
175*10218ae6SDavid Hildenbrand #ifdef CONFIG_NUMA
176*10218ae6SDavid Hildenbrand     const int nbits = numa_num_possible_cpus();
177*10218ae6SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
178*10218ae6SDavid Hildenbrand     uint16List *l, *host_nodes = NULL;
179*10218ae6SDavid Hildenbrand     unsigned long *bitmap = NULL;
180*10218ae6SDavid Hildenbrand     struct bitmask *tmp_cpus;
181*10218ae6SDavid Hildenbrand     Error *err = NULL;
182*10218ae6SDavid Hildenbrand     int ret, i;
183*10218ae6SDavid Hildenbrand 
184*10218ae6SDavid Hildenbrand     if (tc->init_cpu_bitmap) {
185*10218ae6SDavid Hildenbrand         error_setg(errp, "Mixing CPU and node affinity not supported");
186*10218ae6SDavid Hildenbrand         return;
187*10218ae6SDavid Hildenbrand     }
188*10218ae6SDavid Hildenbrand 
189*10218ae6SDavid Hildenbrand     visit_type_uint16List(v, name, &host_nodes, &err);
190*10218ae6SDavid Hildenbrand     if (err) {
191*10218ae6SDavid Hildenbrand         error_propagate(errp, err);
192*10218ae6SDavid Hildenbrand         return;
193*10218ae6SDavid Hildenbrand     }
194*10218ae6SDavid Hildenbrand 
195*10218ae6SDavid Hildenbrand     if (!host_nodes) {
196*10218ae6SDavid Hildenbrand         error_setg(errp, "Node list is empty");
197*10218ae6SDavid Hildenbrand         goto out;
198*10218ae6SDavid Hildenbrand     }
199*10218ae6SDavid Hildenbrand 
200*10218ae6SDavid Hildenbrand     bitmap = bitmap_new(nbits);
201*10218ae6SDavid Hildenbrand     tmp_cpus = numa_allocate_cpumask();
202*10218ae6SDavid Hildenbrand     for (l = host_nodes; l; l = l->next) {
203*10218ae6SDavid Hildenbrand         numa_bitmask_clearall(tmp_cpus);
204*10218ae6SDavid Hildenbrand         ret = numa_node_to_cpus(l->value, tmp_cpus);
205*10218ae6SDavid Hildenbrand         if (ret) {
206*10218ae6SDavid Hildenbrand             /* We ignore any errors, such as impossible nodes. */
207*10218ae6SDavid Hildenbrand             continue;
208*10218ae6SDavid Hildenbrand         }
209*10218ae6SDavid Hildenbrand         for (i = 0; i < nbits; i++) {
210*10218ae6SDavid Hildenbrand             if (numa_bitmask_isbitset(tmp_cpus, i)) {
211*10218ae6SDavid Hildenbrand                 set_bit(i, bitmap);
212*10218ae6SDavid Hildenbrand             }
213*10218ae6SDavid Hildenbrand         }
214*10218ae6SDavid Hildenbrand     }
215*10218ae6SDavid Hildenbrand     numa_free_cpumask(tmp_cpus);
216*10218ae6SDavid Hildenbrand 
217*10218ae6SDavid Hildenbrand     if (bitmap_empty(bitmap, nbits)) {
218*10218ae6SDavid Hildenbrand         error_setg(errp, "The nodes select no CPUs");
219*10218ae6SDavid Hildenbrand         goto out;
220*10218ae6SDavid Hildenbrand     }
221*10218ae6SDavid Hildenbrand 
222*10218ae6SDavid Hildenbrand     if (tc->thread_id != -1) {
223*10218ae6SDavid Hildenbrand         /*
224*10218ae6SDavid Hildenbrand          * Note: we won't be adjusting the affinity of any thread that is still
225*10218ae6SDavid Hildenbrand          * around for now, but only the affinity of the context thread.
226*10218ae6SDavid Hildenbrand          */
227*10218ae6SDavid Hildenbrand         ret = qemu_thread_set_affinity(&tc->thread, bitmap, nbits);
228*10218ae6SDavid Hildenbrand         if (ret) {
229*10218ae6SDavid Hildenbrand             error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret));
230*10218ae6SDavid Hildenbrand         }
231*10218ae6SDavid Hildenbrand     } else {
232*10218ae6SDavid Hildenbrand         tc->init_cpu_bitmap = bitmap;
233*10218ae6SDavid Hildenbrand         bitmap = NULL;
234*10218ae6SDavid Hildenbrand         tc->init_cpu_nbits = nbits;
235*10218ae6SDavid Hildenbrand     }
236*10218ae6SDavid Hildenbrand out:
237*10218ae6SDavid Hildenbrand     g_free(bitmap);
238*10218ae6SDavid Hildenbrand     qapi_free_uint16List(host_nodes);
239*10218ae6SDavid Hildenbrand #else
240*10218ae6SDavid Hildenbrand     error_setg(errp, "NUMA node affinity is not supported by this QEMU");
241*10218ae6SDavid Hildenbrand #endif
242*10218ae6SDavid Hildenbrand }
243*10218ae6SDavid Hildenbrand 
244e2de2c49SDavid Hildenbrand static void thread_context_get_thread_id(Object *obj, Visitor *v,
245e2de2c49SDavid Hildenbrand                                          const char *name, void *opaque,
246e2de2c49SDavid Hildenbrand                                          Error **errp)
247e2de2c49SDavid Hildenbrand {
248e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
249e2de2c49SDavid Hildenbrand     uint64_t value = tc->thread_id;
250e2de2c49SDavid Hildenbrand 
251e2de2c49SDavid Hildenbrand     visit_type_uint64(v, name, &value, errp);
252e2de2c49SDavid Hildenbrand }
253e2de2c49SDavid Hildenbrand 
254e2de2c49SDavid Hildenbrand static void thread_context_instance_complete(UserCreatable *uc, Error **errp)
255e2de2c49SDavid Hildenbrand {
256e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(uc);
257e2de2c49SDavid Hildenbrand     char *thread_name;
258e2de2c49SDavid Hildenbrand     int ret;
259e2de2c49SDavid Hildenbrand 
260e2de2c49SDavid Hildenbrand     thread_name = g_strdup_printf("TC %s",
261e2de2c49SDavid Hildenbrand                                object_get_canonical_path_component(OBJECT(uc)));
262e2de2c49SDavid Hildenbrand     qemu_thread_create(&tc->thread, thread_name, thread_context_run, tc,
263e2de2c49SDavid Hildenbrand                        QEMU_THREAD_JOINABLE);
264e2de2c49SDavid Hildenbrand     g_free(thread_name);
265e2de2c49SDavid Hildenbrand 
266e2de2c49SDavid Hildenbrand     /* Wait until initialization of the thread is done. */
267e2de2c49SDavid Hildenbrand     while (tc->thread_id == -1) {
268e2de2c49SDavid Hildenbrand         qemu_sem_wait(&tc->sem);
269e2de2c49SDavid Hildenbrand     }
270e2de2c49SDavid Hildenbrand 
271e2de2c49SDavid Hildenbrand     if (tc->init_cpu_bitmap) {
272e2de2c49SDavid Hildenbrand         ret = qemu_thread_set_affinity(&tc->thread, tc->init_cpu_bitmap,
273e2de2c49SDavid Hildenbrand                                        tc->init_cpu_nbits);
274e2de2c49SDavid Hildenbrand         if (ret) {
275e2de2c49SDavid Hildenbrand             error_setg(errp, "Setting CPU affinity failed: %s", strerror(ret));
276e2de2c49SDavid Hildenbrand         }
277e2de2c49SDavid Hildenbrand         g_free(tc->init_cpu_bitmap);
278e2de2c49SDavid Hildenbrand         tc->init_cpu_bitmap = NULL;
279e2de2c49SDavid Hildenbrand     }
280e2de2c49SDavid Hildenbrand }
281e2de2c49SDavid Hildenbrand 
282e2de2c49SDavid Hildenbrand static void thread_context_class_init(ObjectClass *oc, void *data)
283e2de2c49SDavid Hildenbrand {
284e2de2c49SDavid Hildenbrand     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
285e2de2c49SDavid Hildenbrand 
286e2de2c49SDavid Hildenbrand     ucc->complete = thread_context_instance_complete;
287e2de2c49SDavid Hildenbrand     object_class_property_add(oc, "thread-id", "int",
288e2de2c49SDavid Hildenbrand                               thread_context_get_thread_id, NULL, NULL,
289e2de2c49SDavid Hildenbrand                               NULL);
290e2de2c49SDavid Hildenbrand     object_class_property_add(oc, "cpu-affinity", "int",
291e2de2c49SDavid Hildenbrand                               thread_context_get_cpu_affinity,
292e2de2c49SDavid Hildenbrand                               thread_context_set_cpu_affinity, NULL, NULL);
293*10218ae6SDavid Hildenbrand     object_class_property_add(oc, "node-affinity", "int", NULL,
294*10218ae6SDavid Hildenbrand                               thread_context_set_node_affinity, NULL, NULL);
295e2de2c49SDavid Hildenbrand }
296e2de2c49SDavid Hildenbrand 
297e2de2c49SDavid Hildenbrand static void thread_context_instance_init(Object *obj)
298e2de2c49SDavid Hildenbrand {
299e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
300e2de2c49SDavid Hildenbrand 
301e2de2c49SDavid Hildenbrand     tc->thread_id = -1;
302e2de2c49SDavid Hildenbrand     qemu_sem_init(&tc->sem, 0);
303e2de2c49SDavid Hildenbrand     qemu_sem_init(&tc->sem_thread, 0);
304e2de2c49SDavid Hildenbrand     qemu_mutex_init(&tc->mutex);
305e2de2c49SDavid Hildenbrand }
306e2de2c49SDavid Hildenbrand 
307e2de2c49SDavid Hildenbrand static void thread_context_instance_finalize(Object *obj)
308e2de2c49SDavid Hildenbrand {
309e2de2c49SDavid Hildenbrand     ThreadContext *tc = THREAD_CONTEXT(obj);
310e2de2c49SDavid Hildenbrand 
311e2de2c49SDavid Hildenbrand     if (tc->thread_id != -1) {
312e2de2c49SDavid Hildenbrand         tc->thread_cmd = TC_CMD_STOP;
313e2de2c49SDavid Hildenbrand         qemu_sem_post(&tc->sem_thread);
314e2de2c49SDavid Hildenbrand         qemu_thread_join(&tc->thread);
315e2de2c49SDavid Hildenbrand     }
316e2de2c49SDavid Hildenbrand     qemu_sem_destroy(&tc->sem);
317e2de2c49SDavid Hildenbrand     qemu_sem_destroy(&tc->sem_thread);
318e2de2c49SDavid Hildenbrand     qemu_mutex_destroy(&tc->mutex);
319e2de2c49SDavid Hildenbrand }
320e2de2c49SDavid Hildenbrand 
321e2de2c49SDavid Hildenbrand static const TypeInfo thread_context_info = {
322e2de2c49SDavid Hildenbrand     .name = TYPE_THREAD_CONTEXT,
323e2de2c49SDavid Hildenbrand     .parent = TYPE_OBJECT,
324e2de2c49SDavid Hildenbrand     .class_init = thread_context_class_init,
325e2de2c49SDavid Hildenbrand     .instance_size = sizeof(ThreadContext),
326e2de2c49SDavid Hildenbrand     .instance_init = thread_context_instance_init,
327e2de2c49SDavid Hildenbrand     .instance_finalize = thread_context_instance_finalize,
328e2de2c49SDavid Hildenbrand     .interfaces = (InterfaceInfo[]) {
329e2de2c49SDavid Hildenbrand         { TYPE_USER_CREATABLE },
330e2de2c49SDavid Hildenbrand         { }
331e2de2c49SDavid Hildenbrand     }
332e2de2c49SDavid Hildenbrand };
333e2de2c49SDavid Hildenbrand 
334e2de2c49SDavid Hildenbrand static void thread_context_register_types(void)
335e2de2c49SDavid Hildenbrand {
336e2de2c49SDavid Hildenbrand     type_register_static(&thread_context_info);
337e2de2c49SDavid Hildenbrand }
338e2de2c49SDavid Hildenbrand type_init(thread_context_register_types)
339e2de2c49SDavid Hildenbrand 
340e2de2c49SDavid Hildenbrand void thread_context_create_thread(ThreadContext *tc, QemuThread *thread,
341e2de2c49SDavid Hildenbrand                                   const char *name,
342e2de2c49SDavid Hildenbrand                                   void *(*start_routine)(void *), void *arg,
343e2de2c49SDavid Hildenbrand                                   int mode)
344e2de2c49SDavid Hildenbrand {
345e2de2c49SDavid Hildenbrand     ThreadContextCmdNew data = {
346e2de2c49SDavid Hildenbrand         .thread = thread,
347e2de2c49SDavid Hildenbrand         .name = name,
348e2de2c49SDavid Hildenbrand         .start_routine = start_routine,
349e2de2c49SDavid Hildenbrand         .arg = arg,
350e2de2c49SDavid Hildenbrand         .mode = mode,
351e2de2c49SDavid Hildenbrand     };
352e2de2c49SDavid Hildenbrand 
353e2de2c49SDavid Hildenbrand     qemu_mutex_lock(&tc->mutex);
354e2de2c49SDavid Hildenbrand     tc->thread_cmd = TC_CMD_NEW;
355e2de2c49SDavid Hildenbrand     tc->thread_cmd_data = &data;
356e2de2c49SDavid Hildenbrand     qemu_sem_post(&tc->sem_thread);
357e2de2c49SDavid Hildenbrand 
358e2de2c49SDavid Hildenbrand     while (tc->thread_cmd != TC_CMD_NONE) {
359e2de2c49SDavid Hildenbrand         qemu_sem_wait(&tc->sem);
360e2de2c49SDavid Hildenbrand     }
361e2de2c49SDavid Hildenbrand     qemu_mutex_unlock(&tc->mutex);
362e2de2c49SDavid Hildenbrand }
363