Commit 43b968580736ebd564a5d20b8a9a78b72c86fe57
1 parent
50317c7f
qemu: refactor main_loop (Marcelo Tosatti)
Break main loop into 3 main functions. 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@7241 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
151 additions
and
129 deletions
vl.c
... | ... | @@ -273,7 +273,7 @@ uint64_t node_cpumask[MAX_NODES]; |
273 | 273 | |
274 | 274 | static CPUState *cur_cpu; |
275 | 275 | static CPUState *next_cpu; |
276 | -static int event_pending = 1; | |
276 | +static int timer_alarm_pending = 1; | |
277 | 277 | /* Conversion factor from emulated instructions to virtual clock ticks. */ |
278 | 278 | static int icount_time_shift; |
279 | 279 | /* Arbitrarily pick 1MIPS as the minimum allowable speed. */ |
... | ... | @@ -1360,7 +1360,7 @@ static void host_alarm_handler(int host_signum) |
1360 | 1360 | } |
1361 | 1361 | #endif |
1362 | 1362 | } |
1363 | - event_pending = 1; | |
1363 | + timer_alarm_pending = 1; | |
1364 | 1364 | qemu_notify_event(); |
1365 | 1365 | } |
1366 | 1366 | } |
... | ... | @@ -3879,153 +3879,175 @@ void main_loop_wait(int timeout) |
3879 | 3879 | |
3880 | 3880 | } |
3881 | 3881 | |
3882 | -static int main_loop(void) | |
3882 | +static int qemu_cpu_exec(CPUState *env) | |
3883 | 3883 | { |
3884 | - int ret, timeout; | |
3884 | + int ret; | |
3885 | 3885 | #ifdef CONFIG_PROFILER |
3886 | 3886 | int64_t ti; |
3887 | 3887 | #endif |
3888 | - CPUState *env; | |
3889 | 3888 | |
3890 | - cur_cpu = first_cpu; | |
3891 | - next_cpu = cur_cpu->next_cpu ?: first_cpu; | |
3892 | - for(;;) { | |
3893 | - if (vm_running) { | |
3894 | - | |
3895 | - for(;;) { | |
3896 | - /* get next cpu */ | |
3897 | - env = next_cpu; | |
3898 | 3889 | #ifdef CONFIG_PROFILER |
3899 | - ti = profile_getclock(); | |
3890 | + ti = profile_getclock(); | |
3900 | 3891 | #endif |
3901 | - if (use_icount) { | |
3902 | - int64_t count; | |
3903 | - int decr; | |
3904 | - qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); | |
3905 | - env->icount_decr.u16.low = 0; | |
3906 | - env->icount_extra = 0; | |
3907 | - count = qemu_next_deadline(); | |
3908 | - count = (count + (1 << icount_time_shift) - 1) | |
3909 | - >> icount_time_shift; | |
3910 | - qemu_icount += count; | |
3911 | - decr = (count > 0xffff) ? 0xffff : count; | |
3912 | - count -= decr; | |
3913 | - env->icount_decr.u16.low = decr; | |
3914 | - env->icount_extra = count; | |
3915 | - } | |
3916 | - ret = cpu_exec(env); | |
3892 | + if (use_icount) { | |
3893 | + int64_t count; | |
3894 | + int decr; | |
3895 | + qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); | |
3896 | + env->icount_decr.u16.low = 0; | |
3897 | + env->icount_extra = 0; | |
3898 | + count = qemu_next_deadline(); | |
3899 | + count = (count + (1 << icount_time_shift) - 1) | |
3900 | + >> icount_time_shift; | |
3901 | + qemu_icount += count; | |
3902 | + decr = (count > 0xffff) ? 0xffff : count; | |
3903 | + count -= decr; | |
3904 | + env->icount_decr.u16.low = decr; | |
3905 | + env->icount_extra = count; | |
3906 | + } | |
3907 | + ret = cpu_exec(env); | |
3917 | 3908 | #ifdef CONFIG_PROFILER |
3918 | - qemu_time += profile_getclock() - ti; | |
3909 | + qemu_time += profile_getclock() - ti; | |
3919 | 3910 | #endif |
3920 | - if (use_icount) { | |
3921 | - /* Fold pending instructions back into the | |
3922 | - instruction counter, and clear the interrupt flag. */ | |
3923 | - qemu_icount -= (env->icount_decr.u16.low | |
3924 | - + env->icount_extra); | |
3925 | - env->icount_decr.u32 = 0; | |
3926 | - env->icount_extra = 0; | |
3927 | - } | |
3928 | - next_cpu = env->next_cpu ?: first_cpu; | |
3929 | - if (event_pending && likely(ret != EXCP_DEBUG)) { | |
3930 | - ret = EXCP_INTERRUPT; | |
3931 | - event_pending = 0; | |
3932 | - break; | |
3933 | - } | |
3934 | - if (ret == EXCP_HLT) { | |
3935 | - /* Give the next CPU a chance to run. */ | |
3936 | - cur_cpu = env; | |
3937 | - continue; | |
3938 | - } | |
3939 | - if (ret != EXCP_HALTED) | |
3911 | + if (use_icount) { | |
3912 | + /* Fold pending instructions back into the | |
3913 | + instruction counter, and clear the interrupt flag. */ | |
3914 | + qemu_icount -= (env->icount_decr.u16.low | |
3915 | + + env->icount_extra); | |
3916 | + env->icount_decr.u32 = 0; | |
3917 | + env->icount_extra = 0; | |
3918 | + } | |
3919 | + return ret; | |
3920 | +} | |
3921 | + | |
3922 | +static int cpu_has_work(CPUState *env) | |
3923 | +{ | |
3924 | + if (!env->halted) | |
3925 | + return 1; | |
3926 | + if (qemu_cpu_has_work(env)) | |
3927 | + return 1; | |
3928 | + return 0; | |
3929 | +} | |
3930 | + | |
3931 | +static int tcg_has_work(void) | |
3932 | +{ | |
3933 | + CPUState *env; | |
3934 | + | |
3935 | + for (env = first_cpu; env != NULL; env = env->next_cpu) | |
3936 | + if (cpu_has_work(env)) | |
3937 | + return 1; | |
3938 | + return 0; | |
3939 | +} | |
3940 | + | |
3941 | +static int qemu_calculate_timeout(void) | |
3942 | +{ | |
3943 | + int timeout; | |
3944 | + | |
3945 | + if (!vm_running) | |
3946 | + timeout = 5000; | |
3947 | + else if (tcg_has_work()) | |
3948 | + timeout = 0; | |
3949 | + else if (!use_icount) | |
3950 | + timeout = 5000; | |
3951 | + else { | |
3952 | + /* XXX: use timeout computed from timers */ | |
3953 | + int64_t add; | |
3954 | + int64_t delta; | |
3955 | + /* Advance virtual time to the next event. */ | |
3956 | + if (use_icount == 1) { | |
3957 | + /* When not using an adaptive execution frequency | |
3958 | + we tend to get badly out of sync with real time, | |
3959 | + so just delay for a reasonable amount of time. */ | |
3960 | + delta = 0; | |
3961 | + } else { | |
3962 | + delta = cpu_get_icount() - cpu_get_clock(); | |
3963 | + } | |
3964 | + if (delta > 0) { | |
3965 | + /* If virtual time is ahead of real time then just | |
3966 | + wait for IO. */ | |
3967 | + timeout = (delta / 1000000) + 1; | |
3968 | + } else { | |
3969 | + /* Wait for either IO to occur or the next | |
3970 | + timer event. */ | |
3971 | + add = qemu_next_deadline(); | |
3972 | + /* We advance the timer before checking for IO. | |
3973 | + Limit the amount we advance so that early IO | |
3974 | + activity won't get the guest too far ahead. */ | |
3975 | + if (add > 10000000) | |
3976 | + add = 10000000; | |
3977 | + delta += add; | |
3978 | + add = (add + (1 << icount_time_shift) - 1) | |
3979 | + >> icount_time_shift; | |
3980 | + qemu_icount += add; | |
3981 | + timeout = delta / 1000000; | |
3982 | + if (timeout < 0) | |
3983 | + timeout = 0; | |
3984 | + } | |
3985 | + } | |
3986 | + | |
3987 | + return timeout; | |
3988 | +} | |
3989 | + | |
3990 | +static int vm_can_run(void) | |
3991 | +{ | |
3992 | + if (powerdown_requested) | |
3993 | + return 0; | |
3994 | + if (reset_requested) | |
3995 | + return 0; | |
3996 | + if (shutdown_requested) | |
3997 | + return 0; | |
3998 | + return 1; | |
3999 | +} | |
4000 | + | |
4001 | +static void main_loop(void) | |
4002 | +{ | |
4003 | + int ret = 0; | |
4004 | +#ifdef CONFIG_PROFILER | |
4005 | + int64_t ti; | |
4006 | +#endif | |
4007 | + | |
4008 | + for (;;) { | |
4009 | + do { | |
4010 | + if (next_cpu == NULL) | |
4011 | + next_cpu = first_cpu; | |
4012 | + for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) { | |
4013 | + CPUState *env = cur_cpu = next_cpu; | |
4014 | + | |
4015 | + if (!vm_running) | |
3940 | 4016 | break; |
3941 | - /* all CPUs are halted ? */ | |
3942 | - if (env == cur_cpu) | |
4017 | + if (timer_alarm_pending) { | |
4018 | + timer_alarm_pending = 0; | |
3943 | 4019 | break; |
3944 | - } | |
3945 | - cur_cpu = env; | |
3946 | - | |
3947 | - if (shutdown_requested) { | |
3948 | - ret = EXCP_INTERRUPT; | |
3949 | - if (no_shutdown) { | |
3950 | - vm_stop(0); | |
3951 | - no_shutdown = 0; | |
3952 | 4020 | } |
3953 | - else | |
4021 | + ret = qemu_cpu_exec(env); | |
4022 | + if (ret == EXCP_DEBUG) { | |
4023 | + gdb_set_stop_cpu(env); | |
3954 | 4024 | break; |
3955 | - } | |
3956 | - if (reset_requested) { | |
3957 | - reset_requested = 0; | |
3958 | - qemu_system_reset(); | |
3959 | - ret = EXCP_INTERRUPT; | |
3960 | - } | |
3961 | - if (powerdown_requested) { | |
3962 | - powerdown_requested = 0; | |
3963 | - qemu_system_powerdown(); | |
3964 | - ret = EXCP_INTERRUPT; | |
3965 | - } | |
3966 | - if (unlikely(ret == EXCP_DEBUG)) { | |
3967 | - gdb_set_stop_cpu(cur_cpu); | |
3968 | - vm_stop(EXCP_DEBUG); | |
3969 | - } | |
3970 | - /* If all cpus are halted then wait until the next IRQ */ | |
3971 | - /* XXX: use timeout computed from timers */ | |
3972 | - if (ret == EXCP_HALTED) { | |
3973 | - if (use_icount) { | |
3974 | - int64_t add; | |
3975 | - int64_t delta; | |
3976 | - /* Advance virtual time to the next event. */ | |
3977 | - if (use_icount == 1) { | |
3978 | - /* When not using an adaptive execution frequency | |
3979 | - we tend to get badly out of sync with real time, | |
3980 | - so just delay for a reasonable amount of time. */ | |
3981 | - delta = 0; | |
3982 | - } else { | |
3983 | - delta = cpu_get_icount() - cpu_get_clock(); | |
3984 | - } | |
3985 | - if (delta > 0) { | |
3986 | - /* If virtual time is ahead of real time then just | |
3987 | - wait for IO. */ | |
3988 | - timeout = (delta / 1000000) + 1; | |
3989 | - } else { | |
3990 | - /* Wait for either IO to occur or the next | |
3991 | - timer event. */ | |
3992 | - add = qemu_next_deadline(); | |
3993 | - /* We advance the timer before checking for IO. | |
3994 | - Limit the amount we advance so that early IO | |
3995 | - activity won't get the guest too far ahead. */ | |
3996 | - if (add > 10000000) | |
3997 | - add = 10000000; | |
3998 | - delta += add; | |
3999 | - add = (add + (1 << icount_time_shift) - 1) | |
4000 | - >> icount_time_shift; | |
4001 | - qemu_icount += add; | |
4002 | - timeout = delta / 1000000; | |
4003 | - if (timeout < 0) | |
4004 | - timeout = 0; | |
4005 | - } | |
4006 | - } else { | |
4007 | - timeout = 5000; | |
4008 | 4025 | } |
4009 | - } else { | |
4010 | - timeout = 0; | |
4011 | 4026 | } |
4012 | - } else { | |
4013 | - if (shutdown_requested) { | |
4014 | - ret = EXCP_INTERRUPT; | |
4015 | - break; | |
4016 | - } | |
4017 | - timeout = 5000; | |
4018 | - } | |
4019 | 4027 | #ifdef CONFIG_PROFILER |
4020 | - ti = profile_getclock(); | |
4028 | + ti = profile_getclock(); | |
4021 | 4029 | #endif |
4022 | - main_loop_wait(timeout); | |
4030 | + main_loop_wait(qemu_calculate_timeout()); | |
4023 | 4031 | #ifdef CONFIG_PROFILER |
4024 | - dev_time += profile_getclock() - ti; | |
4032 | + dev_time += profile_getclock() - ti; | |
4025 | 4033 | #endif |
4034 | + } while (ret != EXCP_DEBUG && vm_can_run()); | |
4035 | + | |
4036 | + if (ret == EXCP_DEBUG) | |
4037 | + vm_stop(EXCP_DEBUG); | |
4038 | + | |
4039 | + if (qemu_shutdown_requested()) { | |
4040 | + if (no_shutdown) { | |
4041 | + vm_stop(0); | |
4042 | + no_shutdown = 0; | |
4043 | + } else | |
4044 | + break; | |
4045 | + } | |
4046 | + if (qemu_reset_requested()) | |
4047 | + qemu_system_reset(); | |
4048 | + if (qemu_powerdown_requested()) | |
4049 | + qemu_system_powerdown(); | |
4026 | 4050 | } |
4027 | - cpu_disable_ticks(); | |
4028 | - return ret; | |
4029 | 4051 | } |
4030 | 4052 | |
4031 | 4053 | static void version(void) | ... | ... |