关闭

spice-client 源码解析之event_sources_p.cpp

24人阅读 评论(0) 收藏 举报
分类:

这个函数是用来对event进行处理的函数,通过一系列的函数获取event的flag以及文件描述符,并对event执行创建和删除工作。

首先,补充这部分涉及到的I/O知识:

1.I/O阻塞模式
通常IO操作都是阻塞I/O的,也就是说当你调用read时,如果没有数据收到,那么线程或者进程就会被挂起,直到收到数据,再进行进行读写操作。应用的函数进行调用,但是内核一直没有返回,就一直等着。应用的函数长时间处于等待结果的状态,我们就称为阻塞I/O。

2.I/O非阻塞模式
调用一个I/O操作的时候,会等待数据,如果没有数据过来,就即刻返回一个error。这样就不会有线程的阻塞,但是需要一直采用轮询的方式查询操作。这个轮询过程是很浪费时间的。

3.I/O的多路复用
多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,spice中使用了select()函数,一次性地传入多个文件描述符fd,如果有一个文件描述符就绪,则返回,否则阻塞直到超时一但得到就绪状态后就进行真正的操作。

然后就是代码部分啦

void EventSources_p::add_event(int fd, EventSource* source)
void EventSources_p::remove_event(EventSource* source)
bool EventSources::wait_events(int timeout_msec)

通过使用以上三个函数进行event的添加,删除以及轮询操作;

1.wait_events(int timeout_msec)
1.1 设置等待时间:timeout_msec;
1.2 调用系统函数FD_ZERO(&rfds):清空文件描述符,这里每次使用完内存如果没有释放的话,再次使用的数据就有可能出错,所以旧的数据进行清空;
1.3 调用ready = ::select(maxfd+1, &rfds, NULL, NULL, tvp):spice使用这个函数进行事件的轮询;
轮询结果:
(1).wait error select failed :并没有数据可以处理
(2).if (FD_ISSET(_fds[i], &rfds)) {
_events[i]->action();
return false;
}//该事件可以处理,需要判断是否已经在执行了

如果对象已经在执行了:return false;
如果对象未被执行:使用如下代码添加对象到执行队列,并创建pipe;
调用set_non_blocking(_event_fd)使能非阻塞I/O;

void EventSources::add_trigger(Trigger& trigger)
EventSources::Trigger::Trigger()

当对象结束执行,调用:

void EventSources::remove_trigger(Trigger& trigger)

2.add_event(int fd, EventSource* source)
重新定义事件队列大小,并将event装入_event[size],_fds[size]中装入对应的文件描述符;

3.remove_event(EventSource* source)
清空event和fds;

当然,2和3过程还涉及到了,socket和fd的添加,event的重置等;

void EventSources::add_socket(Socket& socket)
{
    add_event(socket.get_socket(), &socket);
    set_non_blocking(socket.get_socket());
}

void EventSources::remove_socket(Socket& socket)
{
    remove_event(&socket);
    int fd = socket.get_socket();
    set_blocking(fd);
}

void EventSources::add_file(File& file)
{
    add_event(file.get_fd(), &file);
}

void EventSources::remove_file(File& file)
{
    remove_event(&file);
}

void EventSources::add_handle(Handle& file)
{
}

void EventSources::remove_handle(Handle& file)
{
}

补充:
整个过程的select()函数是有弊端的:
【1】每次调用select()都需要把fd(文件描述符)从用户态拷贝到内核态,开销比较大
【2】每次都需要在内核遍历传入的fd(文件描述符)
【3】select支持文件数量比较小,默认是1024
参考链接:
https://www.cnblogs.com/skiler/p/6852493.html

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3754次
    • 积分:146
    • 等级:
    • 排名:千里之外
    • 原创:11篇
    • 转载:0篇
    • 译文:0篇
    • 评论:3条
    最新评论