IO thread源码浅析之main loop

1260阅读 0评论2014-04-21 embeddedlwp
分类:LINUX

IO thread初始化

Qemu IO thread初始化函数位于main-loop.c:

[cpp] view plaincopy
  1. int qemu_init_main_loop(void)  
  2. {  
  3.     int ret;  
  4.     GSource *src;  
  5.   
  6.     init_clocks();  
  7.     if (init_timer_alarm() < 0) {  
  8.         fprintf(stderr, "could not initialize alarm timer\n");  
  9.         exit(1);  
  10.     }  
  11.   
  12.     ret = qemu_signal_init();  
  13.     if (ret) {  
  14.         return ret;  
  15.     }  
  16.   
  17.     qemu_aio_context = aio_context_new();  
  18.     src = aio_get_g_source(qemu_aio_context);  
  19.     g_source_attach(src, NULL);  
  20.     g_source_unref(src);  
  21.     return 0;  

IO thread主函数

Qemu IO thread的主函数也位于main-loop.c,  主要考虑到跨平台性,使用select和g_poll轮询系统的IO描述符,并根据测试结果调用相应的回调函数。

Qemu中IO的有些回调函数函数是分上部和下部的,该机制在Linux内核中被广泛使用,主要是为了提高事件相应的及时性。

Qemu中常用的IO描述符有下面几类:

该函数同时还负责轮询系统中所有的定时器,并调用定时器的回调函数;

 

[cpp] view plaincopy
  1. int main_loop_wait(int nonblocking)  
  2. {  
  3.     int ret;  
  4.     uint32_t timeout = UINT32_MAX;  
  5.   
  6.     if (nonblocking) {  
  7.         timeout = 0;  
  8.     }  
  9.   
  10.     /* poll any events */  
  11.     /* XXX: separate device handlers from system ones */  
  12.     nfds = -1;  
  13.     FD_ZERO(&rfds);  
  14.     FD_ZERO(&wfds);  
  15.     FD_ZERO(&xfds);  
  16.   
  17. #ifdef CONFIG_SLIRP  
  18.     slirp_update_timeout(&timeout);  
  19.     slirp_select_fill(&nfds, &rfds, &wfds, &xfds);  
  20. #endif  
  21.     qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);  
  22.     ret = os_host_main_loop_wait(timeout);  
  23.     qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);  
  24. #ifdef CONFIG_SLIRP  
  25.     slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));  
  26. #endif  
  27.   
  28.     qemu_run_all_timers();  
  29.   
  30.     return ret;  
  31. }  

slirp(user mode networking)

在KVM环境中,为了提高网络的性能一般虚拟机使用vhost-net, 所以slirp基本没有太多实际用途,也建议在编译配置qemu-kvm的时候,使用--disable-slirp将其禁止掉。关于slirp的介绍,可以看一下http://wiki.qemu.org/Documentation/Networking

IO Handler

用来表示一个IO描述符,其结构定义如下;iohandler.c中定义了一个全局的链表io_handlers,并提供qemu_set_fd_handler()和qemu_set_fd_handler2()函数将一个fd加入到这个链表; 在IO thread主循环中qemu_iohandler_fill()函数负责将io_handlers链表中的所有描述符,加入select测试集合。

[cpp] view plaincopy
  1. typedef struct IOHandlerRecord {  
  2.     IOCanReadHandler *fd_read_poll;  
  3.     IOHandler *fd_read;  
  4.     IOHandler *fd_write;  
  5.     void *opaque;  
  6.     QLIST_ENTRY(IOHandlerRecord) next;  
  7.     int fd;  
  8.     bool deleted;  
  9. } IOHandlerRecord;  
  10.   
  11. static QLIST_HEAD(, IOHandlerRecord) io_handlers =  
  12.     QLIST_HEAD_INITIALIZER(io_handlers);  

AIO Handler

Qemu中的aio主要用于block io, 从而可以提高虚拟磁盘读写的性能。Qemu使用g_poll轮询测试AIO描述符;g_poll是glib的函数,使用方法可以参考GMainLoop的实现原理和代码模型以及glib GMainLoop的手册;

aio_set_fd_handler()用于将一个AioHandler的描述符加入g_poll集合。

[cpp] view plaincopy
  1. typedef struct AioContext {  
  2.     GSource source;  
  3.   
  4.     /* The list of registered AIO handlers */  
  5.     QLIST_HEAD(, AioHandler) aio_handlers;  
  6.   
  7.     /* This is a simple lock used to protect the aio_handlers list. 
  8.      * Specifically, it's used to ensure that no callbacks are removed while 
  9.      * we're walking and dispatching callbacks. 
  10.      */  
  11.     int walking_handlers;  
  12.   
  13.     /* Anchor of the list of Bottom Halves belonging to the context */  
  14.     struct QEMUBH *first_bh;  
  15.   
  16.     /* A simple lock used to protect the first_bh list, and ensure that 
  17.      * no callbacks are removed while we're walking and dispatching callbacks. 
  18.      */  
  19.     int walking_bh;  
  20.   
  21.     /* Used for aio_notify.  */  
  22.     EventNotifier notifier;  
  23. } AioContext;  
  24.   
  25. struct AioHandler {   
  26.     EventNotifier *e;   
  27.     EventNotifierHandler *io_notify;   
  28.     AioFlushEventNotifierHandler *io_flush;   
  29.     GPollFD pfd; int deleted;   
  30.     QLIST_ENTRY(AioHandler) node;  
  31. };  

IO thread同步

Qemu IO thread和vcpu thread使用一个全局共享线程锁来保证同步,函数qemu_mutex_lock_iothread()和qemu_mutex_unlock_iothread()分别用来获取和释放该锁;

当vcpu thread从guest模式退出到host模式的时候,vcpu thread会尝试取得该锁;而IO thread在主循环中,也会不断尝试取得该锁;

思考

上一篇:qemu-kvm io线程
下一篇: KVM虚拟机代码揭秘——QEMU的PCI总线与设备