xen事件通道机制及其实例

来源:互联网 发布:mysql存放byteImage 编辑:程序博客网 时间:2024/05/16 17:44
    事件通道机制是xen用于Domain和Xen之间,或者Domain和Domain之间的异步事件通知机制。事件通道在xen中应用非常广泛,像物理中断,虚拟中断以及域间通信等均是通过事件通道实现的。
    根据用途划分,事件通道一般分为四类:域间通信,域内通信,虚拟中断,物理中断。域间通信主要用于Domain与Domain之间通信,或者Xen与Domain之间通信。域内通信就是同一个域内不同VCPU之间通信。物理中断与虚拟中断都是绑定中断源,实现Xen的中断。
    Xen在内核态和用户态代码中都封装了很多事件通道相关的操作函数,像分配通道,绑定通道,置pending位等,如果需要可以自己研究源码。『Xen虚拟化技术(石磊 邹得清 金海)』一书中对事件通道的原理,函数,数据结构讲解的比较全面,可以参考。
    我这里主要是简单讲一下我自己实现的Domain0与Xen进行通信的例子。

    因为项目需要,我需要实现Xen给Domain0发送事件通知,Domain0收到事件通知后就执行某些操作。这里使用域间通信来实现,大概的流程就是Xen内核态代码中先为Domain0分配一个事件通道端口,用户态通过超级调用获取这个事件通道,并进行通道绑定。然后用户态陷入循环等待中,等待Xen内核发来事件通知,收到通知后就执行预先写好的那部分代码。

具体代码:
内核态分配通道端口:
//save_domid这里指定为0int event_channel_port=alloc_unbound_xen_event_channel(current, save_domid, NULL);

内核态分配了端口后,传到用户态,即event_channel_port。
用户态进行绑定:
xc_evtchn *xc_event_iface = xc_evtchn_open(NULL,0);if(!xc_event_iface){    PERROR("Could not open interface to libxc event channels");}int event_port = xc_evtchn_bind_interdomain(xc_event_iface, DOMID_SELF, event_channel_port);if(event_port != -1){    PERROR("event_port is: %d",event_port);}else{    PERROR("Could not bind xen port to local port");}


用户态绑定后,可以设置一个循环等待事件通知的到来,当然根据自己的需求进行修改。

while(1){    int pending_port = xc_evtchn_pending(xc_event_iface);    if(pending_port == event_port)//收到事件通知    {if(xc_evtchn_unmask(xc_event_iface, event_port) == -1){perror("Could not unmask event port in loop");break;}//下面就是自定义的收到事件通知后的处理代码        //。。。。。。。。。        。        。        。        。    }    else    {PERROR("Unknown event port pending: %d", pending_port);    }}//end while//事件通道使用完了后进行解绑释放xc_evtchn_unbind(xc_event_iface, event_port);xc_evtchn_close(xc_event_iface);free(xc_event_iface);

内核态发送通知代码如下:
void notify_via_specific_xen_event_channel(struct domain *ld, int lport){    struct evtchn *lchn, *rchn;    struct domain *rd;    int            rport;    spin_lock(&ld->event_lock);    if ( unlikely(ld->is_dying) )    {        spin_unlock(&ld->event_lock);        return;    }    ASSERT(port_is_valid(ld, lport));    lchn = evtchn_from_port(ld, lport);//bind local event channel    ASSERT(consumer_is_xen(lchn));    if ( likely(lchn->state == ECS_INTERDOMAIN) )    {        rd    = lchn->u.interdomain.remote_dom;        rport = lchn->u.interdomain.remote_port;        rchn  = evtchn_from_port(rd, rport);        evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);    }    spin_unlock(&ld->event_lock);}void notify_domu_before_page_modify(void){    struct domain *ld;    ld = rcu_lock_domain_by_id(save_domid);    notify_via_specific_xen_event_channel(ld,event_channel_port);    rcu_unlock_domain(ld);}notify_domu_before_page_modify();


    这样,Xen就可以向Domain0发送事件通知了。
0 0