Commit 43b968580736ebd564a5d20b8a9a78b72c86fe57

Authored by aliguori
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
... ... @@ -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)
... ...