Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
qemu
提交
952e849c
Q
qemu
项目概览
openeuler
/
qemu
通知
10
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Q
qemu
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
952e849c
编写于
10月 24, 2011
作者:
A
Anthony Liguori
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'bonzini/split-main-loop-for-anthony' into staging
上级
db418a0a
99435906
变更
23
展开全部
隐藏空白更改
内联
并排
Showing
23 changed file
with
1309 addition
and
1060 deletion
+1309
-1060
Makefile.objs
Makefile.objs
+1
-1
async.c
async.c
+1
-0
cpus.c
cpus.c
+280
-217
cpus.h
cpus.h
+1
-2
exec-all.h
exec-all.h
+14
-0
exec.c
exec.c
+0
-3
hw/mac_dbdma.c
hw/mac_dbdma.c
+0
-5
hw/mac_dbdma.h
hw/mac_dbdma.h
+0
-1
iohandler.c
iohandler.c
+2
-53
main-loop.c
main-loop.c
+495
-0
main-loop.h
main-loop.h
+351
-0
os-win32.c
os-win32.c
+0
-123
qemu-char.h
qemu-char.h
+1
-11
qemu-common.h
qemu-common.h
+4
-33
qemu-coroutine-lock.c
qemu-coroutine-lock.c
+1
-0
qemu-os-posix.h
qemu-os-posix.h
+0
-4
qemu-os-win32.h
qemu-os-win32.h
+1
-16
qemu-timer.c
qemu-timer.c
+88
-401
qemu-timer.h
qemu-timer.h
+7
-24
savevm.c
savevm.c
+25
-0
slirp/libslirp.h
slirp/libslirp.h
+0
-11
sysemu.h
sysemu.h
+1
-2
vl.c
vl.c
+36
-153
未找到文件。
Makefile.objs
浏览文件 @
952e849c
...
...
@@ -81,7 +81,7 @@ common-obj-y += $(oslib-obj-y)
common-obj-$(CONFIG_WIN32)
+=
os-win32.o
common-obj-$(CONFIG_POSIX)
+=
os-posix.o
common-obj-y
+=
tcg-runtime.o host-utils.o
common-obj-y
+=
tcg-runtime.o host-utils.o
main-loop.o
common-obj-y
+=
irq.o input.o
common-obj-$(CONFIG_PTIMER)
+=
ptimer.o
common-obj-$(CONFIG_MAX7310)
+=
max7310.o
...
...
async.c
浏览文件 @
952e849c
...
...
@@ -24,6 +24,7 @@
#include "qemu-common.h"
#include "qemu-aio.h"
#include "main-loop.h"
/* Anchor of the list of Bottom Halves belonging to the context */
static
struct
QEMUBH
*
first_bh
;
...
...
cpus.c
浏览文件 @
952e849c
...
...
@@ -33,17 +33,12 @@
#include "qemu-thread.h"
#include "cpus.h"
#include "main-loop.h"
#ifndef _WIN32
#include "compatfd.h"
#endif
#ifdef SIGRTMIN
#define SIG_IPI (SIGRTMIN+4)
#else
#define SIG_IPI SIGUSR1
#endif
#ifdef CONFIG_LINUX
#include <sys/prctl.h>
...
...
@@ -64,6 +59,281 @@
static
CPUState
*
next_cpu
;
/***********************************************************/
/* guest cycle counter */
/* Conversion factor from emulated instructions to virtual clock ticks. */
static
int
icount_time_shift
;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
#define MAX_ICOUNT_SHIFT 10
/* Compensate for varying guest execution speed. */
static
int64_t
qemu_icount_bias
;
static
QEMUTimer
*
icount_rt_timer
;
static
QEMUTimer
*
icount_vm_timer
;
static
QEMUTimer
*
icount_warp_timer
;
static
int64_t
vm_clock_warp_start
;
static
int64_t
qemu_icount
;
typedef
struct
TimersState
{
int64_t
cpu_ticks_prev
;
int64_t
cpu_ticks_offset
;
int64_t
cpu_clock_offset
;
int32_t
cpu_ticks_enabled
;
int64_t
dummy
;
}
TimersState
;
TimersState
timers_state
;
/* Return the virtual CPU time, based on the instruction counter. */
int64_t
cpu_get_icount
(
void
)
{
int64_t
icount
;
CPUState
*
env
=
cpu_single_env
;;
icount
=
qemu_icount
;
if
(
env
)
{
if
(
!
can_do_io
(
env
))
{
fprintf
(
stderr
,
"Bad clock read
\n
"
);
}
icount
-=
(
env
->
icount_decr
.
u16
.
low
+
env
->
icount_extra
);
}
return
qemu_icount_bias
+
(
icount
<<
icount_time_shift
);
}
/* return the host CPU cycle counter and handle stop/restart */
int64_t
cpu_get_ticks
(
void
)
{
if
(
use_icount
)
{
return
cpu_get_icount
();
}
if
(
!
timers_state
.
cpu_ticks_enabled
)
{
return
timers_state
.
cpu_ticks_offset
;
}
else
{
int64_t
ticks
;
ticks
=
cpu_get_real_ticks
();
if
(
timers_state
.
cpu_ticks_prev
>
ticks
)
{
/* Note: non increasing ticks may happen if the host uses
software suspend */
timers_state
.
cpu_ticks_offset
+=
timers_state
.
cpu_ticks_prev
-
ticks
;
}
timers_state
.
cpu_ticks_prev
=
ticks
;
return
ticks
+
timers_state
.
cpu_ticks_offset
;
}
}
/* return the host CPU monotonic timer and handle stop/restart */
int64_t
cpu_get_clock
(
void
)
{
int64_t
ti
;
if
(
!
timers_state
.
cpu_ticks_enabled
)
{
return
timers_state
.
cpu_clock_offset
;
}
else
{
ti
=
get_clock
();
return
ti
+
timers_state
.
cpu_clock_offset
;
}
}
/* enable cpu_get_ticks() */
void
cpu_enable_ticks
(
void
)
{
if
(
!
timers_state
.
cpu_ticks_enabled
)
{
timers_state
.
cpu_ticks_offset
-=
cpu_get_real_ticks
();
timers_state
.
cpu_clock_offset
-=
get_clock
();
timers_state
.
cpu_ticks_enabled
=
1
;
}
}
/* disable cpu_get_ticks() : the clock is stopped. You must not call
cpu_get_ticks() after that. */
void
cpu_disable_ticks
(
void
)
{
if
(
timers_state
.
cpu_ticks_enabled
)
{
timers_state
.
cpu_ticks_offset
=
cpu_get_ticks
();
timers_state
.
cpu_clock_offset
=
cpu_get_clock
();
timers_state
.
cpu_ticks_enabled
=
0
;
}
}
/* Correlation between real and virtual time is always going to be
fairly approximate, so ignore small variation.
When the guest is idle real and virtual time will be aligned in
the IO wait loop. */
#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10)
static
void
icount_adjust
(
void
)
{
int64_t
cur_time
;
int64_t
cur_icount
;
int64_t
delta
;
static
int64_t
last_delta
;
/* If the VM is not running, then do nothing. */
if
(
!
runstate_is_running
())
{
return
;
}
cur_time
=
cpu_get_clock
();
cur_icount
=
qemu_get_clock_ns
(
vm_clock
);
delta
=
cur_icount
-
cur_time
;
/* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
if
(
delta
>
0
&&
last_delta
+
ICOUNT_WOBBLE
<
delta
*
2
&&
icount_time_shift
>
0
)
{
/* The guest is getting too far ahead. Slow time down. */
icount_time_shift
--
;
}
if
(
delta
<
0
&&
last_delta
-
ICOUNT_WOBBLE
>
delta
*
2
&&
icount_time_shift
<
MAX_ICOUNT_SHIFT
)
{
/* The guest is getting too far behind. Speed time up. */
icount_time_shift
++
;
}
last_delta
=
delta
;
qemu_icount_bias
=
cur_icount
-
(
qemu_icount
<<
icount_time_shift
);
}
static
void
icount_adjust_rt
(
void
*
opaque
)
{
qemu_mod_timer
(
icount_rt_timer
,
qemu_get_clock_ms
(
rt_clock
)
+
1000
);
icount_adjust
();
}
static
void
icount_adjust_vm
(
void
*
opaque
)
{
qemu_mod_timer
(
icount_vm_timer
,
qemu_get_clock_ns
(
vm_clock
)
+
get_ticks_per_sec
()
/
10
);
icount_adjust
();
}
static
int64_t
qemu_icount_round
(
int64_t
count
)
{
return
(
count
+
(
1
<<
icount_time_shift
)
-
1
)
>>
icount_time_shift
;
}
static
void
icount_warp_rt
(
void
*
opaque
)
{
if
(
vm_clock_warp_start
==
-
1
)
{
return
;
}
if
(
runstate_is_running
())
{
int64_t
clock
=
qemu_get_clock_ns
(
rt_clock
);
int64_t
warp_delta
=
clock
-
vm_clock_warp_start
;
if
(
use_icount
==
1
)
{
qemu_icount_bias
+=
warp_delta
;
}
else
{
/*
* In adaptive mode, do not let the vm_clock run too
* far ahead of real time.
*/
int64_t
cur_time
=
cpu_get_clock
();
int64_t
cur_icount
=
qemu_get_clock_ns
(
vm_clock
);
int64_t
delta
=
cur_time
-
cur_icount
;
qemu_icount_bias
+=
MIN
(
warp_delta
,
delta
);
}
if
(
qemu_clock_expired
(
vm_clock
))
{
qemu_notify_event
();
}
}
vm_clock_warp_start
=
-
1
;
}
void
qemu_clock_warp
(
QEMUClock
*
clock
)
{
int64_t
deadline
;
/*
* There are too many global variables to make the "warp" behavior
* applicable to other clocks. But a clock argument removes the
* need for if statements all over the place.
*/
if
(
clock
!=
vm_clock
||
!
use_icount
)
{
return
;
}
/*
* If the CPUs have been sleeping, advance the vm_clock timer now. This
* ensures that the deadline for the timer is computed correctly below.
* This also makes sure that the insn counter is synchronized before the
* CPU starts running, in case the CPU is woken by an event other than
* the earliest vm_clock timer.
*/
icount_warp_rt
(
NULL
);
if
(
!
all_cpu_threads_idle
()
||
!
qemu_clock_has_timers
(
vm_clock
))
{
qemu_del_timer
(
icount_warp_timer
);
return
;
}
vm_clock_warp_start
=
qemu_get_clock_ns
(
rt_clock
);
deadline
=
qemu_clock_deadline
(
vm_clock
);
if
(
deadline
>
0
)
{
/*
* Ensure the vm_clock proceeds even when the virtual CPU goes to
* sleep. Otherwise, the CPU might be waiting for a future timer
* interrupt to wake it up, but the interrupt never comes because
* the vCPU isn't running any insns and thus doesn't advance the
* vm_clock.
*
* An extreme solution for this problem would be to never let VCPUs
* sleep in icount mode if there is a pending vm_clock timer; rather
* time could just advance to the next vm_clock event. Instead, we
* do stop VCPUs and only advance vm_clock after some "real" time,
* (related to the time left until the next event) has passed. This
* rt_clock timer will do this. This avoids that the warps are too
* visible externally---for example, you will not be sending network
* packets continously instead of every 100ms.
*/
qemu_mod_timer
(
icount_warp_timer
,
vm_clock_warp_start
+
deadline
);
}
else
{
qemu_notify_event
();
}
}
static
const
VMStateDescription
vmstate_timers
=
{
.
name
=
"timer"
,
.
version_id
=
2
,
.
minimum_version_id
=
1
,
.
minimum_version_id_old
=
1
,
.
fields
=
(
VMStateField
[])
{
VMSTATE_INT64
(
cpu_ticks_offset
,
TimersState
),
VMSTATE_INT64
(
dummy
,
TimersState
),
VMSTATE_INT64_V
(
cpu_clock_offset
,
TimersState
,
2
),
VMSTATE_END_OF_LIST
()
}
};
void
configure_icount
(
const
char
*
option
)
{
vmstate_register
(
NULL
,
0
,
&
vmstate_timers
,
&
timers_state
);
if
(
!
option
)
{
return
;
}
icount_warp_timer
=
qemu_new_timer_ns
(
rt_clock
,
icount_warp_rt
,
NULL
);
if
(
strcmp
(
option
,
"auto"
)
!=
0
)
{
icount_time_shift
=
strtol
(
option
,
NULL
,
0
);
use_icount
=
1
;
return
;
}
use_icount
=
2
;
/* 125MIPS seems a reasonable initial guess at the guest speed.
It will be corrected fairly quickly anyway. */
icount_time_shift
=
3
;
/* Have both realtime and virtual time triggers for speed adjustment.
The realtime trigger catches emulated time passing too slowly,
the virtual time trigger catches emulated time passing too fast.
Realtime triggers occur even when idle, so use them less frequently
than VM triggers. */
icount_rt_timer
=
qemu_new_timer_ms
(
rt_clock
,
icount_adjust_rt
,
NULL
);
qemu_mod_timer
(
icount_rt_timer
,
qemu_get_clock_ms
(
rt_clock
)
+
1000
);
icount_vm_timer
=
qemu_new_timer_ns
(
vm_clock
,
icount_adjust_vm
,
NULL
);
qemu_mod_timer
(
icount_vm_timer
,
qemu_get_clock_ns
(
vm_clock
)
+
get_ticks_per_sec
()
/
10
);
}
/***********************************************************/
void
hw_error
(
const
char
*
fmt
,
...)
{
...
...
@@ -272,143 +542,10 @@ static void qemu_kvm_eat_signals(CPUState *env)
#endif
/* !CONFIG_LINUX */
#ifndef _WIN32
static
int
io_thread_fd
=
-
1
;
static
void
qemu_event_increment
(
void
)
{
/* Write 8 bytes to be compatible with eventfd. */
static
const
uint64_t
val
=
1
;
ssize_t
ret
;
if
(
io_thread_fd
==
-
1
)
{
return
;
}
do
{
ret
=
write
(
io_thread_fd
,
&
val
,
sizeof
(
val
));
}
while
(
ret
<
0
&&
errno
==
EINTR
);
/* EAGAIN is fine, a read must be pending. */
if
(
ret
<
0
&&
errno
!=
EAGAIN
)
{
fprintf
(
stderr
,
"qemu_event_increment: write() failed: %s
\n
"
,
strerror
(
errno
));
exit
(
1
);
}
}
static
void
qemu_event_read
(
void
*
opaque
)
{
int
fd
=
(
intptr_t
)
opaque
;
ssize_t
len
;
char
buffer
[
512
];
/* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
do
{
len
=
read
(
fd
,
buffer
,
sizeof
(
buffer
));
}
while
((
len
==
-
1
&&
errno
==
EINTR
)
||
len
==
sizeof
(
buffer
));
}
static
int
qemu_event_init
(
void
)
{
int
err
;
int
fds
[
2
];
err
=
qemu_eventfd
(
fds
);
if
(
err
==
-
1
)
{
return
-
errno
;
}
err
=
fcntl_setfl
(
fds
[
0
],
O_NONBLOCK
);
if
(
err
<
0
)
{
goto
fail
;
}
err
=
fcntl_setfl
(
fds
[
1
],
O_NONBLOCK
);
if
(
err
<
0
)
{
goto
fail
;
}
qemu_set_fd_handler2
(
fds
[
0
],
NULL
,
qemu_event_read
,
NULL
,
(
void
*
)(
intptr_t
)
fds
[
0
]);
io_thread_fd
=
fds
[
1
];
return
0
;
fail:
close
(
fds
[
0
]);
close
(
fds
[
1
]);
return
err
;
}
static
void
dummy_signal
(
int
sig
)
{
}
/* If we have signalfd, we mask out the signals we want to handle and then
* use signalfd to listen for them. We rely on whatever the current signal
* handler is to dispatch the signals when we receive them.
*/
static
void
sigfd_handler
(
void
*
opaque
)
{
int
fd
=
(
intptr_t
)
opaque
;
struct
qemu_signalfd_siginfo
info
;
struct
sigaction
action
;
ssize_t
len
;
while
(
1
)
{
do
{
len
=
read
(
fd
,
&
info
,
sizeof
(
info
));
}
while
(
len
==
-
1
&&
errno
==
EINTR
);
if
(
len
==
-
1
&&
errno
==
EAGAIN
)
{
break
;
}
if
(
len
!=
sizeof
(
info
))
{
printf
(
"read from sigfd returned %zd: %m
\n
"
,
len
);
return
;
}
sigaction
(
info
.
ssi_signo
,
NULL
,
&
action
);
if
((
action
.
sa_flags
&
SA_SIGINFO
)
&&
action
.
sa_sigaction
)
{
action
.
sa_sigaction
(
info
.
ssi_signo
,
(
siginfo_t
*
)
&
info
,
NULL
);
}
else
if
(
action
.
sa_handler
)
{
action
.
sa_handler
(
info
.
ssi_signo
);
}
}
}
static
int
qemu_signal_init
(
void
)
{
int
sigfd
;
sigset_t
set
;
/*
* SIG_IPI must be blocked in the main thread and must not be caught
* by sigwait() in the signal thread. Otherwise, the cpu thread will
* not catch it reliably.
*/
sigemptyset
(
&
set
);
sigaddset
(
&
set
,
SIG_IPI
);
pthread_sigmask
(
SIG_BLOCK
,
&
set
,
NULL
);
sigemptyset
(
&
set
);
sigaddset
(
&
set
,
SIGIO
);
sigaddset
(
&
set
,
SIGALRM
);
sigaddset
(
&
set
,
SIGBUS
);
pthread_sigmask
(
SIG_BLOCK
,
&
set
,
NULL
);
sigfd
=
qemu_signalfd
(
&
set
);
if
(
sigfd
==
-
1
)
{
fprintf
(
stderr
,
"failed to create signalfd
\n
"
);
return
-
errno
;
}
fcntl_setfl
(
sigfd
,
O_NONBLOCK
);
qemu_set_fd_handler2
(
sigfd
,
NULL
,
sigfd_handler
,
NULL
,
(
void
*
)(
intptr_t
)
sigfd
);
return
0
;
}
static
void
qemu_kvm_init_cpu_signals
(
CPUState
*
env
)
{
int
r
;
...
...
@@ -452,38 +589,6 @@ static void qemu_tcg_init_cpu_signals(void)
}
#else
/* _WIN32 */
HANDLE
qemu_event_handle
;
static
void
dummy_event_handler
(
void
*
opaque
)
{
}
static
int
qemu_event_init
(
void
)
{
qemu_event_handle
=
CreateEvent
(
NULL
,
FALSE
,
FALSE
,
NULL
);
if
(
!
qemu_event_handle
)
{
fprintf
(
stderr
,
"Failed CreateEvent: %ld
\n
"
,
GetLastError
());
return
-
1
;
}
qemu_add_wait_object
(
qemu_event_handle
,
dummy_event_handler
,
NULL
);
return
0
;
}
static
void
qemu_event_increment
(
void
)
{
if
(
!
SetEvent
(
qemu_event_handle
))
{
fprintf
(
stderr
,
"qemu_event_increment: SetEvent failed: %ld
\n
"
,
GetLastError
());
exit
(
1
);
}
}
static
int
qemu_signal_init
(
void
)
{
return
0
;
}
static
void
qemu_kvm_init_cpu_signals
(
CPUState
*
env
)
{
abort
();
...
...
@@ -509,38 +614,16 @@ static QemuCond qemu_cpu_cond;
static
QemuCond
qemu_pause_cond
;
static
QemuCond
qemu_work_cond
;
int
qemu_init_main
_loop
(
void
)
void
qemu_init_cpu
_loop
(
void
)
{
int
ret
;
qemu_init_sigbus
();
ret
=
qemu_signal_init
();
if
(
ret
)
{
return
ret
;
}
/* Note eventfd must be drained before signalfd handlers run */
ret
=
qemu_event_init
();
if
(
ret
)
{
return
ret
;
}
qemu_cond_init
(
&
qemu_cpu_cond
);
qemu_cond_init
(
&
qemu_pause_cond
);
qemu_cond_init
(
&
qemu_work_cond
);
qemu_cond_init
(
&
qemu_io_proceeded_cond
);
qemu_mutex_init
(
&
qemu_global_mutex
);
qemu_mutex_lock
(
&
qemu_global_mutex
);
qemu_thread_get_self
(
&
io_thread
);
return
0
;
}
void
qemu_main_loop_start
(
void
)
{
resume_all_vcpus
();
}
void
run_on_cpu
(
CPUState
*
env
,
void
(
*
func
)(
void
*
data
),
void
*
data
)
...
...
@@ -686,7 +769,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
while
(
1
)
{
cpu_exec_all
();
if
(
use_icount
&&
qemu_
next_icount_deadline
(
)
<=
0
)
{
if
(
use_icount
&&
qemu_
clock_deadline
(
vm_clock
)
<=
0
)
{
qemu_notify_event
();
}
qemu_tcg_wait_io_event
();
...
...
@@ -784,6 +867,7 @@ void pause_all_vcpus(void)
{
CPUState
*
penv
=
first_cpu
;
qemu_clock_enable
(
vm_clock
,
false
);
while
(
penv
)
{
penv
->
stop
=
1
;
qemu_cpu_kick
(
penv
);
...
...
@@ -858,11 +942,6 @@ void qemu_init_vcpu(void *_env)
}
}
void
qemu_notify_event
(
void
)
{
qemu_event_increment
();
}
void
cpu_stop_current
(
void
)
{
if
(
cpu_single_env
)
{
...
...
@@ -914,7 +993,7 @@ static int tcg_cpu_exec(CPUState *env)
qemu_icount
-=
(
env
->
icount_decr
.
u16
.
low
+
env
->
icount_extra
);
env
->
icount_decr
.
u16
.
low
=
0
;
env
->
icount_extra
=
0
;
count
=
qemu_icount_round
(
qemu_
next_icount_deadline
(
));
count
=
qemu_icount_round
(
qemu_
clock_deadline
(
vm_clock
));
qemu_icount
+=
count
;
decr
=
(
count
>
0xffff
)
?
0xffff
:
count
;
count
-=
decr
;
...
...
@@ -1006,22 +1085,6 @@ void set_cpu_log_filename(const char *optarg)
cpu_set_log_filename
(
optarg
);
}
/* Return the virtual CPU time, based on the instruction counter. */
int64_t
cpu_get_icount
(
void
)
{
int64_t
icount
;
CPUState
*
env
=
cpu_single_env
;;
icount
=
qemu_icount
;
if
(
env
)
{
if
(
!
can_do_io
(
env
))
{
fprintf
(
stderr
,
"Bad clock read
\n
"
);
}
icount
-=
(
env
->
icount_decr
.
u16
.
low
+
env
->
icount_extra
);
}
return
qemu_icount_bias
+
(
icount
<<
icount_time_shift
);
}
void
list_cpus
(
FILE
*
f
,
fprintf_function
cpu_fprintf
,
const
char
*
optarg
)
{
/* XXX: implement xxx_cpu_list for targets that still miss it */
...
...
cpus.h
浏览文件 @
952e849c
...
...
@@ -2,8 +2,7 @@
#define QEMU_CPUS_H
/* cpus.c */
int
qemu_init_main_loop
(
void
);
void
qemu_main_loop_start
(
void
);
void
qemu_init_cpu_loop
(
void
);
void
resume_all_vcpus
(
void
);
void
pause_all_vcpus
(
void
);
void
cpu_stop_current
(
void
);
...
...
exec-all.h
浏览文件 @
952e849c
...
...
@@ -356,4 +356,18 @@ extern int singlestep;
/* cpu-exec.c */
extern
volatile
sig_atomic_t
exit_request
;
/* Deterministic execution requires that IO only be performed on the last
instruction of a TB so that interrupts take effect immediately. */
static
inline
int
can_do_io
(
CPUState
*
env
)
{
if
(
!
use_icount
)
{
return
1
;
}
/* If not executing code then assume we are ok. */
if
(
!
env
->
current_tb
)
{
return
1
;
}
return
env
->
can_do_io
!=
0
;
}
#endif
exec.c
浏览文件 @
952e849c
...
...
@@ -125,9 +125,6 @@ CPUState *cpu_single_env;
1 = Precise instruction counting.
2 = Adaptive rate instruction counting. */
int
use_icount
=
0
;
/* Current instruction counter. While executing translated code this may
include some instructions that have not yet been executed. */
int64_t
qemu_icount
;
typedef
struct
PageDesc
{
/* list of TBs intersecting this ram page */
...
...
hw/mac_dbdma.c
浏览文件 @
952e849c
...
...
@@ -661,11 +661,6 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
ch
->
io
.
channel
=
ch
;
}
void
DBDMA_schedule
(
void
)
{
qemu_notify_event
();
}
static
void
dbdma_control_write
(
DBDMA_channel
*
ch
)
{
...
...
hw/mac_dbdma.h
浏览文件 @
952e849c
...
...
@@ -41,5 +41,4 @@ struct DBDMA_io {
void
DBDMA_register_channel
(
void
*
dbdma
,
int
nchan
,
qemu_irq
irq
,
DBDMA_rw
rw
,
DBDMA_flush
flush
,
void
*
opaque
);
void
DBDMA_schedule
(
void
);
void
*
DBDMA_init
(
MemoryRegion
**
dbdma_mem
);
iohandler.c
浏览文件 @
952e849c
...
...
@@ -26,6 +26,7 @@
#include "qemu-common.h"
#include "qemu-char.h"
#include "qemu-queue.h"
#include "main-loop.h"
#ifndef _WIN32
#include <sys/wait.h>
...
...
@@ -80,64 +81,12 @@ int qemu_set_fd_handler2(int fd,
return
0
;
}
typedef
struct
IOTrampoline
{
GIOChannel
*
chan
;
IOHandler
*
fd_read
;
IOHandler
*
fd_write
;
void
*
opaque
;
guint
tag
;
}
IOTrampoline
;
static
gboolean
fd_trampoline
(
GIOChannel
*
chan
,
GIOCondition
cond
,
gpointer
opaque
)
{
IOTrampoline
*
tramp
=
opaque
;
if
((
cond
&
G_IO_IN
)
&&
tramp
->
fd_read
)
{
tramp
->
fd_read
(
tramp
->
opaque
);
}
if
((
cond
&
G_IO_OUT
)
&&
tramp
->
fd_write
)
{
tramp
->
fd_write
(
tramp
->
opaque
);
}
return
TRUE
;
}
int
qemu_set_fd_handler
(
int
fd
,
IOHandler
*
fd_read
,
IOHandler
*
fd_write
,
void
*
opaque
)
{
static
IOTrampoline
fd_trampolines
[
FD_SETSIZE
];
IOTrampoline
*
tramp
=
&
fd_trampolines
[
fd
];
if
(
tramp
->
tag
!=
0
)
{
g_io_channel_unref
(
tramp
->
chan
);
g_source_remove
(
tramp
->
tag
);
tramp
->
tag
=
0
;
}
if
(
fd_read
||
fd_write
||
opaque
)
{
GIOCondition
cond
=
0
;
tramp
->
fd_read
=
fd_read
;
tramp
->
fd_write
=
fd_write
;
tramp
->
opaque
=
opaque
;
if
(
fd_read
)
{
cond
|=
G_IO_IN
|
G_IO_ERR
;
}
if
(
fd_write
)
{
cond
|=
G_IO_OUT
|
G_IO_ERR
;
}
tramp
->
chan
=
g_io_channel_unix_new
(
fd
);
tramp
->
tag
=
g_io_add_watch
(
tramp
->
chan
,
cond
,
fd_trampoline
,
tramp
);
}
return
0
;
return
qemu_set_fd_handler2
(
fd
,
NULL
,
fd_read
,
fd_write
,
opaque
);
}
void
qemu_iohandler_fill
(
int
*
pnfds
,
fd_set
*
readfds
,
fd_set
*
writefds
,
fd_set
*
xfds
)
...
...
main-loop.c
0 → 100644
浏览文件 @
952e849c
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "config-host.h"
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
#include <stdbool.h>
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/stat.h>
#include "compatfd.h"
#endif
#include <glib.h>
#include "main-loop.h"
#include "qemu-timer.h"
#include "slirp/libslirp.h"
#ifndef _WIN32
static
int
io_thread_fd
=
-
1
;
void
qemu_notify_event
(
void
)
{
/* Write 8 bytes to be compatible with eventfd. */
static
const
uint64_t
val
=
1
;
ssize_t
ret
;
if
(
io_thread_fd
==
-
1
)
{
return
;
}
do
{
ret
=
write
(
io_thread_fd
,
&
val
,
sizeof
(
val
));
}
while
(
ret
<
0
&&
errno
==
EINTR
);
/* EAGAIN is fine, a read must be pending. */
if
(
ret
<
0
&&
errno
!=
EAGAIN
)
{
fprintf
(
stderr
,
"qemu_notify_event: write() failed: %s
\n
"
,
strerror
(
errno
));
exit
(
1
);
}
}
static
void
qemu_event_read
(
void
*
opaque
)
{
int
fd
=
(
intptr_t
)
opaque
;
ssize_t
len
;
char
buffer
[
512
];
/* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
do
{
len
=
read
(
fd
,
buffer
,
sizeof
(
buffer
));
}
while
((
len
==
-
1
&&
errno
==
EINTR
)
||
len
==
sizeof
(
buffer
));
}
static
int
qemu_event_init
(
void
)
{
int
err
;
int
fds
[
2
];
err
=
qemu_eventfd
(
fds
);
if
(
err
==
-
1
)
{
return
-
errno
;
}
err
=
fcntl_setfl
(
fds
[
0
],
O_NONBLOCK
);
if
(
err
<
0
)
{
goto
fail
;
}
err
=
fcntl_setfl
(
fds
[
1
],
O_NONBLOCK
);
if
(
err
<
0
)
{
goto
fail
;
}
qemu_set_fd_handler2
(
fds
[
0
],
NULL
,
qemu_event_read
,
NULL
,
(
void
*
)(
intptr_t
)
fds
[
0
]);
io_thread_fd
=
fds
[
1
];
return
0
;
fail:
close
(
fds
[
0
]);
close
(
fds
[
1
]);
return
err
;
}
/* If we have signalfd, we mask out the signals we want to handle and then
* use signalfd to listen for them. We rely on whatever the current signal
* handler is to dispatch the signals when we receive them.
*/
static
void
sigfd_handler
(
void
*
opaque
)
{
int
fd
=
(
intptr_t
)
opaque
;
struct
qemu_signalfd_siginfo
info
;
struct
sigaction
action
;
ssize_t
len
;
while
(
1
)
{
do
{
len
=
read
(
fd
,
&
info
,
sizeof
(
info
));
}
while
(
len
==
-
1
&&
errno
==
EINTR
);
if
(
len
==
-
1
&&
errno
==
EAGAIN
)
{
break
;
}
if
(
len
!=
sizeof
(
info
))
{
printf
(
"read from sigfd returned %zd: %m
\n
"
,
len
);
return
;
}
sigaction
(
info
.
ssi_signo
,
NULL
,
&
action
);
if
((
action
.
sa_flags
&
SA_SIGINFO
)
&&
action
.
sa_sigaction
)
{
action
.
sa_sigaction
(
info
.
ssi_signo
,
(
siginfo_t
*
)
&
info
,
NULL
);
}
else
if
(
action
.
sa_handler
)
{
action
.
sa_handler
(
info
.
ssi_signo
);
}
}
}
static
int
qemu_signal_init
(
void
)
{
int
sigfd
;
sigset_t
set
;
/*
* SIG_IPI must be blocked in the main thread and must not be caught
* by sigwait() in the signal thread. Otherwise, the cpu thread will
* not catch it reliably.
*/
sigemptyset
(
&
set
);
sigaddset
(
&
set
,
SIG_IPI
);
pthread_sigmask
(
SIG_BLOCK
,
&
set
,
NULL
);
sigemptyset
(
&
set
);
sigaddset
(
&
set
,
SIGIO
);
sigaddset
(
&
set
,
SIGALRM
);
sigaddset
(
&
set
,
SIGBUS
);
pthread_sigmask
(
SIG_BLOCK
,
&
set
,
NULL
);
sigfd
=
qemu_signalfd
(
&
set
);
if
(
sigfd
==
-
1
)
{
fprintf
(
stderr
,
"failed to create signalfd
\n
"
);
return
-
errno
;
}
fcntl_setfl
(
sigfd
,
O_NONBLOCK
);
qemu_set_fd_handler2
(
sigfd
,
NULL
,
sigfd_handler
,
NULL
,
(
void
*
)(
intptr_t
)
sigfd
);
return
0
;
}
#else
/* _WIN32 */
HANDLE
qemu_event_handle
;
static
void
dummy_event_handler
(
void
*
opaque
)
{
}
static
int
qemu_event_init
(
void
)
{
qemu_event_handle
=
CreateEvent
(
NULL
,
FALSE
,
FALSE
,
NULL
);
if
(
!
qemu_event_handle
)
{
fprintf
(
stderr
,
"Failed CreateEvent: %ld
\n
"
,
GetLastError
());
return
-
1
;
}
qemu_add_wait_object
(
qemu_event_handle
,
dummy_event_handler
,
NULL
);
return
0
;
}
void
qemu_notify_event
(
void
)
{
if
(
!
SetEvent
(
qemu_event_handle
))
{
fprintf
(
stderr
,
"qemu_notify_event: SetEvent failed: %ld
\n
"
,
GetLastError
());
exit
(
1
);
}
}
static
int
qemu_signal_init
(
void
)
{
return
0
;
}
#endif
int
qemu_init_main_loop
(
void
)
{
int
ret
;
qemu_mutex_lock_iothread
();
ret
=
qemu_signal_init
();
if
(
ret
)
{
return
ret
;
}
/* Note eventfd must be drained before signalfd handlers run */
ret
=
qemu_event_init
();
if
(
ret
)
{
return
ret
;
}
return
0
;
}
static
GPollFD
poll_fds
[
1024
*
2
];
/* this is probably overkill */
static
int
n_poll_fds
;
static
int
max_priority
;
static
void
glib_select_fill
(
int
*
max_fd
,
fd_set
*
rfds
,
fd_set
*
wfds
,
fd_set
*
xfds
,
struct
timeval
*
tv
)
{
GMainContext
*
context
=
g_main_context_default
();
int
i
;
int
timeout
=
0
,
cur_timeout
;
g_main_context_prepare
(
context
,
&
max_priority
);
n_poll_fds
=
g_main_context_query
(
context
,
max_priority
,
&
timeout
,
poll_fds
,
ARRAY_SIZE
(
poll_fds
));
g_assert
(
n_poll_fds
<=
ARRAY_SIZE
(
poll_fds
));
for
(
i
=
0
;
i
<
n_poll_fds
;
i
++
)
{
GPollFD
*
p
=
&
poll_fds
[
i
];
if
((
p
->
events
&
G_IO_IN
))
{
FD_SET
(
p
->
fd
,
rfds
);
*
max_fd
=
MAX
(
*
max_fd
,
p
->
fd
);
}
if
((
p
->
events
&
G_IO_OUT
))
{
FD_SET
(
p
->
fd
,
wfds
);
*
max_fd
=
MAX
(
*
max_fd
,
p
->
fd
);
}
if
((
p
->
events
&
G_IO_ERR
))
{
FD_SET
(
p
->
fd
,
xfds
);
*
max_fd
=
MAX
(
*
max_fd
,
p
->
fd
);
}
}
cur_timeout
=
(
tv
->
tv_sec
*
1000
)
+
((
tv
->
tv_usec
+
500
)
/
1000
);
if
(
timeout
>=
0
&&
timeout
<
cur_timeout
)
{
tv
->
tv_sec
=
timeout
/
1000
;
tv
->
tv_usec
=
(
timeout
%
1000
)
*
1000
;
}
}
static
void
glib_select_poll
(
fd_set
*
rfds
,
fd_set
*
wfds
,
fd_set
*
xfds
,
bool
err
)
{
GMainContext
*
context
=
g_main_context_default
();
if
(
!
err
)
{
int
i
;
for
(
i
=
0
;
i
<
n_poll_fds
;
i
++
)
{
GPollFD
*
p
=
&
poll_fds
[
i
];
if
((
p
->
events
&
G_IO_IN
)
&&
FD_ISSET
(
p
->
fd
,
rfds
))
{
p
->
revents
|=
G_IO_IN
;
}
if
((
p
->
events
&
G_IO_OUT
)
&&
FD_ISSET
(
p
->
fd
,
wfds
))
{
p
->
revents
|=
G_IO_OUT
;
}
if
((
p
->
events
&
G_IO_ERR
)
&&
FD_ISSET
(
p
->
fd
,
xfds
))
{
p
->
revents
|=
G_IO_ERR
;
}
}
}
if
(
g_main_context_check
(
context
,
max_priority
,
poll_fds
,
n_poll_fds
))
{
g_main_context_dispatch
(
context
);
}
}
#ifdef _WIN32
/***********************************************************/
/* Polling handling */
typedef
struct
PollingEntry
{
PollingFunc
*
func
;
void
*
opaque
;
struct
PollingEntry
*
next
;
}
PollingEntry
;
static
PollingEntry
*
first_polling_entry
;
int
qemu_add_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
)
{
PollingEntry
**
ppe
,
*
pe
;
pe
=
g_malloc0
(
sizeof
(
PollingEntry
));
pe
->
func
=
func
;
pe
->
opaque
=
opaque
;
for
(
ppe
=
&
first_polling_entry
;
*
ppe
!=
NULL
;
ppe
=
&
(
*
ppe
)
->
next
);
*
ppe
=
pe
;
return
0
;
}
void
qemu_del_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
)
{
PollingEntry
**
ppe
,
*
pe
;
for
(
ppe
=
&
first_polling_entry
;
*
ppe
!=
NULL
;
ppe
=
&
(
*
ppe
)
->
next
)
{
pe
=
*
ppe
;
if
(
pe
->
func
==
func
&&
pe
->
opaque
==
opaque
)
{
*
ppe
=
pe
->
next
;
g_free
(
pe
);
break
;
}
}
}
/***********************************************************/
/* Wait objects support */
typedef
struct
WaitObjects
{
int
num
;
HANDLE
events
[
MAXIMUM_WAIT_OBJECTS
+
1
];
WaitObjectFunc
*
func
[
MAXIMUM_WAIT_OBJECTS
+
1
];
void
*
opaque
[
MAXIMUM_WAIT_OBJECTS
+
1
];
}
WaitObjects
;
static
WaitObjects
wait_objects
=
{
0
};
int
qemu_add_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
)
{
WaitObjects
*
w
=
&
wait_objects
;
if
(
w
->
num
>=
MAXIMUM_WAIT_OBJECTS
)
{
return
-
1
;
}
w
->
events
[
w
->
num
]
=
handle
;
w
->
func
[
w
->
num
]
=
func
;
w
->
opaque
[
w
->
num
]
=
opaque
;
w
->
num
++
;
return
0
;
}
void
qemu_del_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
)
{
int
i
,
found
;
WaitObjects
*
w
=
&
wait_objects
;
found
=
0
;
for
(
i
=
0
;
i
<
w
->
num
;
i
++
)
{
if
(
w
->
events
[
i
]
==
handle
)
{
found
=
1
;
}
if
(
found
)
{
w
->
events
[
i
]
=
w
->
events
[
i
+
1
];
w
->
func
[
i
]
=
w
->
func
[
i
+
1
];
w
->
opaque
[
i
]
=
w
->
opaque
[
i
+
1
];
}
}
if
(
found
)
{
w
->
num
--
;
}
}
static
void
os_host_main_loop_wait
(
int
*
timeout
)
{
int
ret
,
ret2
,
i
;
PollingEntry
*
pe
;
/* XXX: need to suppress polling by better using win32 events */
ret
=
0
;
for
(
pe
=
first_polling_entry
;
pe
!=
NULL
;
pe
=
pe
->
next
)
{
ret
|=
pe
->
func
(
pe
->
opaque
);
}
if
(
ret
==
0
)
{
int
err
;
WaitObjects
*
w
=
&
wait_objects
;
qemu_mutex_unlock_iothread
();
ret
=
WaitForMultipleObjects
(
w
->
num
,
w
->
events
,
FALSE
,
*
timeout
);
qemu_mutex_lock_iothread
();
if
(
WAIT_OBJECT_0
+
0
<=
ret
&&
ret
<=
WAIT_OBJECT_0
+
w
->
num
-
1
)
{
if
(
w
->
func
[
ret
-
WAIT_OBJECT_0
])
{
w
->
func
[
ret
-
WAIT_OBJECT_0
](
w
->
opaque
[
ret
-
WAIT_OBJECT_0
]);
}
/* Check for additional signaled events */
for
(
i
=
(
ret
-
WAIT_OBJECT_0
+
1
);
i
<
w
->
num
;
i
++
)
{
/* Check if event is signaled */
ret2
=
WaitForSingleObject
(
w
->
events
[
i
],
0
);
if
(
ret2
==
WAIT_OBJECT_0
)
{
if
(
w
->
func
[
i
])
{
w
->
func
[
i
](
w
->
opaque
[
i
]);
}
}
else
if
(
ret2
!=
WAIT_TIMEOUT
)
{
err
=
GetLastError
();
fprintf
(
stderr
,
"WaitForSingleObject error %d %d
\n
"
,
i
,
err
);
}
}
}
else
if
(
ret
!=
WAIT_TIMEOUT
)
{
err
=
GetLastError
();
fprintf
(
stderr
,
"WaitForMultipleObjects error %d %d
\n
"
,
ret
,
err
);
}
}
*
timeout
=
0
;
}
#else
static
inline
void
os_host_main_loop_wait
(
int
*
timeout
)
{
}
#endif
int
main_loop_wait
(
int
nonblocking
)
{
fd_set
rfds
,
wfds
,
xfds
;
int
ret
,
nfds
;
struct
timeval
tv
;
int
timeout
;
if
(
nonblocking
)
{
timeout
=
0
;
}
else
{
timeout
=
qemu_calculate_timeout
();
qemu_bh_update_timeout
(
&
timeout
);
}
os_host_main_loop_wait
(
&
timeout
);
tv
.
tv_sec
=
timeout
/
1000
;
tv
.
tv_usec
=
(
timeout
%
1000
)
*
1000
;
/* poll any events */
/* XXX: separate device handlers from system ones */
nfds
=
-
1
;
FD_ZERO
(
&
rfds
);
FD_ZERO
(
&
wfds
);
FD_ZERO
(
&
xfds
);
#ifdef CONFIG_SLIRP
slirp_select_fill
(
&
nfds
,
&
rfds
,
&
wfds
,
&
xfds
);
#endif
qemu_iohandler_fill
(
&
nfds
,
&
rfds
,
&
wfds
,
&
xfds
);
glib_select_fill
(
&
nfds
,
&
rfds
,
&
wfds
,
&
xfds
,
&
tv
);
if
(
timeout
>
0
)
{
qemu_mutex_unlock_iothread
();
}
ret
=
select
(
nfds
+
1
,
&
rfds
,
&
wfds
,
&
xfds
,
&
tv
);
if
(
timeout
>
0
)
{
qemu_mutex_lock_iothread
();
}
glib_select_poll
(
&
rfds
,
&
wfds
,
&
xfds
,
(
ret
<
0
));
qemu_iohandler_poll
(
&
rfds
,
&
wfds
,
&
xfds
,
ret
);
#ifdef CONFIG_SLIRP
slirp_select_poll
(
&
rfds
,
&
wfds
,
&
xfds
,
(
ret
<
0
));
#endif
qemu_run_all_timers
();
/* Check bottom-halves last in case any of the earlier events triggered
them. */
qemu_bh_poll
();
return
ret
;
}
main-loop.h
0 → 100644
浏览文件 @
952e849c
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_MAIN_LOOP_H
#define QEMU_MAIN_LOOP_H 1
#ifdef SIGRTMIN
#define SIG_IPI (SIGRTMIN+4)
#else
#define SIG_IPI SIGUSR1
#endif
/**
* qemu_init_main_loop: Set up the process so that it can run the main loop.
*
* This includes setting up signal handlers. It should be called before
* any other threads are created. In addition, threads other than the
* main one should block signals that are trapped by the main loop.
* For simplicity, you can consider these signals to be safe: SIGUSR1,
* SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
* signals if available. Remember that Windows in practice does not have
* signals, though.
*/
int
qemu_init_main_loop
(
void
);
/**
* main_loop_wait: Run one iteration of the main loop.
*
* If @nonblocking is true, poll for events, otherwise suspend until
* one actually occurs. The main loop usually consists of a loop that
* repeatedly calls main_loop_wait(false).
*
* Main loop services include file descriptor callbacks, bottom halves
* and timers (defined in qemu-timer.h). Bottom halves are similar to timers
* that execute immediately, but have a lower overhead and scheduling them
* is wait-free, thread-safe and signal-safe.
*
* It is sometimes useful to put a whole program in a coroutine. In this
* case, the coroutine actually should be started from within the main loop,
* so that the main loop can run whenever the coroutine yields. To do this,
* you can use a bottom half to enter the coroutine as soon as the main loop
* starts:
*
* void enter_co_bh(void *opaque) {
* QEMUCoroutine *co = opaque;
* qemu_coroutine_enter(co, NULL);
* }
*
* ...
* QEMUCoroutine *co = qemu_coroutine_create(coroutine_entry);
* QEMUBH *start_bh = qemu_bh_new(enter_co_bh, co);
* qemu_bh_schedule(start_bh);
* while (...) {
* main_loop_wait(false);
* }
*
* (In the future we may provide a wrapper for this).
*
* @nonblocking: Whether the caller should block until an event occurs.
*/
int
main_loop_wait
(
int
nonblocking
);
/**
* qemu_notify_event: Force processing of pending events.
*
* Similar to signaling a condition variable, qemu_notify_event forces
* main_loop_wait to look at pending events and exit. The caller of
* main_loop_wait will usually call it again very soon, so qemu_notify_event
* also has the side effect of recalculating the sets of file descriptors
* that the main loop waits for.
*
* Calling qemu_notify_event is rarely necessary, because main loop
* services (bottom halves and timers) call it themselves. One notable
* exception occurs when using qemu_set_fd_handler2 (see below).
*/
void
qemu_notify_event
(
void
);
#ifdef _WIN32
/* return TRUE if no sleep should be done afterwards */
typedef
int
PollingFunc
(
void
*
opaque
);
/**
* qemu_add_polling_cb: Register a Windows-specific polling callback
*
* Currently, under Windows some events are polled rather than waited for.
* Polling callbacks do not ensure that @func is called timely, because
* the main loop might wait for an arbitrarily long time. If possible,
* you should instead create a separate thread that does a blocking poll
* and set a Win32 event object. The event can then be passed to
* qemu_add_wait_object.
*
* Polling callbacks really have nothing Windows specific in them, but
* as they are a hack and are currenly not necessary under POSIX systems,
* they are only available when QEMU is running under Windows.
*
* @func: The function that does the polling, and returns 1 to force
* immediate completion of main_loop_wait.
* @opaque: A pointer-size value that is passed to @func.
*/
int
qemu_add_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
);
/**
* qemu_del_polling_cb: Unregister a Windows-specific polling callback
*
* This function removes a callback that was registered with
* qemu_add_polling_cb.
*
* @func: The function that was passed to qemu_add_polling_cb.
* @opaque: A pointer-size value that was passed to qemu_add_polling_cb.
*/
void
qemu_del_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
);
/* Wait objects handling */
typedef
void
WaitObjectFunc
(
void
*
opaque
);
/**
* qemu_add_wait_object: Register a callback for a Windows handle
*
* Under Windows, the iohandler mechanism can only be used with sockets.
* QEMU must use the WaitForMultipleObjects API to wait on other handles.
* This function registers a #HANDLE with QEMU, so that it will be included
* in the main loop's calls to WaitForMultipleObjects. When the handle
* is in a signaled state, QEMU will call @func.
*
* @handle: The Windows handle to be observed.
* @func: A function to be called when @handle is in a signaled state.
* @opaque: A pointer-size value that is passed to @func.
*/
int
qemu_add_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
);
/**
* qemu_del_wait_object: Unregister a callback for a Windows handle
*
* This function removes a callback that was registered with
* qemu_add_wait_object.
*
* @func: The function that was passed to qemu_add_wait_object.
* @opaque: A pointer-size value that was passed to qemu_add_wait_object.
*/
void
qemu_del_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
);
#endif
/* async I/O support */
typedef
void
IOReadHandler
(
void
*
opaque
,
const
uint8_t
*
buf
,
int
size
);
typedef
int
IOCanReadHandler
(
void
*
opaque
);
typedef
void
IOHandler
(
void
*
opaque
);
/**
* qemu_set_fd_handler2: Register a file descriptor with the main loop
*
* This function tells the main loop to wake up whenever one of the
* following conditions is true:
*
* 1) if @fd_write is not %NULL, when the file descriptor is writable;
*
* 2) if @fd_read is not %NULL, when the file descriptor is readable.
*
* @fd_read_poll can be used to disable the @fd_read callback temporarily.
* This is useful to avoid calling qemu_set_fd_handler2 every time the
* client becomes interested in reading (or dually, stops being interested).
* A typical example is when @fd is a listening socket and you want to bound
* the number of active clients. Remember to call qemu_notify_event whenever
* the condition may change from %false to %true.
*
* The callbacks that are set up by qemu_set_fd_handler2 are level-triggered.
* If @fd_read does not read from @fd, or @fd_write does not write to @fd
* until its buffers are full, they will be called again on the next
* iteration.
*
* @fd: The file descriptor to be observed. Under Windows it must be
* a #SOCKET.
*
* @fd_read_poll: A function that returns 1 if the @fd_read callback
* should be fired. If the function returns 0, the main loop will not
* end its iteration even if @fd becomes readable.
*
* @fd_read: A level-triggered callback that is fired if @fd is readable
* at the beginning of a main loop iteration, or if it becomes readable
* during one.
*
* @fd_write: A level-triggered callback that is fired when @fd is writable
* at the beginning of a main loop iteration, or if it becomes writable
* during one.
*
* @opaque: A pointer-sized value that is passed to @fd_read_poll,
* @fd_read and @fd_write.
*/
int
qemu_set_fd_handler2
(
int
fd
,
IOCanReadHandler
*
fd_read_poll
,
IOHandler
*
fd_read
,
IOHandler
*
fd_write
,
void
*
opaque
);
/**
* qemu_set_fd_handler: Register a file descriptor with the main loop
*
* This function tells the main loop to wake up whenever one of the
* following conditions is true:
*
* 1) if @fd_write is not %NULL, when the file descriptor is writable;
*
* 2) if @fd_read is not %NULL, when the file descriptor is readable.
*
* The callbacks that are set up by qemu_set_fd_handler are level-triggered.
* If @fd_read does not read from @fd, or @fd_write does not write to @fd
* until its buffers are full, they will be called again on the next
* iteration.
*
* @fd: The file descriptor to be observed. Under Windows it must be
* a #SOCKET.
*
* @fd_read: A level-triggered callback that is fired if @fd is readable
* at the beginning of a main loop iteration, or if it becomes readable
* during one.
*
* @fd_write: A level-triggered callback that is fired when @fd is writable
* at the beginning of a main loop iteration, or if it becomes writable
* during one.
*
* @opaque: A pointer-sized value that is passed to @fd_read and @fd_write.
*/
int
qemu_set_fd_handler
(
int
fd
,
IOHandler
*
fd_read
,
IOHandler
*
fd_write
,
void
*
opaque
);
typedef
struct
QEMUBH
QEMUBH
;
typedef
void
QEMUBHFunc
(
void
*
opaque
);
/**
* qemu_bh_new: Allocate a new bottom half structure.
*
* Bottom halves are lightweight callbacks whose invocation is guaranteed
* to be wait-free, thread-safe and signal-safe. The #QEMUBH structure
* is opaque and must be allocated prior to its use.
*/
QEMUBH
*
qemu_bh_new
(
QEMUBHFunc
*
cb
,
void
*
opaque
);
/**
* qemu_bh_schedule: Schedule a bottom half.
*
* Scheduling a bottom half interrupts the main loop and causes the
* execution of the callback that was passed to qemu_bh_new.
*
* Bottom halves that are scheduled from a bottom half handler are instantly
* invoked. This can create an infinite loop if a bottom half handler
* schedules itself.
*
* @bh: The bottom half to be scheduled.
*/
void
qemu_bh_schedule
(
QEMUBH
*
bh
);
/**
* qemu_bh_cancel: Cancel execution of a bottom half.
*
* Canceling execution of a bottom half undoes the effect of calls to
* qemu_bh_schedule without freeing its resources yet. While cancellation
* itself is also wait-free and thread-safe, it can of course race with the
* loop that executes bottom halves unless you are holding the iothread
* mutex. This makes it mostly useless if you are not holding the mutex.
*
* @bh: The bottom half to be canceled.
*/
void
qemu_bh_cancel
(
QEMUBH
*
bh
);
/**
*qemu_bh_delete: Cancel execution of a bottom half and free its resources.
*
* Deleting a bottom half frees the memory that was allocated for it by
* qemu_bh_new. It also implies canceling the bottom half if it was
* scheduled.
*
* @bh: The bottom half to be deleted.
*/
void
qemu_bh_delete
(
QEMUBH
*
bh
);
#ifdef CONFIG_POSIX
/**
* qemu_add_child_watch: Register a child process for reaping.
*
* Under POSIX systems, a parent process must read the exit status of
* its child processes using waitpid, or the operating system will not
* free some of the resources attached to that process.
*
* This function directs the QEMU main loop to observe a child process
* and call waitpid as soon as it exits; the watch is then removed
* automatically. It is useful whenever QEMU forks a child process
* but will find out about its termination by other means such as a
* "broken pipe".
*
* @pid: The pid that QEMU should observe.
*/
int
qemu_add_child_watch
(
pid_t
pid
);
#endif
/**
* qemu_mutex_lock_iothread: Lock the main loop mutex.
*
* This function locks the main loop mutex. The mutex is taken by
* qemu_init_main_loop and always taken except while waiting on
* external events (such as with select). The mutex should be taken
* by threads other than the main loop thread when calling
* qemu_bh_new(), qemu_set_fd_handler() and basically all other
* functions documented in this file.
*/
void
qemu_mutex_lock_iothread
(
void
);
/**
* qemu_mutex_unlock_iothread: Unlock the main loop mutex.
*
* This function unlocks the main loop mutex. The mutex is taken by
* qemu_init_main_loop and always taken except while waiting on
* external events (such as with select). The mutex should be unlocked
* as soon as possible by threads other than the main loop thread,
* because it prevents the main loop from processing callbacks,
* including timers and bottom halves.
*/
void
qemu_mutex_unlock_iothread
(
void
);
/* internal interfaces */
void
qemu_iohandler_fill
(
int
*
pnfds
,
fd_set
*
readfds
,
fd_set
*
writefds
,
fd_set
*
xfds
);
void
qemu_iohandler_poll
(
fd_set
*
readfds
,
fd_set
*
writefds
,
fd_set
*
xfds
,
int
rc
);
void
qemu_bh_schedule_idle
(
QEMUBH
*
bh
);
int
qemu_bh_poll
(
void
);
void
qemu_bh_update_timeout
(
int
*
timeout
);
#endif
os-win32.c
浏览文件 @
952e849c
...
...
@@ -48,129 +48,6 @@ int setenv(const char *name, const char *value, int overwrite)
return
result
;
}
/***********************************************************/
/* Polling handling */
typedef
struct
PollingEntry
{
PollingFunc
*
func
;
void
*
opaque
;
struct
PollingEntry
*
next
;
}
PollingEntry
;
static
PollingEntry
*
first_polling_entry
;
int
qemu_add_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
)
{
PollingEntry
**
ppe
,
*
pe
;
pe
=
g_malloc0
(
sizeof
(
PollingEntry
));
pe
->
func
=
func
;
pe
->
opaque
=
opaque
;
for
(
ppe
=
&
first_polling_entry
;
*
ppe
!=
NULL
;
ppe
=
&
(
*
ppe
)
->
next
);
*
ppe
=
pe
;
return
0
;
}
void
qemu_del_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
)
{
PollingEntry
**
ppe
,
*
pe
;
for
(
ppe
=
&
first_polling_entry
;
*
ppe
!=
NULL
;
ppe
=
&
(
*
ppe
)
->
next
)
{
pe
=
*
ppe
;
if
(
pe
->
func
==
func
&&
pe
->
opaque
==
opaque
)
{
*
ppe
=
pe
->
next
;
g_free
(
pe
);
break
;
}
}
}
/***********************************************************/
/* Wait objects support */
typedef
struct
WaitObjects
{
int
num
;
HANDLE
events
[
MAXIMUM_WAIT_OBJECTS
+
1
];
WaitObjectFunc
*
func
[
MAXIMUM_WAIT_OBJECTS
+
1
];
void
*
opaque
[
MAXIMUM_WAIT_OBJECTS
+
1
];
}
WaitObjects
;
static
WaitObjects
wait_objects
=
{
0
};
int
qemu_add_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
)
{
WaitObjects
*
w
=
&
wait_objects
;
if
(
w
->
num
>=
MAXIMUM_WAIT_OBJECTS
)
return
-
1
;
w
->
events
[
w
->
num
]
=
handle
;
w
->
func
[
w
->
num
]
=
func
;
w
->
opaque
[
w
->
num
]
=
opaque
;
w
->
num
++
;
return
0
;
}
void
qemu_del_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
)
{
int
i
,
found
;
WaitObjects
*
w
=
&
wait_objects
;
found
=
0
;
for
(
i
=
0
;
i
<
w
->
num
;
i
++
)
{
if
(
w
->
events
[
i
]
==
handle
)
found
=
1
;
if
(
found
)
{
w
->
events
[
i
]
=
w
->
events
[
i
+
1
];
w
->
func
[
i
]
=
w
->
func
[
i
+
1
];
w
->
opaque
[
i
]
=
w
->
opaque
[
i
+
1
];
}
}
if
(
found
)
w
->
num
--
;
}
void
os_host_main_loop_wait
(
int
*
timeout
)
{
int
ret
,
ret2
,
i
;
PollingEntry
*
pe
;
/* XXX: need to suppress polling by better using win32 events */
ret
=
0
;
for
(
pe
=
first_polling_entry
;
pe
!=
NULL
;
pe
=
pe
->
next
)
{
ret
|=
pe
->
func
(
pe
->
opaque
);
}
if
(
ret
==
0
)
{
int
err
;
WaitObjects
*
w
=
&
wait_objects
;
qemu_mutex_unlock_iothread
();
ret
=
WaitForMultipleObjects
(
w
->
num
,
w
->
events
,
FALSE
,
*
timeout
);
qemu_mutex_lock_iothread
();
if
(
WAIT_OBJECT_0
+
0
<=
ret
&&
ret
<=
WAIT_OBJECT_0
+
w
->
num
-
1
)
{
if
(
w
->
func
[
ret
-
WAIT_OBJECT_0
])
w
->
func
[
ret
-
WAIT_OBJECT_0
](
w
->
opaque
[
ret
-
WAIT_OBJECT_0
]);
/* Check for additional signaled events */
for
(
i
=
(
ret
-
WAIT_OBJECT_0
+
1
);
i
<
w
->
num
;
i
++
)
{
/* Check if event is signaled */
ret2
=
WaitForSingleObject
(
w
->
events
[
i
],
0
);
if
(
ret2
==
WAIT_OBJECT_0
)
{
if
(
w
->
func
[
i
])
w
->
func
[
i
](
w
->
opaque
[
i
]);
}
else
if
(
ret2
==
WAIT_TIMEOUT
)
{
}
else
{
err
=
GetLastError
();
fprintf
(
stderr
,
"WaitForSingleObject error %d %d
\n
"
,
i
,
err
);
}
}
}
else
if
(
ret
==
WAIT_TIMEOUT
)
{
}
else
{
err
=
GetLastError
();
fprintf
(
stderr
,
"WaitForMultipleObjects error %d %d
\n
"
,
ret
,
err
);
}
}
*
timeout
=
0
;
}
static
BOOL
WINAPI
qemu_ctrl_handler
(
DWORD
type
)
{
exit
(
STATUS_CONTROL_C_EXIT
);
...
...
qemu-char.h
浏览文件 @
952e849c
...
...
@@ -7,6 +7,7 @@
#include "qemu-config.h"
#include "qobject.h"
#include "qstring.h"
#include "main-loop.h"
/* character device */
...
...
@@ -237,15 +238,4 @@ void qemu_chr_close_mem(CharDriverState *chr);
QString
*
qemu_chr_mem_to_qs
(
CharDriverState
*
chr
);
size_t
qemu_chr_mem_osize
(
const
CharDriverState
*
chr
);
/* async I/O support */
int
qemu_set_fd_handler2
(
int
fd
,
IOCanReadHandler
*
fd_read_poll
,
IOHandler
*
fd_read
,
IOHandler
*
fd_write
,
void
*
opaque
);
int
qemu_set_fd_handler
(
int
fd
,
IOHandler
*
fd_read
,
IOHandler
*
fd_write
,
void
*
opaque
);
#endif
qemu-common.h
浏览文件 @
952e849c
...
...
@@ -13,7 +13,6 @@
typedef
struct
QEMUTimer
QEMUTimer
;
typedef
struct
QEMUFile
QEMUFile
;
typedef
struct
QEMUBH
QEMUBH
;
typedef
struct
DeviceState
DeviceState
;
struct
Monitor
;
...
...
@@ -96,6 +95,10 @@ static inline char *realpath(const char *path, char *resolved_path)
}
#endif
/* icount */
void
configure_icount
(
const
char
*
option
);
extern
int
use_icount
;
/* FIXME: Remove NEED_CPU_H. */
#ifndef NEED_CPU_H
...
...
@@ -113,23 +116,6 @@ static inline char *realpath(const char *path, char *resolved_path)
int
qemu_main
(
int
argc
,
char
**
argv
,
char
**
envp
);
#endif
/* bottom halves */
typedef
void
QEMUBHFunc
(
void
*
opaque
);
QEMUBH
*
qemu_bh_new
(
QEMUBHFunc
*
cb
,
void
*
opaque
);
void
qemu_bh_schedule
(
QEMUBH
*
bh
);
/* Bottom halfs that are scheduled from a bottom half handler are instantly
* invoked. This can create an infinite loop if a bottom half handler
* schedules itself. qemu_bh_schedule_idle() avoids this infinite loop by
* ensuring that the bottom half isn't executed until the next main loop
* iteration.
*/
void
qemu_bh_schedule_idle
(
QEMUBH
*
bh
);
void
qemu_bh_cancel
(
QEMUBH
*
bh
);
void
qemu_bh_delete
(
QEMUBH
*
bh
);
int
qemu_bh_poll
(
void
);
void
qemu_bh_update_timeout
(
int
*
timeout
);
void
qemu_get_timedate
(
struct
tm
*
tm
,
int
offset
);
int
qemu_timedate_diff
(
struct
tm
*
tm
);
...
...
@@ -183,16 +169,12 @@ const char *path(const char *pathname);
void
*
qemu_oom_check
(
void
*
ptr
);
void
qemu_mutex_lock_iothread
(
void
);
void
qemu_mutex_unlock_iothread
(
void
);
int
qemu_open
(
const
char
*
name
,
int
flags
,
...);
ssize_t
qemu_write_full
(
int
fd
,
const
void
*
buf
,
size_t
count
)
QEMU_WARN_UNUSED_RESULT
;
void
qemu_set_cloexec
(
int
fd
);
#ifndef _WIN32
int
qemu_add_child_watch
(
pid_t
pid
);
int
qemu_eventfd
(
int
pipefd
[
2
]);
int
qemu_pipe
(
int
pipefd
[
2
]);
#endif
...
...
@@ -207,14 +189,6 @@ int qemu_pipe(int pipefd[2]);
void
QEMU_NORETURN
hw_error
(
const
char
*
fmt
,
...)
GCC_FMT_ATTR
(
1
,
2
);
/* IO callbacks. */
typedef
void
IOReadHandler
(
void
*
opaque
,
const
uint8_t
*
buf
,
int
size
);
typedef
int
IOCanReadHandler
(
void
*
opaque
);
typedef
void
IOHandler
(
void
*
opaque
);
void
qemu_iohandler_fill
(
int
*
pnfds
,
fd_set
*
readfds
,
fd_set
*
writefds
,
fd_set
*
xfds
);
void
qemu_iohandler_poll
(
fd_set
*
readfds
,
fd_set
*
writefds
,
fd_set
*
xfds
,
int
rc
);
struct
ParallelIOArg
{
void
*
buffer
;
int
count
;
...
...
@@ -276,9 +250,6 @@ void cpu_exec_init_all(void);
void
cpu_save
(
QEMUFile
*
f
,
void
*
opaque
);
int
cpu_load
(
QEMUFile
*
f
,
void
*
opaque
,
int
version_id
);
/* Force QEMU to process pending events */
void
qemu_notify_event
(
void
);
/* Unblock cpu */
void
qemu_cpu_kick
(
void
*
env
);
void
qemu_cpu_kick_self
(
void
);
...
...
qemu-coroutine-lock.c
浏览文件 @
952e849c
...
...
@@ -26,6 +26,7 @@
#include "qemu-coroutine.h"
#include "qemu-coroutine-int.h"
#include "qemu-queue.h"
#include "main-loop.h"
#include "trace.h"
static
QTAILQ_HEAD
(,
Coroutine
)
unlock_bh_queue
=
...
...
qemu-os-posix.h
浏览文件 @
952e849c
...
...
@@ -26,10 +26,6 @@
#ifndef QEMU_OS_POSIX_H
#define QEMU_OS_POSIX_H
static
inline
void
os_host_main_loop_wait
(
int
*
timeout
)
{
}
void
os_set_line_buffering
(
void
);
void
os_set_proc_name
(
const
char
*
s
);
void
os_setup_signal_handling
(
void
);
...
...
qemu-os-win32.h
浏览文件 @
952e849c
...
...
@@ -28,26 +28,11 @@
#include <windows.h>
#include <winsock2.h>
#include "main-loop.h"
/* Declaration of ffs() is missing in MinGW's strings.h. */
int
ffs
(
int
i
);
/* Polling handling */
/* return TRUE if no sleep should be done afterwards */
typedef
int
PollingFunc
(
void
*
opaque
);
int
qemu_add_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
);
void
qemu_del_polling_cb
(
PollingFunc
*
func
,
void
*
opaque
);
/* Wait objects handling */
typedef
void
WaitObjectFunc
(
void
*
opaque
);
int
qemu_add_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
);
void
qemu_del_wait_object
(
HANDLE
handle
,
WaitObjectFunc
*
func
,
void
*
opaque
);
void
os_host_main_loop_wait
(
int
*
timeout
);
static
inline
void
os_setup_signal_handling
(
void
)
{}
static
inline
void
os_daemonize
(
void
)
{}
static
inline
void
os_setup_post
(
void
)
{}
...
...
qemu-timer.c
浏览文件 @
952e849c
此差异已折叠。
点击以展开。
qemu-timer.h
浏览文件 @
952e849c
...
...
@@ -2,6 +2,7 @@
#define QEMU_TIMER_H
#include "qemu-common.h"
#include "main-loop.h"
#include "notify.h"
#include <time.h>
#include <sys/time.h>
...
...
@@ -38,6 +39,9 @@ extern QEMUClock *vm_clock;
extern
QEMUClock
*
host_clock
;
int64_t
qemu_get_clock_ns
(
QEMUClock
*
clock
);
int64_t
qemu_clock_has_timers
(
QEMUClock
*
clock
);
int64_t
qemu_clock_expired
(
QEMUClock
*
clock
);
int64_t
qemu_clock_deadline
(
QEMUClock
*
clock
);
void
qemu_clock_enable
(
QEMUClock
*
clock
,
int
enabled
);
void
qemu_clock_warp
(
QEMUClock
*
clock
);
...
...
@@ -49,19 +53,18 @@ QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
QEMUTimerCB
*
cb
,
void
*
opaque
);
void
qemu_free_timer
(
QEMUTimer
*
ts
);
void
qemu_del_timer
(
QEMUTimer
*
ts
);
void
qemu_mod_timer_ns
(
QEMUTimer
*
ts
,
int64_t
expire_time
);
void
qemu_mod_timer
(
QEMUTimer
*
ts
,
int64_t
expire_time
);
int
qemu_timer_pending
(
QEMUTimer
*
ts
);
int
qemu_timer_expired
(
QEMUTimer
*
timer_head
,
int64_t
current_time
);
uint64_t
qemu_timer_expire_time_ns
(
QEMUTimer
*
ts
);
void
qemu_run_all_timers
(
void
);
int
qemu_alarm_pending
(
void
);
int64_t
qemu_next_icount_deadline
(
void
);
void
configure_alarms
(
char
const
*
opt
);
void
configure_icount
(
const
char
*
option
);
int
qemu_calculate_timeout
(
void
);
void
init_clocks
(
void
);
int
init_timer_alarm
(
void
);
void
quit_timers
(
void
);
int64_t
cpu_get_ticks
(
void
);
void
cpu_enable_ticks
(
void
);
...
...
@@ -150,12 +153,8 @@ void ptimer_run(ptimer_state *s, int oneshot);
void
ptimer_stop
(
ptimer_state
*
s
);
/* icount */
int64_t
qemu_icount_round
(
int64_t
count
);
extern
int64_t
qemu_icount
;
extern
int
use_icount
;
extern
int
icount_time_shift
;
extern
int64_t
qemu_icount_bias
;
int64_t
cpu_get_icount
(
void
);
int64_t
cpu_get_clock
(
void
);
/*******************************************/
/* host CPU ticks (if available) */
...
...
@@ -311,22 +310,6 @@ static inline int64_t cpu_get_real_ticks (void)
}
#endif
#ifdef NEED_CPU_H
/* Deterministic execution requires that IO only be performed on the last
instruction of a TB so that interrupts take effect immediately. */
static
inline
int
can_do_io
(
CPUState
*
env
)
{
if
(
!
use_icount
)
return
1
;
/* If not executing code then assume we are ok. */
if
(
!
env
->
current_tb
)
return
1
;
return
env
->
can_do_io
!=
0
;
}
#endif
#ifdef CONFIG_PROFILER
static
inline
int64_t
profile_getclock
(
void
)
{
...
...
savevm.c
浏览文件 @
952e849c
...
...
@@ -81,6 +81,7 @@
#include "migration.h"
#include "qemu_socket.h"
#include "qemu-queue.h"
#include "qemu-timer.h"
#include "cpus.h"
#define SELF_ANNOUNCE_ROUNDS 5
...
...
@@ -712,6 +713,30 @@ uint64_t qemu_get_be64(QEMUFile *f)
return
v
;
}
/* timer */
void
qemu_put_timer
(
QEMUFile
*
f
,
QEMUTimer
*
ts
)
{
uint64_t
expire_time
;
expire_time
=
qemu_timer_expire_time_ns
(
ts
);
qemu_put_be64
(
f
,
expire_time
);
}
void
qemu_get_timer
(
QEMUFile
*
f
,
QEMUTimer
*
ts
)
{
uint64_t
expire_time
;
expire_time
=
qemu_get_be64
(
f
);
if
(
expire_time
!=
-
1
)
{
qemu_mod_timer_ns
(
ts
,
expire_time
);
}
else
{
qemu_del_timer
(
ts
);
}
}
/* bool */
static
int
get_bool
(
QEMUFile
*
f
,
void
*
pv
,
size_t
size
)
...
...
slirp/libslirp.h
浏览文件 @
952e849c
...
...
@@ -3,8 +3,6 @@
#include "qemu-common.h"
#ifdef CONFIG_SLIRP
struct
Slirp
;
typedef
struct
Slirp
Slirp
;
...
...
@@ -44,13 +42,4 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
size_t
slirp_socket_can_recv
(
Slirp
*
slirp
,
struct
in_addr
guest_addr
,
int
guest_port
);
#else
/* !CONFIG_SLIRP */
static
inline
void
slirp_select_fill
(
int
*
pnfds
,
fd_set
*
readfds
,
fd_set
*
writefds
,
fd_set
*
xfds
)
{
}
static
inline
void
slirp_select_poll
(
fd_set
*
readfds
,
fd_set
*
writefds
,
fd_set
*
xfds
,
int
select_error
)
{
}
#endif
/* !CONFIG_SLIRP */
#endif
sysemu.h
浏览文件 @
952e849c
...
...
@@ -8,6 +8,7 @@
#include "qemu-timer.h"
#include "qapi-types.h"
#include "notify.h"
#include "main-loop.h"
/* vl.c */
...
...
@@ -64,8 +65,6 @@ void do_info_snapshots(Monitor *mon);
void
qemu_announce_self
(
void
);
int
main_loop_wait
(
int
nonblocking
);
bool
qemu_savevm_state_blocked
(
Monitor
*
mon
);
int
qemu_savevm_state_begin
(
Monitor
*
mon
,
QEMUFile
*
f
,
int
blk_enable
,
int
shared
);
...
...
vl.c
浏览文件 @
952e849c
...
...
@@ -148,6 +148,7 @@ int main(int argc, char **argv)
#include "qemu-objects.h"
#include "qemu-options.h"
#include "qmp-commands.h"
#include "main-loop.h"
#ifdef CONFIG_VIRTFS
#include "fsdev/qemu-fsdev.h"
#endif
...
...
@@ -1425,142 +1426,51 @@ void qemu_system_vmstop_request(RunState state)
qemu_notify_event
();
}
static
GPollFD
poll_fds
[
1024
*
2
];
/* this is probably overkill */
static
int
n_poll_fds
;
static
int
max_priority
;
qemu_irq
qemu_system_powerdown
;
static
void
glib_select_fill
(
int
*
max_fd
,
fd_set
*
rfds
,
fd_set
*
wfds
,
fd_set
*
xfds
,
struct
timeval
*
tv
)
static
bool
main_loop_should_exit
(
void
)
{
GMainContext
*
context
=
g_main_context_default
();
int
i
;
int
timeout
=
0
,
cur_timeout
;
g_main_context_prepare
(
context
,
&
max_priority
);
n_poll_fds
=
g_main_context_query
(
context
,
max_priority
,
&
timeout
,
poll_fds
,
ARRAY_SIZE
(
poll_fds
));
g_assert
(
n_poll_fds
<=
ARRAY_SIZE
(
poll_fds
));
for
(
i
=
0
;
i
<
n_poll_fds
;
i
++
)
{
GPollFD
*
p
=
&
poll_fds
[
i
];
if
((
p
->
events
&
G_IO_IN
))
{
FD_SET
(
p
->
fd
,
rfds
);
*
max_fd
=
MAX
(
*
max_fd
,
p
->
fd
);
}
if
((
p
->
events
&
G_IO_OUT
))
{
FD_SET
(
p
->
fd
,
wfds
);
*
max_fd
=
MAX
(
*
max_fd
,
p
->
fd
);
}
if
((
p
->
events
&
G_IO_ERR
))
{
FD_SET
(
p
->
fd
,
xfds
);
*
max_fd
=
MAX
(
*
max_fd
,
p
->
fd
);
RunState
r
;
if
(
qemu_debug_requested
())
{
vm_stop
(
RUN_STATE_DEBUG
);
}
if
(
qemu_shutdown_requested
())
{
qemu_kill_report
();
monitor_protocol_event
(
QEVENT_SHUTDOWN
,
NULL
);
if
(
no_shutdown
)
{
vm_stop
(
RUN_STATE_SHUTDOWN
);
}
else
{
return
true
;
}
}
cur_timeout
=
(
tv
->
tv_sec
*
1000
)
+
((
tv
->
tv_usec
+
500
)
/
1000
);
if
(
timeout
>=
0
&&
timeout
<
cur_timeout
)
{
tv
->
tv_sec
=
timeout
/
1000
;
tv
->
tv_usec
=
(
timeout
%
1000
)
*
1000
;
}
}
static
void
glib_select_poll
(
fd_set
*
rfds
,
fd_set
*
wfds
,
fd_set
*
xfds
,
bool
err
)
{
GMainContext
*
context
=
g_main_context_default
();
if
(
!
err
)
{
int
i
;
for
(
i
=
0
;
i
<
n_poll_fds
;
i
++
)
{
GPollFD
*
p
=
&
poll_fds
[
i
];
if
((
p
->
events
&
G_IO_IN
)
&&
FD_ISSET
(
p
->
fd
,
rfds
))
{
p
->
revents
|=
G_IO_IN
;
}
if
((
p
->
events
&
G_IO_OUT
)
&&
FD_ISSET
(
p
->
fd
,
wfds
))
{
p
->
revents
|=
G_IO_OUT
;
}
if
((
p
->
events
&
G_IO_ERR
)
&&
FD_ISSET
(
p
->
fd
,
xfds
))
{
p
->
revents
|=
G_IO_ERR
;
}
if
(
qemu_reset_requested
())
{
pause_all_vcpus
();
cpu_synchronize_all_states
();
qemu_system_reset
(
VMRESET_REPORT
);
resume_all_vcpus
();
if
(
runstate_check
(
RUN_STATE_INTERNAL_ERROR
)
||
runstate_check
(
RUN_STATE_SHUTDOWN
))
{
runstate_set
(
RUN_STATE_PAUSED
);
}
}
if
(
g_main_context_check
(
context
,
max_priority
,
poll_fds
,
n_poll_fds
))
{
g_main_context_dispatch
(
context
);
}
}
int
main_loop_wait
(
int
nonblocking
)
{
fd_set
rfds
,
wfds
,
xfds
;
int
ret
,
nfds
;
struct
timeval
tv
;
int
timeout
;
if
(
nonblocking
)
timeout
=
0
;
else
{
timeout
=
qemu_calculate_timeout
();
qemu_bh_update_timeout
(
&
timeout
);
}
os_host_main_loop_wait
(
&
timeout
);
tv
.
tv_sec
=
timeout
/
1000
;
tv
.
tv_usec
=
(
timeout
%
1000
)
*
1000
;
/* poll any events */
/* XXX: separate device handlers from system ones */
nfds
=
-
1
;
FD_ZERO
(
&
rfds
);
FD_ZERO
(
&
wfds
);
FD_ZERO
(
&
xfds
);
qemu_iohandler_fill
(
&
nfds
,
&
rfds
,
&
wfds
,
&
xfds
);
slirp_select_fill
(
&
nfds
,
&
rfds
,
&
wfds
,
&
xfds
);
glib_select_fill
(
&
nfds
,
&
rfds
,
&
wfds
,
&
xfds
,
&
tv
);
if
(
timeout
>
0
)
{
qemu_mutex_unlock_iothread
();
if
(
qemu_powerdown_requested
())
{
monitor_protocol_event
(
QEVENT_POWERDOWN
,
NULL
);
qemu_irq_raise
(
qemu_system_powerdown
);
}
ret
=
select
(
nfds
+
1
,
&
rfds
,
&
wfds
,
&
xfds
,
&
tv
);
if
(
timeout
>
0
)
{
qemu_mutex_lock_iothread
();
if
(
qemu_vmstop_requested
(
&
r
))
{
vm_stop
(
r
);
}
qemu_iohandler_poll
(
&
rfds
,
&
wfds
,
&
xfds
,
ret
);
slirp_select_poll
(
&
rfds
,
&
wfds
,
&
xfds
,
(
ret
<
0
));
glib_select_poll
(
&
rfds
,
&
wfds
,
&
xfds
,
(
ret
<
0
));
qemu_run_all_timers
();
/* Check bottom-halves last in case any of the earlier events triggered
them. */
qemu_bh_poll
();
return
ret
;
return
false
;
}
qemu_irq
qemu_system_powerdown
;
static
void
main_loop
(
void
)
{
bool
nonblocking
;
int
last_io
__attribute__
((
unused
))
=
0
;
int
last_io
=
0
;
#ifdef CONFIG_PROFILER
int64_t
ti
;
#endif
RunState
r
;
qemu_main_loop_start
();
for
(;;)
{
do
{
nonblocking
=
!
kvm_enabled
()
&&
last_io
>
0
;
#ifdef CONFIG_PROFILER
ti
=
profile_getclock
();
...
...
@@ -1569,38 +1479,7 @@ static void main_loop(void)
#ifdef CONFIG_PROFILER
dev_time
+=
profile_getclock
()
-
ti
;
#endif
if
(
qemu_debug_requested
())
{
vm_stop
(
RUN_STATE_DEBUG
);
}
if
(
qemu_shutdown_requested
())
{
qemu_kill_report
();
monitor_protocol_event
(
QEVENT_SHUTDOWN
,
NULL
);
if
(
no_shutdown
)
{
vm_stop
(
RUN_STATE_SHUTDOWN
);
}
else
break
;
}
if
(
qemu_reset_requested
())
{
pause_all_vcpus
();
cpu_synchronize_all_states
();
qemu_system_reset
(
VMRESET_REPORT
);
resume_all_vcpus
();
if
(
runstate_check
(
RUN_STATE_INTERNAL_ERROR
)
||
runstate_check
(
RUN_STATE_SHUTDOWN
))
{
runstate_set
(
RUN_STATE_PAUSED
);
}
}
if
(
qemu_powerdown_requested
())
{
monitor_protocol_event
(
QEVENT_POWERDOWN
,
NULL
);
qemu_irq_raise
(
qemu_system_powerdown
);
}
if
(
qemu_vmstop_requested
(
&
r
))
{
vm_stop
(
r
);
}
}
bdrv_close_all
();
pause_all_vcpus
();
}
while
(
!
main_loop_should_exit
());
}
static
void
version
(
void
)
...
...
@@ -2311,6 +2190,7 @@ int main(int argc, char **argv, char **envp)
runstate_init
();
init_clocks
();
rtc_clock
=
host_clock
;
qemu_cache_utils_init
(
envp
);
...
...
@@ -3298,6 +3178,7 @@ int main(int argc, char **argv, char **envp)
configure_accelerator
();
qemu_init_cpu_loop
();
if
(
qemu_init_main_loop
())
{
fprintf
(
stderr
,
"qemu_init_main_loop failed
\n
"
);
exit
(
1
);
...
...
@@ -3564,8 +3445,10 @@ int main(int argc, char **argv, char **envp)
os_setup_post
();
resume_all_vcpus
();
main_loop
();
quit_timers
();
bdrv_close_all
();
pause_all_vcpus
();
net_cleanup
();
res_free
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录