qemu启动流程
来源:互联网 发布:java.net.socket 编辑:程序博客网 时间:2024/05/11 17:13
1.主线程代码分析
主线程主要是监控各种需要处理的请求的句柄,然后等相关事件触发后,进行相关的处理。
下面是典型的主线程的调用栈,通过ppoll来监控事件。
(gdb) bt
#0 0x00007ffff618dd51 in ppoll () from /lib64/libc.so.6
#1 0x000055555580fdbc in ppoll (__ss=0x0, __timeout=0x7fffffffdb90,
__nfds=<optimized out>, __fds=<optimized out>)
at /usr/include/bits/poll2.h:77
#2 qemu_poll_ns (fds=<optimized out>, nfds=<optimized out>,
timeout=timeout@entry=46251116) at qemu-timer.c:322
#3 0x000055555580f594 in os_host_main_loop_wait (timeout=46251116)
at main-loop.c:238
#4 main_loop_wait (nonblocking=<optimized out>) at main-loop.c:493
#5 0x00005555555ea10e in main_loop () at vl.c:1808
#6 main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>)
at vl.c:4470
代码分析如下:
main -> main_loop()
main_loop判断是否有关闭,暂停的操作,如果没有,循环调用main_loop_wait进行监控。
static void main_loop(void)
{
bool nonblocking;
int last_io = 0;
do {
nonblocking = !kvm_enabled() && !xen_enabled() && last_io > 0;
last_io = main_loop_wait(nonblocking);
} while (!main_loop_should_exit());
}
main_loop_should_exit函数分析,判断是否有关闭,暂停的请求。
static bool main_loop_should_exit(void)
{
RunState r;
if (qemu_debug_requested()) {
vm_stop(RUN_STATE_DEBUG);
}
if (qemu_suspend_requested()) {
qemu_system_suspend();
}
if (qemu_shutdown_requested()) {
qemu_kill_report();
qapi_event_send_shutdown(&error_abort);
if (no_shutdown) {
vm_stop(RUN_STATE_SHUTDOWN);
} else {
return true;
}
}
if (qemu_reset_requested()) {
pause_all_vcpus();
主线程的poll是在监控哪些?
main_loop_wait中处理:
g_array_set_size(gpollfds, 0);
./iohandler.c中进行的调试。
qemu_iohandler_fill(gpollfds);
根据全局变量io_handlers进行填充。
void qemu_iohandler_fill(GArray *pollfds)
根据句柄轮询调用之间的处理函数。
qemu_iohandler_poll(gpollfds, ret);
GArray *pollfds
void qemu_iohandler_fill(GArray *pollfds)
{
IOHandlerRecord *ioh;
QLIST_FOREACH(ioh, &io_handlers, next) {
int events = 0;
if (ioh->deleted)
continue;
if (ioh->fd_read) {
events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
}
if (ioh->fd_write) {
events |= G_IO_OUT | G_IO_ERR;
}
if (events) {
GPollFD pfd = {
.fd = ioh->fd,
.events = events,
};
ioh->pollfds_idx = pollfds->len;
g_array_append_val(pollfds, pfd);
} else {
ioh->pollfds_idx = -1;
}
}
}
typedef struct IOHandlerRecord {
IOHandler *fd_read;
IOHandler *fd_write;
void *opaque;
QLIST_ENTRY(IOHandlerRecord) next;
int fd;
int pollfds_idx;
bool deleted;
} IOHandlerRecord;
注册监控句柄的接口函数。
void qemu_set_fd_handler(int fd,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque)
2. VCPU线程分析
qemu针对每一个vcpu单独创建一个线程,循环调用ioctl。
调用栈:
(gdb) bt
#0 0x00007f1e257b7407 in ioctl () from /lib64/libc.so.6
#1 0x00007f1e276f94f4 in kvm_vcpu_ioctl (cpu=cpu@entry=0x7f1e29f8bb30,
type=type@entry=44672) at /home/jemmy/develop/qemu/kvm-all.c:1916
#2 0x00007f1e276f95ae in kvm_cpu_exec (cpu=cpu@entry=0x7f1e29f8bb30)
at /home/jemmy/develop/qemu/kvm-all.c:1775
#3 0x00007f1e276e732a in qemu_kvm_cpu_thread_fn (arg=0x7f1e29f8bb30)
at /home/jemmy/develop/qemu/cpus.c:976
#4 0x00007f1e25a8552a in start_thread () from /lib64/libpthread.so.0
#5 0x00007f1e257c122d in clone () from /lib64/libc.so.6
代码分析如下:
int kvm_cpu_exec(CPUState *cpu)
do {
MemTxAttrs attrs;
if (cpu->kvm_vcpu_dirty) {
kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE);
cpu->kvm_vcpu_dirty = false;
}
kvm_arch_pre_run(cpu, run);
if (cpu->exit_request) {
DPRINTF("interrupt exit requested\n");
/*
* KVM requires us to reenter the kernel after IO exits to complete
* instruction emulation. This self-signal will ensure that we
* leave ASAP again.
*/
qemu_cpu_kick_self();
}
qemu_mutex_unlock_iothread();
run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);
qemu_mutex_lock_iothread();
attrs = kvm_arch_post_run(cpu, run);
trace_kvm_run_exit(cpu->cpu_index, run->exit_reason);
switch (run->exit_reason) { //根据推出原因,进行相关的处理。
case KVM_EXIT_IO:
DPRINTF("handle_io\n");
kvm_handle_io(run->io.port, attrs,
(uint8_t *)run + run->io.data_offset,
run->io.direction,
run->io.size,
run->io.count);
ret = 0;
break;
case KVM_EXIT_MMIO:
DPRINTF("handle_mmio\n");
address_space_rw(&address_space_memory,
run->mmio.phys_addr, attrs,
run->mmio.data,
run->mmio.len,
run->mmio.is_write);
ret = 0;
break;
简单以address_space_rw为例,进行调试,调用栈如下:
(gdb) b address_space_rw
Breakpoint 1 at 0x7f1e276c5dd0: file /home/jemmy/develop/qemu/exec.c, line 2317.
(gdb) c
Continuing.
[Switching to Thread 0x7f1e24ad9700 (LWP 25581)]
Breakpoint 1, address_space_rw (as=0x7f1e27daef40 <address_space_io>,
addr=addr@entry=112, attrs=attrs@entry=...,
buf=0x7f1e2761c000 "\217\200\377\377", len=len@entry=1,
is_write=is_write@entry=true) at /home/jemmy/develop/qemu/exec.c:2317
2317 {
(gdb) bt
#0 address_space_rw (as=0x7f1e27daef40 <address_space_io>,
addr=addr@entry=112, attrs=attrs@entry=...,
buf=0x7f1e2761c000 "\217\200\377\377", len=len@entry=1,
is_write=is_write@entry=true) at /home/jemmy/develop/qemu/exec.c:2317
#1 0x00007f1e276f9805 in kvm_handle_io (count=1, size=1,
direction=<optimized out>, data=<optimized out>, attrs=..., port=112)
at /home/jemmy/develop/qemu/kvm-all.c:1636
#2 kvm_cpu_exec (cpu=cpu@entry=0x7f1e29f8bb30)
at /home/jemmy/develop/qemu/kvm-all.c:1804
#3 0x00007f1e276e732a in qemu_kvm_cpu_thread_fn (arg=0x7f1e29f8bb30)
at /home/jemmy/develop/qemu/cpus.c:976
#4 0x00007f1e25a8552a in start_thread () from /lib64/libpthread.so.0
#5 0x00007f1e257c122d in clone () from /lib64/libc.so.6
3.VNC线程分析:
(gdb) bt
#0 0x00007f1e25a8a590 in pthread_cond_wait@@GLIBC_2.3.2 ()
from /lib64/libpthread.so.0
#1 0x00007f1e2794af19 in qemu_cond_wait (cond=cond@entry=0x7f1e2ad81150,
mutex=mutex@entry=0x7f1e2ad81180) at util/qemu-thread-posix.c:132
#2 0x00007f1e278d7823 in vnc_worker_thread_loop (
queue=queue@entry=0x7f1e2ad81150) at ui/vnc-jobs.c:222
#3 0x00007f1e278d7c08 in vnc_worker_thread (arg=0x7f1e2ad81150)
at ui/vnc-jobs.c:323
#4 0x00007f1e25a8552a in start_thread () from /lib64/libpthread.so.0
#5 0x00007f1e257c122d in clone () from /lib64/libc.so.6
疑问:其余的线程是什么作用?在哪里进行的创建?
(gdb) bt
#0 0x00007f1e257bb939 in syscall () from /lib64/libc.so.6
#1 0x00007f1e2794b211 in futex_wait (val=4294967295,
ev=0x7f1e2823ccc4 <rcu_call_ready_event>) at util/qemu-thread-posix.c:301
#2 qemu_event_wait (ev=ev@entry=0x7f1e2823ccc4 <rcu_call_ready_event>)
at util/qemu-thread-posix.c:399
#3 0x00007f1e279598f6 in call_rcu_thread (opaque=<optimized out>)
at util/rcu.c:233
#4 0x00007f1e25a8552a in start_thread () from /lib64/libpthread.so.0
#5 0x00007f1e257c122d in clone () from /lib64/libc.so.6
- qemu启动流程
- qemu执行流程分析
- QEMU执行流程
- qemu启动虚拟机
- QEMU-KVM无法启动
- qemu-kvm启动脚本
- qemu 启动虚拟机 sheepdog
- qemu利用uboot启动
- qemu中启动versatilepb,qemu挂起问题解决
- qemu-kvm savevm/loadvm 流程
- QEMU ARM异常处理流程
- QEMU(Centos7)环境搭建流程
- qemu busybox模拟Linux启动
- qemu启动参数代码分析
- qemu网络启动模式配置
- 8.3 Qemu启动参数管理
- qemu启动Busybox和内核
- QEMU命令行参数启动虚拟机
- 外观模式(Facade)
- 可变集合NSMutableSet的常用的功能
- 【SuperMap .Net 组件】二维线转三维线
- Linux基础(三)常用命令2
- 一般处理程序中Session的用法
- qemu启动流程
- iPhone/iOS开启个人热点的纵向适配小结
- 后海日记(9)
- 如何利用开发者账号重签ipa文件,并部署到IOS设备做测试搜索
- “error LNK1169: 找到一个或多个多重定义的符号”的解决方法
- C库-----字符串(string)与整型(int)、浮点型(float)等之间的转换
- SAT数学:计算器的准备
- RTTI symbol not found for class 'QWidget'
- GC微调实践