Qemu事件处理机制简介
Qmeu 采用了基于事件驱动的架构,所有的事件都在一个事件循环(event loop)中被处理,系统中默认的事件循环是在main-loop.c 中的主循环(main loop)。我们也可以使用 –object iothread,id=my-iothread自己创建事件循环。
Qemu 中的事件架构来源于glib,其实qemu本身就是基于glib的,qemu中有大量的概念来源于glib,所以在学习qemu之前先了解一下glib有助于更快的理解qemu。下面首先介绍一下glib中的事件机制。
Glib 中的事件处理
Glib中是由一个主事件循环(main event loop)来负责处理所有的事件源(source),事件源包括文件描述符(纯文件、管道或者socket)和超时。新的事件源可以通过 g_source_attach()来添加。为了实现在不同的线程中处理多个、独立的事件源,每一个事件源都关联一个主上下文GMainContext的数据结构。一个GMainContex只能在一个线程中运行,但不同线程中的事件源可以互相添加或删除。GMainContext中的事件源会在GMainContext关联的主事件循环中进行检查和发送(dispatch)。
新的事件源类型可以通过包含GSource结构体来创建。新的事件源类型中GSource结构体必须是第一个成员,其他成员放在其后。要创建一个新事件源类型实例,可以调用g_source_new()函数,传入新的事件源类型大小和一个GSourceFuncs类型的变量,这个变量决定了新的事件源类型的控制方式。
新的事件源通过两种方式跟主上下文交互。第一种方式是GSourceFuncs中的prepare函数可以设置一个超时时间,来决定主事件循环中轮询的超时时间;第二种方式是通过g_source_add_poll()函数来添加文件描述符。
主上下文的一次循环包含四个步骤,分别由四个函数实现:g_main_context_prepare(), g_main_context_query(), g_main_context_check() 和 g_main_context_dispatch(),其状态转换图如下:

下面分别简单介绍一下这四个函数的作用:
- g_main_context_prepare():对于没有设置G_SOURCE_READY标志的source,调用source->source_funcs->prepare函数,如果返回TRUE,则设置source的G_SOURCE_READY;调用prepare函数时会通过参数返回一个超时时间,选取最小的一个超时时间赋值给context->timeout。
- g_main_context_query():从context->poll_records中返回指定个数的fd,返回 context->timeout,context->poll_changed设为FALSE.
- g_main_context_check():如果context->poll_changed 为TRUE,则返回FALSE;否则复制传入的fds的revents到相应的 context->poll_records->fd->revents中;遍历所有的source,对未设置 G_SOURCE_READY 标志的source调用其 check 函数;将已经设置 G_SOURCE_READY 标志的source 添加到 context->pending_dispatches中;
- g_main_context_dispatch():清除 context->pending_dispatches 中 source 的 G_SOURCE_READY 标志,然后调用其 dispatch 函数;
上面就是整个事件的处理流程,我们需要做的就是把新的source加入到这个处理流程中,glib会负责处理source上注册的各种事件源。Glib中有两个添加函数,分别实现将source 加入到GMaincontext和将fd加入到source的功能:
- g_source_attach(): 将 source->poll_fds中的文件描述符加入到 context->poll_records中;source添加到 context 的source 链表中;
- g_source_add_poll(): 将 fd 加入到 source->poll_fds中,然后再加入到 context->poll_records中,设置 context->poll_changed 为 TRUE.
Qemu 中的事件处理
下面介绍一下qemu 是如何使用这一套事件处理流程的。Qemu是基于glib 开发的,继承了很多glib的概念,struct AioContext 就是按照 glib 的source 创建原则新建的一个事件源类型,用来处理信号,中断等事件,其内容如下:
struct AioContext {
GSource source;
RFifoLock lock;
QLIST_HEAD(, AioHandler) aio_handlers;
int walking_handlers;
uint32_t notify_me;
QemuMutex bh_lock;
struct QEMUBH *first_bh;
int walking_bh;
bool notified;
EventNotifier notifier;
QEMUBH *notify_dummy_bh;
struct ThreadPool *thread_pool;
QEMUTimerListGroup tlg;
int external_disable_cnt;
int epollfd;
bool epoll_enabled;
bool epoll_available;
};
AioContext 拓展了glib 中source的功能,不但支持fd、超时的轮询,还模拟内核中的下半部机制实现了事件的异步通知功能,其中的通知功能是基于 eventfd 实现的。
AioContext 本质上还是一个 source,我们在上文中提到,source有一个很重要的成员 GSourceFuncs,它控制着source在主上下文中的控制方式。AioContext 的 GSourceFuncs 定义如下:
static GSourceFuncs aio_source_funcs = {
aio_ctx_prepare,
aio_ctx_check,
aio_ctx_dispatch,
aio_ctx_finalize
};
这几个函数分别在g_main_context_prepare(), g_main_context_check() 和 g_main_context_dispatch() 中被调用。下面分别介绍一下这几个函数的主要功能:
- aio_ctx_prepare 会调用 aio_compute_timeout 来计算需要的超时时间,这个超时时间是在轮询过程中使用的,它是由 AioContext 中注册的bh的属性决定的,当AioContext 中注册的所有的bh 都是空闲的时,则返回一个有效的超时时间;当至少有一个bh不是空闲的时,则返回0,从而保证bh会被尽快执行。
struct QEMUBH {
AioContext *ctx;
QEMUBHFunc *cb;
void *opaque;
QEMUBH *next;
bool scheduled;
bool idle;
bool deleted;
};
2. aio_ctx_check 用来检查如果bh、fd或timer存在就绪,则返回TRUE,从而调用 g_main_context_dispatch()
3. aio_ctx_dispatch 调用aio_dispatch,依次执行就绪的bh、fd和timer,完成依次主循环。
qemu会在初始化的过程中通过g_source_new 函数把 aio_source_funcs 注册到AioContext。
Qemu中常用的 AioContext 实例有四个, qemu_aio_context, iohandler->ctx,iothread 中的AioContext,描述磁盘镜像的BlockDriverState 中的 AioContext。他们负责处理的事件分别是:
- Qemu_aio_context: VNC,QMP 命令
- Iohandler->ctx:负责监控信号,中断,事件通知,socket等;
- Iothread->ctx:主要负责io方面的监控;
- Bs->ctx:负责blockjob等相关任务的监控
Qemu在初始化的过程中用 g_source_attach 函数把 qemu_aio_context和iohandler->ctx 添加到主循环。
新建qemu事件处理循环
上面是qemu效仿glib 实现的主循环,但主循环存在一些缺陷,比如在主机使用多CPU的情况下伸缩性受到限制,同时主循环使用了qemu全局互斥锁,从而导致vCPU线程和主循环存在锁竞争,导致性能下降。为了解决这个问题,qemu引入了iothread 事件循环,把一些IO操作分配给iothread,从而提高IO性能。
Iothread的创建方式是在qemu启动的时候传入–object iothread,id=my-iothread参数。在iothread线程中循环执行aio_poll,这个函数简化了glib的事件循环,只要存在就绪的fd就执行aio_dispatch,从而执行就绪的bh、fd和timer。
参考:
- Qemu/docs/multiple-iothreads.txt
- https://developer.gnome.org/glib/2.46/glib-The-Main-Event-Loop.html
Qemu事件处理机制简介的更多相关文章
- 【3】【MOOC】Python游戏开发入门-北京理工大学【第三部分-游戏开发之机制(事件处理机制)】
学习地址链接:http://www.icourse163.org/course/0809BIT021E-1001873001?utm_campaign=share&utm_medium=and ...
- Qt事件处理机制
研一的时候开始使用Qt,感觉用Qt开发图形界面比MFC的一套框架来方便的多.后来由于项目的需要,也没有再接触Qt了.现在要重新拾起来,于是要从基础学起. Now,开始学习Qt事件处理机制. 先给出原文 ...
- Qt 事件处理机制
Qt 事件处理机制 因为这篇文章写得特别好,将Qt的事件处理机制能够阐述的清晰有条理,并且便于学习.于是就装载过来了(本文做了排版,并删减了一些冗余的东西,希望原主勿怪),以供学习之用. 简介 在Qt ...
- QT开发(十二)——QT事件处理机制
一.QT事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下和松开 ...
- Qt之事件处理机制
思维导读 一.事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下 ...
- Android休眠唤醒机制简介(二)
本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408911 Android休眠唤醒机制简介(二)************* ...
- Cocos2d-x之事件处理机制
| 版权声明:本文为博主原创文章,未经博主允许不得转载. 事件处理机制分为单点触屏,多点触屏,加速度事件,键盘事件和鼠标事件.在现在的智能手机中,触屏的应用比较的广泛,尤其是多点触屏事件的技术,使 ...
- java 事件处理机制:按下上下左右键控制小球的运动
/** * 加深对事件处理机制的理解 * 通过上下左右键来控制一个小球的位置 */package com.test3;import java.awt.*;import javax.swing.*;im ...
- Android事件处理机制
包括监听和回调两种机制. 1. 基于监听的事件处理: 事件监听包含三类对象,事件源,事件,事件监听器.Android的事件处理机制是一种委派式(Delegation)事件处理方式:普通组件(事件源)将 ...
随机推荐
- hdu 5150(水题)
Sum Sum Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- 代码编辑器[0] -> Vim/gVim[0] -> 基于 Python 的 gVim 环境配置(Windows)
环境配置 / Environment Setup 基于Python开发的 gVim 环境配置(Windows) 使用方式参考 Vim 的使用. 1 基于vundle进行配置 Vim有多个扩展管理器, ...
- 线段树【p2801】教主的魔法
Description 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.--.N. 每个人的 ...
- POJ 2135 Farm Tour (费用流)
[题目链接] http://poj.org/problem?id=2135 [题目大意] 有一张无向图,求从1到n然后又回来的最短路 同一条路只能走一次 [题解] 题目等价于求从1到n的两条路,使得两 ...
- 六. 异常处理4.try和catch的使用
尽管由Java运行时系统提供的默认异常处理程序对于调试是很有用的,但通常你希望自己处理异常.这样做有两个好处.第一,它允许你修正错误.第二,它防止程序自动终止.大多数用户对于在程序终止运行和在无论何时 ...
- linux命令详解:df命令
转:http://www.cnblogs.com/lwgdream/p/3413579.html 前言 df命令用来查看系统的space和inode使用情况,也是常用命令之一 使用说明 -a 显示所有 ...
- cocurrent包ExecutorService线程池
16. 执行器服务 ExecutorService java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务.因此一个 Execut ...
- IdHTTPServer(indy10)开发REST中间件
IdHTTPServer(indy10)开发REST中间件 浏览器通过“get”方式查询数据URL样例:http://127.0.0.1:7777/query?sql=select * from t1 ...
- 开源 ≠ 免费,开源协议License详解
凡是做过软件开发的,都会接触到开源软件或开源组件,它们都会基于某种协议来提供源码和授权,那么这些开源协议到底有哪些约束呢? 在介绍之前,必须告诉大家,针对开源协议,必须打消“开源 = 免费”这个念头, ...
- 图文介绍openLDAP在windows上的安装配置
目录 概述 测试环境 安装过程 配置启动 客户端介绍 多级DC的ldif文件的配置 [一].概述 什么叫LDAP呢,概念的东西这里就不多讲了,网上搜索下有很多,本文的重点是介绍如何在windows平台 ...