Qemu-KVM Guest OS Time Tick Source(2)

上一篇文章已经讨论过了在有内核模拟时钟情况下,kvm是如何给guest OS提供时钟源的。

后面,我对Linux时间子系统做了一定的研究,体现在博文[Timer学习]系列,为了进一步加

深理解,我就想,能不能把没有内核模拟时钟时,即原来Qemu用户空间模拟时钟的机制搞

清楚。通过研究qemu-kvm-0.12.3代码,有了一定的认识,下面总结一下。

 
还是先来看一下Qemu 用户态 模拟时钟是从哪里开始初始化的。代码路径如下图所示,在main
中调用init_timer_alarm开始。 还是那句话,Qemu模拟时钟是软件的,不能像硬件时钟那样自
己产生时钟计数,所以必须要求 助于host的各种timer服务来提供实际时钟。Qemu在vl.c定义了
一个全局数组alarm_timers[],里 面定义了几种host timer服务的封装实例,有dynticks, hpet, rtc。
这三种timer服务是Linux内核提 供给用户程序使用的。下面看Qemu是如何具体利用这些服务的,
就能有更深的认识了。
 
如果是选用dynticks,那么在init_timer_alarm中调用t->start即dynticks_start_timer。dynticks_start_timer 首先用sigaction注册SIGALARM信号的handler为host_alarm_handler,然后调用timer_create创建一个
时钟。这就很清楚了,timer_create实际上就属于Posix Timer API。应用程序创建了一个Posix Timer后,
一旦timer到期,那么内核将给调用进程发送一个SIGALARM信号,应用进程通过signal handler再去做处理。
 
QEMU timer emulation path:

main(vl.c) ---> init_timer_alarm(vl.c) ---> dynticks_start_timer ---> sigaction(SIGALARM, host_alarm_handler)

 --> timer_create(or ---> hpet_start_timer ---> open(/dev/hpet) ---> enable_sigio_timer --> sigaction(SIGIO, host_alarm_handler)

 
刚开始仔细一想发现不对了,在内核模拟时钟时,是调用hrtimer_init和hrtimer_start来初始化hrtimer,并且
可以指定一个回调函数,一旦hrtimer到期,内核会调用回调函数,为什么这里不能这样,而只是发送一个信
号呢? 其实问题很简单,内核调用回调函数是在内核空间调用,所以内核模拟时钟可以注册回调函数。但是,
提供给用户程序的timer API当然不能让用户程序直接注册回调函数,不然启不是允许用户函数到时可以在内核
态下运行了?因此,对于用户程序,当timer到期后,只能是发送一个信号给用户进程,进程实际上用回调函数
注册为signal handler。
 
Posix Timer是怎样实现的呢?在hrtimer.txt中说了,Posix Timer是基于hrtimer机制实现的,我想大概是这样的:
用户进程调用timer_create创建Posix Timer,实际上内核用调用hrtimer_init初始化一个hrtimer,当hrtimer到期时,
内核执行其回调函数,回调函数将会发送一个SIGALARM给用户进程。
 
结合以上论述,当dynticks timer到期后,内核发送一个SIGALARM信号给Qemu进程,之前介绍过,Qemu进程
block了SIGALARM信号,信号是由创建的signalfd去接受;之后,io thread用select检测到signalfd read ready,
然后就调用sigfd_handler;sigfd_handler根据signal number,调用相应的handler,就是之前用sigaction注册过的
host_alarm_handler。
 
可以看出,dynticks实际上是内核提供的软件timer服务,那么hpet和rtc又是怎样的呢?通过研究hpet_start_timer,
发现原来这里是直接去调用hpet driver,使hpet硬件直接产生一个Qemu需要的时钟源。当hpet timer到期时,hpet
硬件发送一个interrupt给host,host hpet driver handler发现这个中断是由Qemu进程"引起"的,所以发送一个SIGIO
信号给Qemu进程。同样,在hpet_start_timer调用的enable_sigio_timer函数中用sigaction注册host_alarm_handler
为SIGIO信号的handler。rtc也跟hpet是一样的,实际上是去调用rtc driver,不用多讲了。
 
因此,可以发现dynticks是利用软件timer提供时钟计数,而hpet和rtc是直接利用硬件提供时钟计数。现在可以总结
一下Linux下的各种timer服务了:
 
首先,内核态程序可以直接使用hrtimer API来使用timer,可以到期时可直接执行回调函数。至于hrtimer可以使利用
hpet,也可以是利用local APIC timer去实现的。
 
其次,用户态程序可以有三大类timer服务——第一类是,nanosleep()、sleep()这样的系统调用,内核
实际上在内核创建一个临时的timer,当到期时将用户进程唤醒;第二类是,Posix Timer API,内核实现
上是用hrtimer来实现Posix Timer的,当到期时将发送一个SIGALARM信号给用户进程;第三类是,
/dev/hpet和/dev/rtc,即直接利用硬件timer,因为这些硬件timer可以支持很多个不同频率的timer,所以
用户进程可以直接使用其中的一个,当到期时内核将发送SIGIO信号给应用进程。
 
最后说一下,这里还有个重要问题没有讨论,就是Qemu用户态模拟时钟如何将产生一个虚拟时钟中断,将其最后
注入到guest里面去。这就要从host_alarm_handler开始研究,以后再总结吧!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值