Commit d6dc3d424e26b49e1f37f1ef2598eacf3bc4eac7

Authored by aliguori
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 170 target_ulong mem_io_vaddr; /* target virtual addr at which the \
171 171 memory was accessed */ \
172 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 175 uint32_t interrupt_request; \
174 176 volatile sig_atomic_t exit_request; \
175 177 /* The meaning of the MMU modes is defined in the target code. */ \
... ... @@ -210,6 +212,9 @@ typedef struct CPUWatchpoint {
210 212 /* user data */ \
211 213 void *opaque; \
212 214 \
  215 + uint32_t created; \
  216 + struct QemuThread *thread; \
  217 + struct QemuCond *halt_cond; \
213 218 const char *cpu_model_str; \
214 219 struct KVMState *kvm_state; \
215 220 struct kvm_run *kvm_run; \
... ...
... ... @@ -1346,20 +1346,20 @@ static void host_alarm_handler(int host_signum)
1346 1346 qemu_get_clock(vm_clock))) ||
1347 1347 qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
1348 1348 qemu_get_clock(rt_clock))) {
1349   - CPUState *env = next_cpu;
1350   -
1351 1349 qemu_event_increment();
1352 1350 alarm_timer->flags |= ALARM_FLAG_EXPIRED;
1353 1351  
1354   - if (env) {
  1352 +#ifndef CONFIG_IOTHREAD
  1353 + if (next_cpu) {
1355 1354 /* stop the currently executing cpu because a timer occured */
1356   - cpu_exit(env);
  1355 + cpu_exit(next_cpu);
1357 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 1360 #endif
1362 1361 }
  1362 +#endif
1363 1363 timer_alarm_pending = 1;
1364 1364 qemu_notify_event();
1365 1365 }
... ... @@ -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 3543 void vm_start(void)
3541 3544 {
3542 3545 if (!vm_running) {
... ... @@ -3544,6 +3547,7 @@ void vm_start(void)
3544 3547 vm_running = 1;
3545 3548 vm_state_notify(1, 0);
3546 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 3606 if (vm_running) {
3603 3607 cpu_disable_ticks();
3604 3608 vm_running = 0;
  3609 + pause_all_vcpus();
3605 3610 vm_state_notify(0, reason);
3606 3611 }
3607 3612 }
... ... @@ -3654,18 +3659,13 @@ void qemu_system_powerdown_request(void)
3654 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 3670 #ifndef _WIN32
3671 3671 static int io_thread_fd = -1;
... ... @@ -3742,6 +3742,16 @@ static void qemu_event_increment(void)
3742 3742 }
3743 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 3755 static int qemu_init_main_loop(void)
3746 3756 {
3747 3757 return qemu_event_init();
... ... @@ -3761,11 +3771,32 @@ int qemu_cpu_self(void *env)
3761 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 3782 void qemu_cpu_kick(void *env)
3765 3783 {
3766 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 3800 #define qemu_mutex_lock_iothread() do { } while (0)
3770 3801 #define qemu_mutex_unlock_iothread() do { } while (0)
3771 3802  
... ... @@ -3774,6 +3805,321 @@ void vm_stop(int reason)
3774 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 4123 #ifdef _WIN32
3778 4124 static void host_main_loop_wait(int *timeout)
3779 4125 {
... ... @@ -3910,9 +4256,11 @@ void main_loop_wait(int timeout)
3910 4256 }
3911 4257  
3912 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 4265 /* real time timers */
3918 4266 qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
... ... @@ -3966,7 +4314,7 @@ static int qemu_cpu_exec(CPUState *env)
3966 4314  
3967 4315 static void tcg_cpu_exec(void)
3968 4316 {
3969   - int ret;
  4317 + int ret = 0;
3970 4318  
3971 4319 if (next_cpu == NULL)
3972 4320 next_cpu = first_cpu;
... ... @@ -3979,7 +4327,8 @@ static void tcg_cpu_exec(void)
3979 4327 timer_alarm_pending = 0;
3980 4328 break;
3981 4329 }
3982   - ret = qemu_cpu_exec(env);
  4330 + if (cpu_can_run(env))
  4331 + ret = qemu_cpu_exec(env);
3983 4332 if (ret == EXCP_DEBUG) {
3984 4333 gdb_set_stop_cpu(env);
3985 4334 debug_requested = 1;
... ... @@ -3990,6 +4339,10 @@ static void tcg_cpu_exec(void)
3990 4339  
3991 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 4346 if (!env->halted)
3994 4347 return 1;
3995 4348 if (qemu_cpu_has_work(env))
... ... @@ -4073,16 +4426,27 @@ static void main_loop(void)
4073 4426 {
4074 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 4434 for (;;) {
4077 4435 do {
4078 4436 #ifdef CONFIG_PROFILER
4079 4437 int64_t ti;
4080 4438 #endif
  4439 +#ifndef CONFIG_IOTHREAD
4081 4440 tcg_cpu_exec();
  4441 +#endif
4082 4442 #ifdef CONFIG_PROFILER
4083 4443 ti = profile_getclock();
4084 4444 #endif
  4445 +#ifdef CONFIG_IOTHREAD
  4446 + main_loop_wait(1000);
  4447 +#else
4085 4448 main_loop_wait(qemu_calculate_timeout());
  4449 +#endif
4086 4450 #ifdef CONFIG_PROFILER
4087 4451 dev_time += profile_getclock() - ti;
4088 4452 #endif
... ... @@ -4097,13 +4461,17 @@ static void main_loop(void)
4097 4461 } else
4098 4462 break;
4099 4463 }
4100   - if (qemu_reset_requested())
  4464 + if (qemu_reset_requested()) {
  4465 + pause_all_vcpus();
4101 4466 qemu_system_reset();
  4467 + resume_all_vcpus();
  4468 + }
4102 4469 if (qemu_powerdown_requested())
4103 4470 qemu_system_powerdown();
4104 4471 if ((r = qemu_vmstop_requested()))
4105 4472 vm_stop(r);
4106 4473 }
  4474 + pause_all_vcpus();
4107 4475 }
4108 4476  
4109 4477 static void version(void)
... ...