-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTimeQueue.cc
129 lines (102 loc) · 2.95 KB
/
TimeQueue.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
#include "Timestamp.h"
#include "TimeQueue.h"
#include "Logging.h"
#include "Timer.h"
#include "EventLoop.h"
#include <dlfcn.h>
#include <algorithm>
#include<sys/timerfd.h>
#include<stdio.h>
#include<boost/bind.hpp>
#include"Channel.h"
#include<stdint.h>
struct timespec howLongFromNow(Timer* timer){
int64_t useconds = timer->expiration().microSecondsSinceEpoch() - Timestamp::now().microSecondsSinceEpoch();
struct timespec it;
it. tv_sec = static_cast<time_t>(useconds / Timestamp::kMicroSecondsPerSecond);
it. tv_nsec = static_cast<time_t>(useconds % Timestamp::kMicroSecondsPerSecond * 1000);
return it;
}
int creatTimefd(){
int timefd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (timefd < 0)
LOG_FATAL<<"Failed in timerfd_create";
return timefd;
}
TimeQueue::TimeQueue(EventLoop* loop):loop_(loop),timefd_(creatTimefd()),channel(new Channel(loop_, timefd_))
{
channel->setReadCallback(boost::bind(&TimeQueue::handleRead, this));
channel->enableRead();
}
TimeQueue::~TimeQueue(){}
void TimeQueue::addTimer(Timer* ptimer)
{
loop_->runInLoop(boost::bind(&TimeQueue::addTimerInLoop,this,ptimer));
}
void TimeQueue::addTimerInLoop(Timer* ptimer){
bool earliest = insert(ptimer);
if (earliest){
resetTimefd(ptimer);
}
}
bool TimeQueue::insert(Timer* timer){
bool earliest = false;
Entry entry(timer->expiration(), timer);
Iterator it = timers_.begin();
if (it == timers_. end()||entry < *it)
{
earliest = true;
}
{
timers_. insert(entry);
}
return earliest;
}
void TimeQueue::resetTimefd(Timer* timer){
struct timespec value = howLongFromNow(timer);
struct itimerspec newValue,old;
bzero(&newValue, sizeof newValue);
bzero(&old, sizeof old);
newValue. it_value = value;
int i = timerfd_settime(timefd_, 0, &newValue,&old) ;
if (i)
LOG_FATAL<<"settime error";
}
void TimeQueue::reset(Timestamp now, std::vector<Entry>& expired){
for (std::vector<Entry>::iterator it = expired.begin();
it != expired.end(); ++it)
{
if (it->second->repeat())
{
it->second->reset();
insert(it->second);
}
}
if (!timers_. empty())
resetTimefd((*(timers_.begin())).second);
}
void TimeQueue::readTimerfd()
{
int64_t exp = 0;
if ( (read(timefd_,&exp,sizeof exp)) != sizeof exp)
LOG_FATAL<<"timerfd read error";
}
void TimeQueue::handleRead(){
readTimerfd();
Timestamp now(Timestamp::now());
std::vector<Entry> expired = getExpiration(now);
for (std::vector<Entry>::iterator it = expired.begin();
it != expired.end(); ++it)
{
it->second->run();
}
reset(now, expired);
}
std::vector<TimeQueue::Entry> TimeQueue::getExpiration(Timestamp now){
Entry entry (now, reinterpret_cast<Timer*>(UINTPTR_MAX));
Iterator it = timers_.lower_bound(entry);
std::vector<Entry> expired;
std::copy(timers_.begin(), it, back_inserter(expired));
timers_. erase(timers_.begin(), it);
return expired;
}