-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEPollPoller.cc
136 lines (118 loc) · 4.42 KB
/
EPollPoller.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include"EPollPoller.h"
#include"Logger.h"
#include"Channel.h"
#include<errno.h>
#include<cstring>
#include<unistd.h>
const int kNew = -1; // 表示channel从未添加进poller中
const int kAdded = 1; // channel在poller的channelMap中
const int kDeleted = 2; // channel不在channelMap中
/*
该类主要用于处理事件轮询和Channel的添加,删除和修改等操作.其中,事件轮询使用epoll_wait函数实现,轮询结果通过参数activeChannels返回给EventLoop.同时该类还维护了一个channelMap,用于存储所有channel,并在需要时调用epoll_ctl函数对其进行添加,删除和修改等操作.
构造函数:创建epollfd和events数组(size:16),并对其初始化.
析构函数:释放epollfd
poll函数:调用epoll_wait函数进行事件轮询,返回发生事件的channel列表,并设置超时时间.
removeChannel函数:向channelMap中添加或修改channel,并调用epoll_ctl函数对其进行添加,修改或删除.
update函数:调用epoll_ctl函数对channel进行添加,修改或删除操作.
fillActiveChannels函数:将events数组中的所有发生事件的channel添加到activeChannels列表中.
*/
EPollPoller::EPollPoller(EventLoop* loop)
:Poller(loop),
epollfd_(::epoll_create1(EPOLL_CLOEXEC)),
events_(kInitEventListSize) // epoll_event
{
if(epollfd_ < 0){
LOG_FATAL("epoll_create error:%d \n",errno);
}
}
EPollPoller::~EPollPoller(){
::close(epollfd_);
}
// 主要调用epoll_wait
Timestamp EPollPoller::poll(int timeoutMs,ChannelList* activeChannels){
// 这里写日志对效率影响大,用LOG_DEBUG更加合理
LOG_DEBUG("func=%s -> fd total count:%lu \n",__FUNCTION__,channels_.size());
int numEvents = ::epoll_wait(epollfd_,&*events_.begin(),static_cast<int>(events_.size()),timeoutMs);
int savedErrno = errno; // errno是全局的,所以save一下
Timestamp now(Timestamp::now());
if(numEvents > 0){
LOG_INFO("%d events happened \n",numEvents);
fillActiveChannels(numEvents,activeChannels);
if(numEvents == events_.size()) { // 发生事件数=vector size
events_.resize(2 * events_.size());
}
} else if(numEvents == 0){
// nothing happened , timeout
LOG_DEBUG("%s timeout. \n",__FUNCTION__);
} else {
if(savedErrno != EINTR) {// 中断
errno = savedErrno;
LOG_ERROR("EPollPoller::Poll() error! \n");
}
}
return now;
}
/*
eventLoop
ChannelList poller
存放所有channel channelMap <fd,channel*>
*/
// 从poller中删除channel
void EPollPoller::removeChannel(Channel* channel){
LOG_DEBUG("func=%s => fd=%d \n",__FUNCTION__,channel->fd());
int fd = channel->fd();
channels_.erase(fd); // 从channelMap中删除
int index = channel->index();
if(index == kAdded) {
update(EPOLL_CTL_DEL,channel);
}
channel->set_index(kNew); // kNew从来没有往poller从添加过
}
void EPollPoller::updateChannel(Channel* channel){
const int index = channel->index();
LOG_DEBUG("func=%s => fd=%d events=%d index=%d \n",__FUNCTION__,channel->fd(),channel->events(),index);
if(index == kNew or index == kDeleted){
if(index == kNew){
// 添加到poller的channelMap里面
int fd = channel->fd();
channels_[fd] = channel;
} else { // kDeleted
// do nothing
}
channel->set_index(kAdded);
update(EPOLL_CTL_ADD,channel);
} else { // index == kAdded
// 表示channel已经在poller上注册过了
int fd = channel->fd();
if(channel->isNoneEvent()){
update(EPOLL_CTL_DEL,channel);
channel->set_index(kDeleted);
} else {
update(EPOLL_CTL_MOD,channel);
}
}
}
void EPollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels) const {
for(int i = 0;i < numEvents;++i){
// events.data.ptr是void*,所以强转一下
Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
channel->set_revents(events_[i].events);
activeChannels->push_back(channel);
} // 这样eventloop就拿到了poller返回的所有发生事件的channel列表
}
// epoll_ctl具体操作
void EPollPoller::update(int operation,Channel* channel) {
epoll_event event;
memset(&event,0,sizeof(event));
int fd = channel->fd();
event.events = channel->events();
event.data.fd = fd;
event.data.ptr = channel;
if(::epoll_ctl(epollfd_,operation,fd,&event) < 0){
if(operation == EPOLL_CTL_DEL){
LOG_ERROR("epoll_ctl_del error:%d \n",errno);
} else {
LOG_FATAL("epoll_ctl add/mod error:%d \n",errno);
}
}
}