Commit d6dc3d424e26b49e1f37f1ef2598eacf3bc4eac7
1 parent
6e29f5da
qemu: introduce iothread (Marcelo Tosatti)
Fill in the hooks and introduce iothread. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7248 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
395 additions
and
22 deletions
cpu-defs.h
| @@ -170,6 +170,8 @@ typedef struct CPUWatchpoint { | @@ -170,6 +170,8 @@ typedef struct CPUWatchpoint { | ||
| 170 | target_ulong mem_io_vaddr; /* target virtual addr at which the \ | 170 | target_ulong mem_io_vaddr; /* target virtual addr at which the \ |
| 171 | memory was accessed */ \ | 171 | memory was accessed */ \ |
| 172 | uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ | 172 | uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ |
| 173 | + uint32_t stop; /* Stop request */ \ | ||
| 174 | + uint32_t stopped; /* Artificially stopped */ \ | ||
| 173 | uint32_t interrupt_request; \ | 175 | uint32_t interrupt_request; \ |
| 174 | volatile sig_atomic_t exit_request; \ | 176 | volatile sig_atomic_t exit_request; \ |
| 175 | /* The meaning of the MMU modes is defined in the target code. */ \ | 177 | /* The meaning of the MMU modes is defined in the target code. */ \ |
| @@ -210,6 +212,9 @@ typedef struct CPUWatchpoint { | @@ -210,6 +212,9 @@ typedef struct CPUWatchpoint { | ||
| 210 | /* user data */ \ | 212 | /* user data */ \ |
| 211 | void *opaque; \ | 213 | void *opaque; \ |
| 212 | \ | 214 | \ |
| 215 | + uint32_t created; \ | ||
| 216 | + struct QemuThread *thread; \ | ||
| 217 | + struct QemuCond *halt_cond; \ | ||
| 213 | const char *cpu_model_str; \ | 218 | const char *cpu_model_str; \ |
| 214 | struct KVMState *kvm_state; \ | 219 | struct KVMState *kvm_state; \ |
| 215 | struct kvm_run *kvm_run; \ | 220 | struct kvm_run *kvm_run; \ |
vl.c
| @@ -1346,20 +1346,20 @@ static void host_alarm_handler(int host_signum) | @@ -1346,20 +1346,20 @@ static void host_alarm_handler(int host_signum) | ||
| 1346 | qemu_get_clock(vm_clock))) || | 1346 | qemu_get_clock(vm_clock))) || |
| 1347 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], | 1347 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], |
| 1348 | qemu_get_clock(rt_clock))) { | 1348 | qemu_get_clock(rt_clock))) { |
| 1349 | - CPUState *env = next_cpu; | ||
| 1350 | - | ||
| 1351 | qemu_event_increment(); | 1349 | qemu_event_increment(); |
| 1352 | alarm_timer->flags |= ALARM_FLAG_EXPIRED; | 1350 | alarm_timer->flags |= ALARM_FLAG_EXPIRED; |
| 1353 | 1351 | ||
| 1354 | - if (env) { | 1352 | +#ifndef CONFIG_IOTHREAD |
| 1353 | + if (next_cpu) { | ||
| 1355 | /* stop the currently executing cpu because a timer occured */ | 1354 | /* stop the currently executing cpu because a timer occured */ |
| 1356 | - cpu_exit(env); | 1355 | + cpu_exit(next_cpu); |
| 1357 | #ifdef CONFIG_KQEMU | 1356 | #ifdef CONFIG_KQEMU |
| 1358 | - if (env->kqemu_enabled) { | ||
| 1359 | - kqemu_cpu_interrupt(env); | 1357 | + if (next_cpu->kqemu_enabled) { |
| 1358 | + kqemu_cpu_interrupt(next_cpu); | ||
| 1360 | } | 1359 | } |
| 1361 | #endif | 1360 | #endif |
| 1362 | } | 1361 | } |
| 1362 | +#endif | ||
| 1363 | timer_alarm_pending = 1; | 1363 | timer_alarm_pending = 1; |
| 1364 | qemu_notify_event(); | 1364 | qemu_notify_event(); |
| 1365 | } | 1365 | } |
| @@ -3537,6 +3537,9 @@ static void vm_state_notify(int running, int reason) | @@ -3537,6 +3537,9 @@ static void vm_state_notify(int running, int reason) | ||
| 3537 | } | 3537 | } |
| 3538 | } | 3538 | } |
| 3539 | 3539 | ||
| 3540 | +static void resume_all_vcpus(void); | ||
| 3541 | +static void pause_all_vcpus(void); | ||
| 3542 | + | ||
| 3540 | void vm_start(void) | 3543 | void vm_start(void) |
| 3541 | { | 3544 | { |
| 3542 | if (!vm_running) { | 3545 | if (!vm_running) { |
| @@ -3544,6 +3547,7 @@ void vm_start(void) | @@ -3544,6 +3547,7 @@ void vm_start(void) | ||
| 3544 | vm_running = 1; | 3547 | vm_running = 1; |
| 3545 | vm_state_notify(1, 0); | 3548 | vm_state_notify(1, 0); |
| 3546 | qemu_rearm_alarm_timer(alarm_timer); | 3549 | qemu_rearm_alarm_timer(alarm_timer); |
| 3550 | + resume_all_vcpus(); | ||
| 3547 | } | 3551 | } |
| 3548 | } | 3552 | } |
| 3549 | 3553 | ||
| @@ -3602,6 +3606,7 @@ static void do_vm_stop(int reason) | @@ -3602,6 +3606,7 @@ static void do_vm_stop(int reason) | ||
| 3602 | if (vm_running) { | 3606 | if (vm_running) { |
| 3603 | cpu_disable_ticks(); | 3607 | cpu_disable_ticks(); |
| 3604 | vm_running = 0; | 3608 | vm_running = 0; |
| 3609 | + pause_all_vcpus(); | ||
| 3605 | vm_state_notify(0, reason); | 3610 | vm_state_notify(0, reason); |
| 3606 | } | 3611 | } |
| 3607 | } | 3612 | } |
| @@ -3654,18 +3659,13 @@ void qemu_system_powerdown_request(void) | @@ -3654,18 +3659,13 @@ void qemu_system_powerdown_request(void) | ||
| 3654 | qemu_notify_event(); | 3659 | qemu_notify_event(); |
| 3655 | } | 3660 | } |
| 3656 | 3661 | ||
| 3657 | -void qemu_notify_event(void) | 3662 | +#ifdef CONFIG_IOTHREAD |
| 3663 | +static void qemu_system_vmstop_request(int reason) | ||
| 3658 | { | 3664 | { |
| 3659 | - CPUState *env = cpu_single_env; | ||
| 3660 | - | ||
| 3661 | - if (env) { | ||
| 3662 | - cpu_exit(env); | ||
| 3663 | -#ifdef USE_KQEMU | ||
| 3664 | - if (env->kqemu_enabled) | ||
| 3665 | - kqemu_cpu_interrupt(env); | ||
| 3666 | -#endif | ||
| 3667 | - } | 3665 | + vmstop_requested = reason; |
| 3666 | + qemu_notify_event(); | ||
| 3668 | } | 3667 | } |
| 3668 | +#endif | ||
| 3669 | 3669 | ||
| 3670 | #ifndef _WIN32 | 3670 | #ifndef _WIN32 |
| 3671 | static int io_thread_fd = -1; | 3671 | static int io_thread_fd = -1; |
| @@ -3742,6 +3742,16 @@ static void qemu_event_increment(void) | @@ -3742,6 +3742,16 @@ static void qemu_event_increment(void) | ||
| 3742 | } | 3742 | } |
| 3743 | #endif | 3743 | #endif |
| 3744 | 3744 | ||
| 3745 | +static int cpu_can_run(CPUState *env) | ||
| 3746 | +{ | ||
| 3747 | + if (env->stop) | ||
| 3748 | + return 0; | ||
| 3749 | + if (env->stopped) | ||
| 3750 | + return 0; | ||
| 3751 | + return 1; | ||
| 3752 | +} | ||
| 3753 | + | ||
| 3754 | +#ifndef CONFIG_IOTHREAD | ||
| 3745 | static int qemu_init_main_loop(void) | 3755 | static int qemu_init_main_loop(void) |
| 3746 | { | 3756 | { |
| 3747 | return qemu_event_init(); | 3757 | return qemu_event_init(); |
| @@ -3761,11 +3771,32 @@ int qemu_cpu_self(void *env) | @@ -3761,11 +3771,32 @@ int qemu_cpu_self(void *env) | ||
| 3761 | return 1; | 3771 | return 1; |
| 3762 | } | 3772 | } |
| 3763 | 3773 | ||
| 3774 | +static void resume_all_vcpus(void) | ||
| 3775 | +{ | ||
| 3776 | +} | ||
| 3777 | + | ||
| 3778 | +static void pause_all_vcpus(void) | ||
| 3779 | +{ | ||
| 3780 | +} | ||
| 3781 | + | ||
| 3764 | void qemu_cpu_kick(void *env) | 3782 | void qemu_cpu_kick(void *env) |
| 3765 | { | 3783 | { |
| 3766 | return; | 3784 | return; |
| 3767 | } | 3785 | } |
| 3768 | 3786 | ||
| 3787 | +void qemu_notify_event(void) | ||
| 3788 | +{ | ||
| 3789 | + CPUState *env = cpu_single_env; | ||
| 3790 | + | ||
| 3791 | + if (env) { | ||
| 3792 | + cpu_exit(env); | ||
| 3793 | +#ifdef USE_KQEMU | ||
| 3794 | + if (env->kqemu_enabled) | ||
| 3795 | + kqemu_cpu_interrupt(env); | ||
| 3796 | +#endif | ||
| 3797 | + } | ||
| 3798 | +} | ||
| 3799 | + | ||
| 3769 | #define qemu_mutex_lock_iothread() do { } while (0) | 3800 | #define qemu_mutex_lock_iothread() do { } while (0) |
| 3770 | #define qemu_mutex_unlock_iothread() do { } while (0) | 3801 | #define qemu_mutex_unlock_iothread() do { } while (0) |
| 3771 | 3802 | ||
| @@ -3774,6 +3805,321 @@ void vm_stop(int reason) | @@ -3774,6 +3805,321 @@ void vm_stop(int reason) | ||
| 3774 | do_vm_stop(reason); | 3805 | do_vm_stop(reason); |
| 3775 | } | 3806 | } |
| 3776 | 3807 | ||
| 3808 | +#else /* CONFIG_IOTHREAD */ | ||
| 3809 | + | ||
| 3810 | +#include "qemu-thread.h" | ||
| 3811 | + | ||
| 3812 | +QemuMutex qemu_global_mutex; | ||
| 3813 | +static QemuMutex qemu_fair_mutex; | ||
| 3814 | + | ||
| 3815 | +static QemuThread io_thread; | ||
| 3816 | + | ||
| 3817 | +static QemuThread *tcg_cpu_thread; | ||
| 3818 | +static QemuCond *tcg_halt_cond; | ||
| 3819 | + | ||
| 3820 | +static int qemu_system_ready; | ||
| 3821 | +/* cpu creation */ | ||
| 3822 | +static QemuCond qemu_cpu_cond; | ||
| 3823 | +/* system init */ | ||
| 3824 | +static QemuCond qemu_system_cond; | ||
| 3825 | +static QemuCond qemu_pause_cond; | ||
| 3826 | + | ||
| 3827 | +static void block_io_signals(void); | ||
| 3828 | +static void unblock_io_signals(void); | ||
| 3829 | +static int tcg_has_work(void); | ||
| 3830 | + | ||
| 3831 | +static int qemu_init_main_loop(void) | ||
| 3832 | +{ | ||
| 3833 | + int ret; | ||
| 3834 | + | ||
| 3835 | + ret = qemu_event_init(); | ||
| 3836 | + if (ret) | ||
| 3837 | + return ret; | ||
| 3838 | + | ||
| 3839 | + qemu_cond_init(&qemu_pause_cond); | ||
| 3840 | + qemu_mutex_init(&qemu_fair_mutex); | ||
| 3841 | + qemu_mutex_init(&qemu_global_mutex); | ||
| 3842 | + qemu_mutex_lock(&qemu_global_mutex); | ||
| 3843 | + | ||
| 3844 | + unblock_io_signals(); | ||
| 3845 | + qemu_thread_self(&io_thread); | ||
| 3846 | + | ||
| 3847 | + return 0; | ||
| 3848 | +} | ||
| 3849 | + | ||
| 3850 | +static void qemu_wait_io_event(CPUState *env) | ||
| 3851 | +{ | ||
| 3852 | + while (!tcg_has_work()) | ||
| 3853 | + qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000); | ||
| 3854 | + | ||
| 3855 | + qemu_mutex_unlock(&qemu_global_mutex); | ||
| 3856 | + | ||
| 3857 | + /* | ||
| 3858 | + * Users of qemu_global_mutex can be starved, having no chance | ||
| 3859 | + * to acquire it since this path will get to it first. | ||
| 3860 | + * So use another lock to provide fairness. | ||
| 3861 | + */ | ||
| 3862 | + qemu_mutex_lock(&qemu_fair_mutex); | ||
| 3863 | + qemu_mutex_unlock(&qemu_fair_mutex); | ||
| 3864 | + | ||
| 3865 | + qemu_mutex_lock(&qemu_global_mutex); | ||
| 3866 | + if (env->stop) { | ||
| 3867 | + env->stop = 0; | ||
| 3868 | + env->stopped = 1; | ||
| 3869 | + qemu_cond_signal(&qemu_pause_cond); | ||
| 3870 | + } | ||
| 3871 | +} | ||
| 3872 | + | ||
| 3873 | +static int qemu_cpu_exec(CPUState *env); | ||
| 3874 | + | ||
| 3875 | +static void *kvm_cpu_thread_fn(void *arg) | ||
| 3876 | +{ | ||
| 3877 | + CPUState *env = arg; | ||
| 3878 | + | ||
| 3879 | + block_io_signals(); | ||
| 3880 | + qemu_thread_self(env->thread); | ||
| 3881 | + | ||
| 3882 | + /* signal CPU creation */ | ||
| 3883 | + qemu_mutex_lock(&qemu_global_mutex); | ||
| 3884 | + env->created = 1; | ||
| 3885 | + qemu_cond_signal(&qemu_cpu_cond); | ||
| 3886 | + | ||
| 3887 | + /* and wait for machine initialization */ | ||
| 3888 | + while (!qemu_system_ready) | ||
| 3889 | + qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); | ||
| 3890 | + | ||
| 3891 | + while (1) { | ||
| 3892 | + if (cpu_can_run(env)) | ||
| 3893 | + qemu_cpu_exec(env); | ||
| 3894 | + qemu_wait_io_event(env); | ||
| 3895 | + } | ||
| 3896 | + | ||
| 3897 | + return NULL; | ||
| 3898 | +} | ||
| 3899 | + | ||
| 3900 | +static void tcg_cpu_exec(void); | ||
| 3901 | + | ||
| 3902 | +static void *tcg_cpu_thread_fn(void *arg) | ||
| 3903 | +{ | ||
| 3904 | + CPUState *env = arg; | ||
| 3905 | + | ||
| 3906 | + block_io_signals(); | ||
| 3907 | + qemu_thread_self(env->thread); | ||
| 3908 | + | ||
| 3909 | + /* signal CPU creation */ | ||
| 3910 | + qemu_mutex_lock(&qemu_global_mutex); | ||
| 3911 | + for (env = first_cpu; env != NULL; env = env->next_cpu) | ||
| 3912 | + env->created = 1; | ||
| 3913 | + qemu_cond_signal(&qemu_cpu_cond); | ||
| 3914 | + | ||
| 3915 | + /* and wait for machine initialization */ | ||
| 3916 | + while (!qemu_system_ready) | ||
| 3917 | + qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); | ||
| 3918 | + | ||
| 3919 | + while (1) { | ||
| 3920 | + tcg_cpu_exec(); | ||
| 3921 | + qemu_wait_io_event(cur_cpu); | ||
| 3922 | + } | ||
| 3923 | + | ||
| 3924 | + return NULL; | ||
| 3925 | +} | ||
| 3926 | + | ||
| 3927 | +void qemu_cpu_kick(void *_env) | ||
| 3928 | +{ | ||
| 3929 | + CPUState *env = _env; | ||
| 3930 | + qemu_cond_broadcast(env->halt_cond); | ||
| 3931 | + if (kvm_enabled()) | ||
| 3932 | + qemu_thread_signal(env->thread, SIGUSR1); | ||
| 3933 | +} | ||
| 3934 | + | ||
| 3935 | +int qemu_cpu_self(void *env) | ||
| 3936 | +{ | ||
| 3937 | + return (cpu_single_env != NULL); | ||
| 3938 | +} | ||
| 3939 | + | ||
| 3940 | +static void cpu_signal(int sig) | ||
| 3941 | +{ | ||
| 3942 | + if (cpu_single_env) | ||
| 3943 | + cpu_exit(cpu_single_env); | ||
| 3944 | +} | ||
| 3945 | + | ||
| 3946 | +static void block_io_signals(void) | ||
| 3947 | +{ | ||
| 3948 | + sigset_t set; | ||
| 3949 | + struct sigaction sigact; | ||
| 3950 | + | ||
| 3951 | + sigemptyset(&set); | ||
| 3952 | + sigaddset(&set, SIGUSR2); | ||
| 3953 | + sigaddset(&set, SIGIO); | ||
| 3954 | + sigaddset(&set, SIGALRM); | ||
| 3955 | + pthread_sigmask(SIG_BLOCK, &set, NULL); | ||
| 3956 | + | ||
| 3957 | + sigemptyset(&set); | ||
| 3958 | + sigaddset(&set, SIGUSR1); | ||
| 3959 | + pthread_sigmask(SIG_UNBLOCK, &set, NULL); | ||
| 3960 | + | ||
| 3961 | + memset(&sigact, 0, sizeof(sigact)); | ||
| 3962 | + sigact.sa_handler = cpu_signal; | ||
| 3963 | + sigaction(SIGUSR1, &sigact, NULL); | ||
| 3964 | +} | ||
| 3965 | + | ||
| 3966 | +static void unblock_io_signals(void) | ||
| 3967 | +{ | ||
| 3968 | + sigset_t set; | ||
| 3969 | + | ||
| 3970 | + sigemptyset(&set); | ||
| 3971 | + sigaddset(&set, SIGUSR2); | ||
| 3972 | + sigaddset(&set, SIGIO); | ||
| 3973 | + sigaddset(&set, SIGALRM); | ||
| 3974 | + pthread_sigmask(SIG_UNBLOCK, &set, NULL); | ||
| 3975 | + | ||
| 3976 | + sigemptyset(&set); | ||
| 3977 | + sigaddset(&set, SIGUSR1); | ||
| 3978 | + pthread_sigmask(SIG_BLOCK, &set, NULL); | ||
| 3979 | +} | ||
| 3980 | + | ||
| 3981 | +static void qemu_signal_lock(unsigned int msecs) | ||
| 3982 | +{ | ||
| 3983 | + qemu_mutex_lock(&qemu_fair_mutex); | ||
| 3984 | + | ||
| 3985 | + while (qemu_mutex_trylock(&qemu_global_mutex)) { | ||
| 3986 | + qemu_thread_signal(tcg_cpu_thread, SIGUSR1); | ||
| 3987 | + if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs)) | ||
| 3988 | + break; | ||
| 3989 | + } | ||
| 3990 | + qemu_mutex_unlock(&qemu_fair_mutex); | ||
| 3991 | +} | ||
| 3992 | + | ||
| 3993 | +static void qemu_mutex_lock_iothread(void) | ||
| 3994 | +{ | ||
| 3995 | + if (kvm_enabled()) { | ||
| 3996 | + qemu_mutex_lock(&qemu_fair_mutex); | ||
| 3997 | + qemu_mutex_lock(&qemu_global_mutex); | ||
| 3998 | + qemu_mutex_unlock(&qemu_fair_mutex); | ||
| 3999 | + } else | ||
| 4000 | + qemu_signal_lock(100); | ||
| 4001 | +} | ||
| 4002 | + | ||
| 4003 | +static void qemu_mutex_unlock_iothread(void) | ||
| 4004 | +{ | ||
| 4005 | + qemu_mutex_unlock(&qemu_global_mutex); | ||
| 4006 | +} | ||
| 4007 | + | ||
| 4008 | +static int all_vcpus_paused(void) | ||
| 4009 | +{ | ||
| 4010 | + CPUState *penv = first_cpu; | ||
| 4011 | + | ||
| 4012 | + while (penv) { | ||
| 4013 | + if (!penv->stopped) | ||
| 4014 | + return 0; | ||
| 4015 | + penv = (CPUState *)penv->next_cpu; | ||
| 4016 | + } | ||
| 4017 | + | ||
| 4018 | + return 1; | ||
| 4019 | +} | ||
| 4020 | + | ||
| 4021 | +static void pause_all_vcpus(void) | ||
| 4022 | +{ | ||
| 4023 | + CPUState *penv = first_cpu; | ||
| 4024 | + | ||
| 4025 | + while (penv) { | ||
| 4026 | + penv->stop = 1; | ||
| 4027 | + qemu_thread_signal(penv->thread, SIGUSR1); | ||
| 4028 | + qemu_cpu_kick(penv); | ||
| 4029 | + penv = (CPUState *)penv->next_cpu; | ||
| 4030 | + } | ||
| 4031 | + | ||
| 4032 | + while (!all_vcpus_paused()) { | ||
| 4033 | + qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100); | ||
| 4034 | + penv = first_cpu; | ||
| 4035 | + while (penv) { | ||
| 4036 | + qemu_thread_signal(penv->thread, SIGUSR1); | ||
| 4037 | + penv = (CPUState *)penv->next_cpu; | ||
| 4038 | + } | ||
| 4039 | + } | ||
| 4040 | +} | ||
| 4041 | + | ||
| 4042 | +static void resume_all_vcpus(void) | ||
| 4043 | +{ | ||
| 4044 | + CPUState *penv = first_cpu; | ||
| 4045 | + | ||
| 4046 | + while (penv) { | ||
| 4047 | + penv->stop = 0; | ||
| 4048 | + penv->stopped = 0; | ||
| 4049 | + qemu_thread_signal(penv->thread, SIGUSR1); | ||
| 4050 | + qemu_cpu_kick(penv); | ||
| 4051 | + penv = (CPUState *)penv->next_cpu; | ||
| 4052 | + } | ||
| 4053 | +} | ||
| 4054 | + | ||
| 4055 | +static void tcg_init_vcpu(void *_env) | ||
| 4056 | +{ | ||
| 4057 | + CPUState *env = _env; | ||
| 4058 | + /* share a single thread for all cpus with TCG */ | ||
| 4059 | + if (!tcg_cpu_thread) { | ||
| 4060 | + env->thread = qemu_mallocz(sizeof(QemuThread)); | ||
| 4061 | + env->halt_cond = qemu_mallocz(sizeof(QemuCond)); | ||
| 4062 | + qemu_cond_init(env->halt_cond); | ||
| 4063 | + qemu_thread_create(env->thread, tcg_cpu_thread_fn, env); | ||
| 4064 | + while (env->created == 0) | ||
| 4065 | + qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); | ||
| 4066 | + tcg_cpu_thread = env->thread; | ||
| 4067 | + tcg_halt_cond = env->halt_cond; | ||
| 4068 | + } else { | ||
| 4069 | + env->thread = tcg_cpu_thread; | ||
| 4070 | + env->halt_cond = tcg_halt_cond; | ||
| 4071 | + } | ||
| 4072 | +} | ||
| 4073 | + | ||
| 4074 | +static void kvm_start_vcpu(CPUState *env) | ||
| 4075 | +{ | ||
| 4076 | + kvm_init_vcpu(env); | ||
| 4077 | + env->thread = qemu_mallocz(sizeof(QemuThread)); | ||
| 4078 | + env->halt_cond = qemu_mallocz(sizeof(QemuCond)); | ||
| 4079 | + qemu_cond_init(env->halt_cond); | ||
| 4080 | + qemu_thread_create(env->thread, kvm_cpu_thread_fn, env); | ||
| 4081 | + while (env->created == 0) | ||
| 4082 | + qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); | ||
| 4083 | +} | ||
| 4084 | + | ||
| 4085 | +void qemu_init_vcpu(void *_env) | ||
| 4086 | +{ | ||
| 4087 | + CPUState *env = _env; | ||
| 4088 | + | ||
| 4089 | + if (kvm_enabled()) | ||
| 4090 | + kvm_start_vcpu(env); | ||
| 4091 | + else | ||
| 4092 | + tcg_init_vcpu(env); | ||
| 4093 | +} | ||
| 4094 | + | ||
| 4095 | +void qemu_notify_event(void) | ||
| 4096 | +{ | ||
| 4097 | + qemu_event_increment(); | ||
| 4098 | +} | ||
| 4099 | + | ||
| 4100 | +void vm_stop(int reason) | ||
| 4101 | +{ | ||
| 4102 | + QemuThread me; | ||
| 4103 | + qemu_thread_self(&me); | ||
| 4104 | + | ||
| 4105 | + if (!qemu_thread_equal(&me, &io_thread)) { | ||
| 4106 | + qemu_system_vmstop_request(reason); | ||
| 4107 | + /* | ||
| 4108 | + * FIXME: should not return to device code in case | ||
| 4109 | + * vm_stop() has been requested. | ||
| 4110 | + */ | ||
| 4111 | + if (cpu_single_env) { | ||
| 4112 | + cpu_exit(cpu_single_env); | ||
| 4113 | + cpu_single_env->stop = 1; | ||
| 4114 | + } | ||
| 4115 | + return; | ||
| 4116 | + } | ||
| 4117 | + do_vm_stop(reason); | ||
| 4118 | +} | ||
| 4119 | + | ||
| 4120 | +#endif | ||
| 4121 | + | ||
| 4122 | + | ||
| 3777 | #ifdef _WIN32 | 4123 | #ifdef _WIN32 |
| 3778 | static void host_main_loop_wait(int *timeout) | 4124 | static void host_main_loop_wait(int *timeout) |
| 3779 | { | 4125 | { |
| @@ -3910,9 +4256,11 @@ void main_loop_wait(int timeout) | @@ -3910,9 +4256,11 @@ void main_loop_wait(int timeout) | ||
| 3910 | } | 4256 | } |
| 3911 | 4257 | ||
| 3912 | /* vm time timers */ | 4258 | /* vm time timers */ |
| 3913 | - if (vm_running && likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))) | ||
| 3914 | - qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], | ||
| 3915 | - qemu_get_clock(vm_clock)); | 4259 | + if (vm_running) { |
| 4260 | + if (!cur_cpu || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))) | ||
| 4261 | + qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], | ||
| 4262 | + qemu_get_clock(vm_clock)); | ||
| 4263 | + } | ||
| 3916 | 4264 | ||
| 3917 | /* real time timers */ | 4265 | /* real time timers */ |
| 3918 | qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], | 4266 | qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], |
| @@ -3966,7 +4314,7 @@ static int qemu_cpu_exec(CPUState *env) | @@ -3966,7 +4314,7 @@ static int qemu_cpu_exec(CPUState *env) | ||
| 3966 | 4314 | ||
| 3967 | static void tcg_cpu_exec(void) | 4315 | static void tcg_cpu_exec(void) |
| 3968 | { | 4316 | { |
| 3969 | - int ret; | 4317 | + int ret = 0; |
| 3970 | 4318 | ||
| 3971 | if (next_cpu == NULL) | 4319 | if (next_cpu == NULL) |
| 3972 | next_cpu = first_cpu; | 4320 | next_cpu = first_cpu; |
| @@ -3979,7 +4327,8 @@ static void tcg_cpu_exec(void) | @@ -3979,7 +4327,8 @@ static void tcg_cpu_exec(void) | ||
| 3979 | timer_alarm_pending = 0; | 4327 | timer_alarm_pending = 0; |
| 3980 | break; | 4328 | break; |
| 3981 | } | 4329 | } |
| 3982 | - ret = qemu_cpu_exec(env); | 4330 | + if (cpu_can_run(env)) |
| 4331 | + ret = qemu_cpu_exec(env); | ||
| 3983 | if (ret == EXCP_DEBUG) { | 4332 | if (ret == EXCP_DEBUG) { |
| 3984 | gdb_set_stop_cpu(env); | 4333 | gdb_set_stop_cpu(env); |
| 3985 | debug_requested = 1; | 4334 | debug_requested = 1; |
| @@ -3990,6 +4339,10 @@ static void tcg_cpu_exec(void) | @@ -3990,6 +4339,10 @@ static void tcg_cpu_exec(void) | ||
| 3990 | 4339 | ||
| 3991 | static int cpu_has_work(CPUState *env) | 4340 | static int cpu_has_work(CPUState *env) |
| 3992 | { | 4341 | { |
| 4342 | + if (env->stop) | ||
| 4343 | + return 1; | ||
| 4344 | + if (env->stopped) | ||
| 4345 | + return 0; | ||
| 3993 | if (!env->halted) | 4346 | if (!env->halted) |
| 3994 | return 1; | 4347 | return 1; |
| 3995 | if (qemu_cpu_has_work(env)) | 4348 | if (qemu_cpu_has_work(env)) |
| @@ -4073,16 +4426,27 @@ static void main_loop(void) | @@ -4073,16 +4426,27 @@ static void main_loop(void) | ||
| 4073 | { | 4426 | { |
| 4074 | int r; | 4427 | int r; |
| 4075 | 4428 | ||
| 4429 | +#ifdef CONFIG_IOTHREAD | ||
| 4430 | + qemu_system_ready = 1; | ||
| 4431 | + qemu_cond_broadcast(&qemu_system_cond); | ||
| 4432 | +#endif | ||
| 4433 | + | ||
| 4076 | for (;;) { | 4434 | for (;;) { |
| 4077 | do { | 4435 | do { |
| 4078 | #ifdef CONFIG_PROFILER | 4436 | #ifdef CONFIG_PROFILER |
| 4079 | int64_t ti; | 4437 | int64_t ti; |
| 4080 | #endif | 4438 | #endif |
| 4439 | +#ifndef CONFIG_IOTHREAD | ||
| 4081 | tcg_cpu_exec(); | 4440 | tcg_cpu_exec(); |
| 4441 | +#endif | ||
| 4082 | #ifdef CONFIG_PROFILER | 4442 | #ifdef CONFIG_PROFILER |
| 4083 | ti = profile_getclock(); | 4443 | ti = profile_getclock(); |
| 4084 | #endif | 4444 | #endif |
| 4445 | +#ifdef CONFIG_IOTHREAD | ||
| 4446 | + main_loop_wait(1000); | ||
| 4447 | +#else | ||
| 4085 | main_loop_wait(qemu_calculate_timeout()); | 4448 | main_loop_wait(qemu_calculate_timeout()); |
| 4449 | +#endif | ||
| 4086 | #ifdef CONFIG_PROFILER | 4450 | #ifdef CONFIG_PROFILER |
| 4087 | dev_time += profile_getclock() - ti; | 4451 | dev_time += profile_getclock() - ti; |
| 4088 | #endif | 4452 | #endif |
| @@ -4097,13 +4461,17 @@ static void main_loop(void) | @@ -4097,13 +4461,17 @@ static void main_loop(void) | ||
| 4097 | } else | 4461 | } else |
| 4098 | break; | 4462 | break; |
| 4099 | } | 4463 | } |
| 4100 | - if (qemu_reset_requested()) | 4464 | + if (qemu_reset_requested()) { |
| 4465 | + pause_all_vcpus(); | ||
| 4101 | qemu_system_reset(); | 4466 | qemu_system_reset(); |
| 4467 | + resume_all_vcpus(); | ||
| 4468 | + } | ||
| 4102 | if (qemu_powerdown_requested()) | 4469 | if (qemu_powerdown_requested()) |
| 4103 | qemu_system_powerdown(); | 4470 | qemu_system_powerdown(); |
| 4104 | if ((r = qemu_vmstop_requested())) | 4471 | if ((r = qemu_vmstop_requested())) |
| 4105 | vm_stop(r); | 4472 | vm_stop(r); |
| 4106 | } | 4473 | } |
| 4474 | + pause_all_vcpus(); | ||
| 4107 | } | 4475 | } |
| 4108 | 4476 | ||
| 4109 | static void version(void) | 4477 | static void version(void) |