提交 43b96858 编写于 作者: A aliguori

qemu: refactor main_loop (Marcelo Tosatti)

Break main loop into 3 main functions.
Signed-off-by: NMarcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: NAnthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7241 c046a42c-6fe2-441c-8c8c-71466251a162
上级 50317c7f
...@@ -273,7 +273,7 @@ uint64_t node_cpumask[MAX_NODES]; ...@@ -273,7 +273,7 @@ uint64_t node_cpumask[MAX_NODES];
static CPUState *cur_cpu; static CPUState *cur_cpu;
static CPUState *next_cpu; static CPUState *next_cpu;
static int event_pending = 1; static int timer_alarm_pending = 1;
/* Conversion factor from emulated instructions to virtual clock ticks. */ /* Conversion factor from emulated instructions to virtual clock ticks. */
static int icount_time_shift; static int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ /* Arbitrarily pick 1MIPS as the minimum allowable speed. */
...@@ -1360,7 +1360,7 @@ static void host_alarm_handler(int host_signum) ...@@ -1360,7 +1360,7 @@ static void host_alarm_handler(int host_signum)
} }
#endif #endif
} }
event_pending = 1; timer_alarm_pending = 1;
qemu_notify_event(); qemu_notify_event();
} }
} }
...@@ -3879,153 +3879,175 @@ void main_loop_wait(int timeout) ...@@ -3879,153 +3879,175 @@ void main_loop_wait(int timeout)
} }
static int main_loop(void) static int qemu_cpu_exec(CPUState *env)
{ {
int ret, timeout; int ret;
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
int64_t ti; int64_t ti;
#endif #endif
CPUState *env;
cur_cpu = first_cpu;
next_cpu = cur_cpu->next_cpu ?: first_cpu;
for(;;) {
if (vm_running) {
for(;;) {
/* get next cpu */
env = next_cpu;
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
ti = profile_getclock(); ti = profile_getclock();
#endif #endif
if (use_icount) { if (use_icount) {
int64_t count; int64_t count;
int decr; int decr;
qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
env->icount_decr.u16.low = 0; env->icount_decr.u16.low = 0;
env->icount_extra = 0; env->icount_extra = 0;
count = qemu_next_deadline(); count = qemu_next_deadline();
count = (count + (1 << icount_time_shift) - 1) count = (count + (1 << icount_time_shift) - 1)
>> icount_time_shift; >> icount_time_shift;
qemu_icount += count; qemu_icount += count;
decr = (count > 0xffff) ? 0xffff : count; decr = (count > 0xffff) ? 0xffff : count;
count -= decr; count -= decr;
env->icount_decr.u16.low = decr; env->icount_decr.u16.low = decr;
env->icount_extra = count; env->icount_extra = count;
} }
ret = cpu_exec(env); ret = cpu_exec(env);
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
qemu_time += profile_getclock() - ti; qemu_time += profile_getclock() - ti;
#endif #endif
if (use_icount) { if (use_icount) {
/* Fold pending instructions back into the /* Fold pending instructions back into the
instruction counter, and clear the interrupt flag. */ instruction counter, and clear the interrupt flag. */
qemu_icount -= (env->icount_decr.u16.low qemu_icount -= (env->icount_decr.u16.low
+ env->icount_extra); + env->icount_extra);
env->icount_decr.u32 = 0; env->icount_decr.u32 = 0;
env->icount_extra = 0; env->icount_extra = 0;
} }
next_cpu = env->next_cpu ?: first_cpu; return ret;
if (event_pending && likely(ret != EXCP_DEBUG)) { }
ret = EXCP_INTERRUPT;
event_pending = 0; static int cpu_has_work(CPUState *env)
break; {
} if (!env->halted)
if (ret == EXCP_HLT) { return 1;
/* Give the next CPU a chance to run. */ if (qemu_cpu_has_work(env))
cur_cpu = env; return 1;
continue; return 0;
} }
if (ret != EXCP_HALTED)
static int tcg_has_work(void)
{
CPUState *env;
for (env = first_cpu; env != NULL; env = env->next_cpu)
if (cpu_has_work(env))
return 1;
return 0;
}
static int qemu_calculate_timeout(void)
{
int timeout;
if (!vm_running)
timeout = 5000;
else if (tcg_has_work())
timeout = 0;
else if (!use_icount)
timeout = 5000;
else {
/* XXX: use timeout computed from timers */
int64_t add;
int64_t delta;
/* Advance virtual time to the next event. */
if (use_icount == 1) {
/* When not using an adaptive execution frequency
we tend to get badly out of sync with real time,
so just delay for a reasonable amount of time. */
delta = 0;
} else {
delta = cpu_get_icount() - cpu_get_clock();
}
if (delta > 0) {
/* If virtual time is ahead of real time then just
wait for IO. */
timeout = (delta / 1000000) + 1;
} else {
/* Wait for either IO to occur or the next
timer event. */
add = qemu_next_deadline();
/* We advance the timer before checking for IO.
Limit the amount we advance so that early IO
activity won't get the guest too far ahead. */
if (add > 10000000)
add = 10000000;
delta += add;
add = (add + (1 << icount_time_shift) - 1)
>> icount_time_shift;
qemu_icount += add;
timeout = delta / 1000000;
if (timeout < 0)
timeout = 0;
}
}
return timeout;
}
static int vm_can_run(void)
{
if (powerdown_requested)
return 0;
if (reset_requested)
return 0;
if (shutdown_requested)
return 0;
return 1;
}
static void main_loop(void)
{
int ret = 0;
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
for (;;) {
do {
if (next_cpu == NULL)
next_cpu = first_cpu;
for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
CPUState *env = cur_cpu = next_cpu;
if (!vm_running)
break; break;
/* all CPUs are halted ? */ if (timer_alarm_pending) {
if (env == cur_cpu) timer_alarm_pending = 0;
break; break;
}
cur_cpu = env;
if (shutdown_requested) {
ret = EXCP_INTERRUPT;
if (no_shutdown) {
vm_stop(0);
no_shutdown = 0;
} }
else ret = qemu_cpu_exec(env);
if (ret == EXCP_DEBUG) {
gdb_set_stop_cpu(env);
break; break;
}
if (reset_requested) {
reset_requested = 0;
qemu_system_reset();
ret = EXCP_INTERRUPT;
}
if (powerdown_requested) {
powerdown_requested = 0;
qemu_system_powerdown();
ret = EXCP_INTERRUPT;
}
if (unlikely(ret == EXCP_DEBUG)) {
gdb_set_stop_cpu(cur_cpu);
vm_stop(EXCP_DEBUG);
}
/* If all cpus are halted then wait until the next IRQ */
/* XXX: use timeout computed from timers */
if (ret == EXCP_HALTED) {
if (use_icount) {
int64_t add;
int64_t delta;
/* Advance virtual time to the next event. */
if (use_icount == 1) {
/* When not using an adaptive execution frequency
we tend to get badly out of sync with real time,
so just delay for a reasonable amount of time. */
delta = 0;
} else {
delta = cpu_get_icount() - cpu_get_clock();
}
if (delta > 0) {
/* If virtual time is ahead of real time then just
wait for IO. */
timeout = (delta / 1000000) + 1;
} else {
/* Wait for either IO to occur or the next
timer event. */
add = qemu_next_deadline();
/* We advance the timer before checking for IO.
Limit the amount we advance so that early IO
activity won't get the guest too far ahead. */
if (add > 10000000)
add = 10000000;
delta += add;
add = (add + (1 << icount_time_shift) - 1)
>> icount_time_shift;
qemu_icount += add;
timeout = delta / 1000000;
if (timeout < 0)
timeout = 0;
}
} else {
timeout = 5000;
} }
} else {
timeout = 0;
} }
} else {
if (shutdown_requested) {
ret = EXCP_INTERRUPT;
break;
}
timeout = 5000;
}
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
ti = profile_getclock(); ti = profile_getclock();
#endif #endif
main_loop_wait(timeout); main_loop_wait(qemu_calculate_timeout());
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
dev_time += profile_getclock() - ti; dev_time += profile_getclock() - ti;
#endif #endif
} while (ret != EXCP_DEBUG && vm_can_run());
if (ret == EXCP_DEBUG)
vm_stop(EXCP_DEBUG);
if (qemu_shutdown_requested()) {
if (no_shutdown) {
vm_stop(0);
no_shutdown = 0;
} else
break;
}
if (qemu_reset_requested())
qemu_system_reset();
if (qemu_powerdown_requested())
qemu_system_powerdown();
} }
cpu_disable_ticks();
return ret;
} }
static void version(void) static void version(void)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册