EventLoop.h
eventfd 是 Linux 的一个系统调用,创建一个文件描述符用于事件通知,自 Linux 2.6.22 以后开始支持。
`#include <sys/eventfd.h>`
`int eventfd(unsigned int initval, int flags);`
eventfd() 创建一个 eventfd 对象,可以由用户空间应用程序实现事件等待/通知机制,或由内核通知用户空间应用程序事件。
该对象包含了由内核维护的无符号64位整数计数器 count 。使用参数 initval 初始化此计数器。
flags 可以是以下值的 OR 运算结果,用以改变 eventfd 的行为。
EFD_CLOEXEC (since Linux 2.6.27)
文件被设置成 O_CLOEXEC,创建子进程 (fork) 时不继承父进程的文件描述符。
EFD_NONBLOCK (since Linux 2.6.27)
文件被设置成 O_NONBLOCK,执行 read / write 操作时,不会阻塞。
EFD_SEMAPHORE (since Linux 2.6.30)
提供类似信号量语义的 read 操作,简单说就是计数值 count 递减 1。
在 Linux 2.6.26 版本之前,没有使用参数 flags,必须指定为 0。
对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。信号,为 Linux 提供了一种处理异步事件的方法。比如,终端用户输入了 ctrl+c 来中断程序,会通过信号机制停止一个程序。
信号的名字和编号:
1每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
2信号的处理有三种方法,分别是:忽略、捕捉和默认动作
忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景
捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。
系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
__thread EventLoop* t_loopInThisThread = 0; //线程变量
const int kPollTimeMs = 10000;
int createEventfd()
{
int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
if (evtfd < 0)
{
LOG_SYSERR << "Failed in eventfd";
abort();
}
return evtfd;
}
class IgnoreSigPipe
{
public:
IgnoreSigPipe()
{
::signal(SIGPIPE, SIG_IGN); //忽略SIGPIPE
// LOG_TRACE << "Ignore SIGPIPE";
}
};
IgnoreSigPipe initObj;//创建了一个对象
class EventLoop {
public:
typedef std::function<void()> Functor;
private:
typedef std::vector<Channel*> ChannelList;
bool looping_; /* atomic */
std::atomic<bool> quit_;
bool eventHandling_; /* atomic */
bool callingPendingFunctors_; /* atomic */
int64_t iteration_;
const pid_t threadId_;
Timestamp pollReturnTime_;
std::unique_ptr<Poller> poller_;
std::unique_ptr<TimerQueue> timerQueue_;
int wakeupFd_;
// unlike in TimerQueue, which is an internal class,
// we don't expose Channel to client.
std::unique_ptr<Channel> wakeupChannel_;
boost::any context_;
ChannelList activeChannels_;
Channel* currentActiveChannel_; //当前活跃频道
mutable MutexLock mutex_;
std::vector<Functor> pendingFunctors_ GUARDED_BY(mutex_);
public:
EventLoop()
: looping_(false),
quit_(false),
eventHandling_(false),
callingPendingFunctors_(false),
iteration_(0),
threadId_(CurrentThread::tid()), //设置线程id
poller_(Poller::newDefaultPoller(this)), //创建一个默认轮训器
timerQueue_(new TimerQueue(this)), //创建一个定时器队列
wakeupFd_(createEventfd()), //单纯理解为创建了一个事件描述符
wakeupChannel_(new Channel(this, wakeupFd_)), //将频道和文件描述符绑定
currentActiveChannel_(NULL)
{
LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_;
if (t_loopInThisThread) //如果这个线程已经有EventLoop对象
{
LOG_FATAL << "Another EventLoop " << t_loopInThisThread
<< " exists in this thread " << threadId_;
}
else
{
t_loopInThisThread = this;
}
wakeupChannel_->setReadCallback(
std::bind(&EventLoop::handleRead, this)); //绑定处理有读事件的回调函数
// we are always reading the wakeupfd
wakeupChannel_->enableReading(); //运去读
}
void EventLoop::handleRead()
{
uint64_t one = 1;
ssize_t n = sockets::read(wakeupFd_, &one, sizeof one); //读取wakeupFd事件
if (n != sizeof one)
{
LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8";
}
}
~EventLoop() {
wakeupChannel_->disableAll();
wakeupChannel_->remove();
::close(wakeupFd_);
t_loopInThisThread = NULL;
}
void loop() {
assert(!looping_);
assertInLoopThread();
looping_ = true;
quit_ = false;
while (!quit_)
{
activeChannels_.clear();
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); //让轮训器去询问有没有事件等就绪
++iteration_; //迭代数目+1
if (Logger::logLevel() <= Logger::TRACE)
{
printActiveChannels();
}
// TODO sort channel by priority
eventHandling_ = true;
for (Channel* channel : activeChannels_) //处理每一个活跃频道的事件
{
currentActiveChannel_ = channel; //当前活跃频道
currentActiveChannel_->handleEvent(pollReturnTime_); 调用回调函数
}
currentActiveChannel_ = NULL;
eventHandling_ = false;
doPendingFunctors();
}
looping_ = false;
}
void doPendingFunctors() {
std::vector<Functor> functors;
callingPendingFunctors_ = true;
{
MutexLockGuard lock(mutex_);
functors.swap(pendingFunctors_);
}
for (const Functor& functor : functors) //调用栈上对象,尽量减少锁的粒度
{
functor();
}
callingPendingFunctors_ = false;
}
void EventLoop::printActiveChannels() const 打印当前活跃频道
{
for (const Channel* channel : activeChannels_)
{
LOG_TRACE << "{" << channel->reventsToString() << "} ";
}
}
void quit() {
quit_ = true;
if (!isInLoopThread())
{
wakeup();
}
}
void wakeup() {
uint64_t one = 1;
ssize_t n = sockets::write(wakeupFd_, &one, sizeof one);
if (n != sizeof one)
{
LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8";
}
}
void EventLoop::runInLoop(Functor cb)
{
if (isInLoopThread())
{
cb();
}
else
{
queueInLoop(std::move(cb));
}
}
void EventLoop::queueInLoop(Functor cb)
{
{
MutexLockGuard lock(mutex_);
pendingFunctors_.push_back(std::move(cb));
}
if (!isInLoopThread() || callingPendingFunctors_)
{
wakeup();
}
}
size_t EventLoop::queueSize() const
{
MutexLockGuard lock(mutex_);
return pendingFunctors_.size();
}
TimerId EventLoop::runAt(Timestamp time, TimerCallback cb)
{
return timerQueue_->addTimer(std::move(cb), time, 0.0);
}
TimerId EventLoop::runAfter(double delay, TimerCallback cb)
{
Timestamp time(addTime(Timestamp::now(), delay));
return runAt(time, std::move(cb));
}
TimerId EventLoop::runEvery(double interval, TimerCallback cb)
{
Timestamp time(addTime(Timestamp::now(), interval));
return timerQueue_->addTimer(std::move(cb), time, interval);
}
void EventLoop::cancel(TimerId timerId)
{
return timerQueue_->cancel(timerId);
}
void EventLoop::updateChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
poller_->updateChannel(channel);
}
void EventLoop::removeChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
if (eventHandling_)
{
assert(currentActiveChannel_ == channel ||
std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end());
}
poller_->removeChannel(channel);
}
bool EventLoop::hasChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
return poller_->hasChannel(channel);
}
}