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