qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

tcg-accel-ops-mttcg.c (4948B)


      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 "sysemu/tcg.h"
     28 #include "sysemu/replay.h"
     29 #include "sysemu/cpu-timers.h"
     30 #include "qemu/main-loop.h"
     31 #include "qemu/notify.h"
     32 #include "qemu/guest-random.h"
     33 #include "exec/exec-all.h"
     34 #include "hw/boards.h"
     35 
     36 #include "tcg-accel-ops.h"
     37 #include "tcg-accel-ops-mttcg.h"
     38 
     39 typedef struct MttcgForceRcuNotifier {
     40     Notifier notifier;
     41     CPUState *cpu;
     42 } MttcgForceRcuNotifier;
     43 
     44 static void do_nothing(CPUState *cpu, run_on_cpu_data d)
     45 {
     46 }
     47 
     48 static void mttcg_force_rcu(Notifier *notify, void *data)
     49 {
     50     CPUState *cpu = container_of(notify, MttcgForceRcuNotifier, notifier)->cpu;
     51 
     52     /*
     53      * Called with rcu_registry_lock held, using async_run_on_cpu() ensures
     54      * that there are no deadlocks.
     55      */
     56     async_run_on_cpu(cpu, do_nothing, RUN_ON_CPU_NULL);
     57 }
     58 
     59 /*
     60  * In the multi-threaded case each vCPU has its own thread. The TLS
     61  * variable current_cpu can be used deep in the code to find the
     62  * current CPUState for a given thread.
     63  */
     64 
     65 static void *mttcg_cpu_thread_fn(void *arg)
     66 {
     67     MttcgForceRcuNotifier force_rcu;
     68     CPUState *cpu = arg;
     69 
     70     assert(tcg_enabled());
     71     g_assert(!icount_enabled());
     72 
     73     rcu_register_thread();
     74     force_rcu.notifier.notify = mttcg_force_rcu;
     75     force_rcu.cpu = cpu;
     76     rcu_add_force_rcu_notifier(&force_rcu.notifier);
     77     tcg_register_thread();
     78 
     79     qemu_mutex_lock_iothread();
     80     qemu_thread_get_self(cpu->thread);
     81 
     82     cpu->thread_id = qemu_get_thread_id();
     83     cpu->can_do_io = 1;
     84     current_cpu = cpu;
     85     cpu_thread_signal_created(cpu);
     86     qemu_guest_random_seed_thread_part2(cpu->random_seed);
     87 
     88     /* process any pending work */
     89     cpu->exit_request = 1;
     90 
     91     do {
     92         if (cpu_can_run(cpu)) {
     93             int r;
     94             qemu_mutex_unlock_iothread();
     95             r = tcg_cpus_exec(cpu);
     96             qemu_mutex_lock_iothread();
     97             switch (r) {
     98             case EXCP_DEBUG:
     99                 cpu_handle_guest_debug(cpu);
    100                 break;
    101             case EXCP_HALTED:
    102                 /*
    103                  * during start-up the vCPU is reset and the thread is
    104                  * kicked several times. If we don't ensure we go back
    105                  * to sleep in the halted state we won't cleanly
    106                  * start-up when the vCPU is enabled.
    107                  *
    108                  * cpu->halted should ensure we sleep in wait_io_event
    109                  */
    110                 g_assert(cpu->halted);
    111                 break;
    112             case EXCP_ATOMIC:
    113                 qemu_mutex_unlock_iothread();
    114                 cpu_exec_step_atomic(cpu);
    115                 qemu_mutex_lock_iothread();
    116             default:
    117                 /* Ignore everything else? */
    118                 break;
    119             }
    120         }
    121 
    122         qatomic_mb_set(&cpu->exit_request, 0);
    123         qemu_wait_io_event(cpu);
    124     } while (!cpu->unplug || cpu_can_run(cpu));
    125 
    126     tcg_cpus_destroy(cpu);
    127     qemu_mutex_unlock_iothread();
    128     rcu_remove_force_rcu_notifier(&force_rcu.notifier);
    129     rcu_unregister_thread();
    130     return NULL;
    131 }
    132 
    133 void mttcg_kick_vcpu_thread(CPUState *cpu)
    134 {
    135     cpu_exit(cpu);
    136 }
    137 
    138 void mttcg_start_vcpu_thread(CPUState *cpu)
    139 {
    140     char thread_name[VCPU_THREAD_NAME_SIZE];
    141 
    142     g_assert(tcg_enabled());
    143     tcg_cpu_init_cflags(cpu, current_machine->smp.max_cpus > 1);
    144 
    145     cpu->thread = g_new0(QemuThread, 1);
    146     cpu->halt_cond = g_malloc0(sizeof(QemuCond));
    147     qemu_cond_init(cpu->halt_cond);
    148 
    149     /* create a thread per vCPU with TCG (MTTCG) */
    150     snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
    151              cpu->cpu_index);
    152 
    153     qemu_thread_create(cpu->thread, thread_name, mttcg_cpu_thread_fn,
    154                        cpu, QEMU_THREAD_JOINABLE);
    155 
    156 #ifdef _WIN32
    157     cpu->hThread = qemu_thread_get_handle(cpu->thread);
    158 #endif
    159 }