1 /* 2 * QEMU TCG Multi Threaded vCPUs implementation 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * Copyright (c) 2014 Red Hat Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26 #include "qemu/osdep.h" 27 #include "qemu-common.h" 28 #include "sysemu/tcg.h" 29 #include "sysemu/replay.h" 30 #include "sysemu/cpu-timers.h" 31 #include "qemu/main-loop.h" 32 #include "qemu/notify.h" 33 #include "qemu/guest-random.h" 34 #include "exec/exec-all.h" 35 #include "hw/boards.h" 36 37 #include "tcg-accel-ops.h" 38 #include "tcg-accel-ops-mttcg.h" 39 40 typedef struct MttcgForceRcuNotifier { 41 Notifier notifier; 42 CPUState *cpu; 43 } MttcgForceRcuNotifier; 44 45 static void do_nothing(CPUState *cpu, run_on_cpu_data d) 46 { 47 } 48 49 static void mttcg_force_rcu(Notifier *notify, void *data) 50 { 51 CPUState *cpu = container_of(notify, MttcgForceRcuNotifier, notifier)->cpu; 52 53 /* 54 * Called with rcu_registry_lock held, using async_run_on_cpu() ensures 55 * that there are no deadlocks. 56 */ 57 async_run_on_cpu(cpu, do_nothing, RUN_ON_CPU_NULL); 58 } 59 60 /* 61 * In the multi-threaded case each vCPU has its own thread. The TLS 62 * variable current_cpu can be used deep in the code to find the 63 * current CPUState for a given thread. 64 */ 65 66 static void *mttcg_cpu_thread_fn(void *arg) 67 { 68 MttcgForceRcuNotifier force_rcu; 69 CPUState *cpu = arg; 70 71 assert(tcg_enabled()); 72 g_assert(!icount_enabled()); 73 74 rcu_register_thread(); 75 force_rcu.notifier.notify = mttcg_force_rcu; 76 force_rcu.cpu = cpu; 77 rcu_add_force_rcu_notifier(&force_rcu.notifier); 78 tcg_register_thread(); 79 80 qemu_mutex_lock_iothread(); 81 qemu_thread_get_self(cpu->thread); 82 83 cpu->thread_id = qemu_get_thread_id(); 84 cpu->can_do_io = 1; 85 current_cpu = cpu; 86 cpu_thread_signal_created(cpu); 87 qemu_guest_random_seed_thread_part2(cpu->random_seed); 88 89 /* process any pending work */ 90 cpu->exit_request = 1; 91 92 do { 93 if (cpu_can_run(cpu)) { 94 int r; 95 qemu_mutex_unlock_iothread(); 96 r = tcg_cpus_exec(cpu); 97 qemu_mutex_lock_iothread(); 98 switch (r) { 99 case EXCP_DEBUG: 100 cpu_handle_guest_debug(cpu); 101 break; 102 case EXCP_HALTED: 103 /* 104 * during start-up the vCPU is reset and the thread is 105 * kicked several times. If we don't ensure we go back 106 * to sleep in the halted state we won't cleanly 107 * start-up when the vCPU is enabled. 108 * 109 * cpu->halted should ensure we sleep in wait_io_event 110 */ 111 g_assert(cpu->halted); 112 break; 113 case EXCP_ATOMIC: 114 qemu_mutex_unlock_iothread(); 115 cpu_exec_step_atomic(cpu); 116 qemu_mutex_lock_iothread(); 117 default: 118 /* Ignore everything else? */ 119 break; 120 } 121 } 122 123 qatomic_mb_set(&cpu->exit_request, 0); 124 qemu_wait_io_event(cpu); 125 } while (!cpu->unplug || cpu_can_run(cpu)); 126 127 tcg_cpus_destroy(cpu); 128 qemu_mutex_unlock_iothread(); 129 rcu_remove_force_rcu_notifier(&force_rcu.notifier); 130 rcu_unregister_thread(); 131 return NULL; 132 } 133 134 void mttcg_kick_vcpu_thread(CPUState *cpu) 135 { 136 cpu_exit(cpu); 137 } 138 139 void mttcg_start_vcpu_thread(CPUState *cpu) 140 { 141 char thread_name[VCPU_THREAD_NAME_SIZE]; 142 143 g_assert(tcg_enabled()); 144 tcg_cpu_init_cflags(cpu, current_machine->smp.max_cpus > 1); 145 146 cpu->thread = g_malloc0(sizeof(QemuThread)); 147 cpu->halt_cond = g_malloc0(sizeof(QemuCond)); 148 qemu_cond_init(cpu->halt_cond); 149 150 /* create a thread per vCPU with TCG (MTTCG) */ 151 snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", 152 cpu->cpu_index); 153 154 qemu_thread_create(cpu->thread, thread_name, mttcg_cpu_thread_fn, 155 cpu, QEMU_THREAD_JOINABLE); 156 157 #ifdef _WIN32 158 cpu->hThread = qemu_thread_get_handle(cpu->thread); 159 #endif 160 } 161