19a1e991dSShuo Chen// excerpts from http://code.google.com/p/muduo/ 29a1e991dSShuo Chen// 39a1e991dSShuo Chen// Use of this source code is governed by a BSD-style license 49a1e991dSShuo Chen// that can be found in the License file. 59a1e991dSShuo Chen// 69a1e991dSShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 79a1e991dSShuo Chen 89a1e991dSShuo Chen#define __STDC_LIMIT_MACROS 99a1e991dSShuo Chen#include "TimerQueue.h" 109a1e991dSShuo Chen 119a1e991dSShuo Chen#include "logging/Logging.h" 129a1e991dSShuo Chen#include "EventLoop.h" 139a1e991dSShuo Chen#include "Timer.h" 149a1e991dSShuo Chen#include "TimerId.h" 159a1e991dSShuo Chen 169a1e991dSShuo Chen#include <boost/bind.hpp> 179a1e991dSShuo Chen 189a1e991dSShuo Chen#include <sys/timerfd.h> 199a1e991dSShuo Chen 209a1e991dSShuo Chennamespace muduo 219a1e991dSShuo Chen{ 229a1e991dSShuo Chennamespace detail 239a1e991dSShuo Chen{ 249a1e991dSShuo Chen 259a1e991dSShuo Chenint createTimerfd() 269a1e991dSShuo Chen{ 279a1e991dSShuo Chen int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 289a1e991dSShuo Chen TFD_NONBLOCK | TFD_CLOEXEC); 299a1e991dSShuo Chen if (timerfd < 0) 309a1e991dSShuo Chen { 319a1e991dSShuo Chen LOG_SYSFATAL << "Failed in timerfd_create"; 329a1e991dSShuo Chen } 339a1e991dSShuo Chen return timerfd; 349a1e991dSShuo Chen} 359a1e991dSShuo Chen 369a1e991dSShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when) 379a1e991dSShuo Chen{ 389a1e991dSShuo Chen int64_t microseconds = when.microSecondsSinceEpoch() 399a1e991dSShuo Chen - Timestamp::now().microSecondsSinceEpoch(); 409a1e991dSShuo Chen if (microseconds < 100) 419a1e991dSShuo Chen { 429a1e991dSShuo Chen microseconds = 100; 439a1e991dSShuo Chen } 449a1e991dSShuo Chen struct timespec ts; 459a1e991dSShuo Chen ts.tv_sec = static_cast<time_t>( 469a1e991dSShuo Chen microseconds / Timestamp::kMicroSecondsPerSecond); 479a1e991dSShuo Chen ts.tv_nsec = static_cast<long>( 489a1e991dSShuo Chen (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 499a1e991dSShuo Chen return ts; 509a1e991dSShuo Chen} 519a1e991dSShuo Chen 529a1e991dSShuo Chenvoid readTimerfd(int timerfd, Timestamp now) 539a1e991dSShuo Chen{ 549a1e991dSShuo Chen uint64_t howmany; 559a1e991dSShuo Chen ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 569a1e991dSShuo Chen LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 579a1e991dSShuo Chen if (n != sizeof howmany) 589a1e991dSShuo Chen { 599a1e991dSShuo Chen LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 609a1e991dSShuo Chen } 619a1e991dSShuo Chen} 629a1e991dSShuo Chen 639a1e991dSShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration) 649a1e991dSShuo Chen{ 659a1e991dSShuo Chen // wake up loop by timerfd_settime() 669a1e991dSShuo Chen struct itimerspec newValue; 679a1e991dSShuo Chen struct itimerspec oldValue; 689a1e991dSShuo Chen bzero(&newValue, sizeof newValue); 699a1e991dSShuo Chen bzero(&oldValue, sizeof oldValue); 709a1e991dSShuo Chen newValue.it_value = howMuchTimeFromNow(expiration); 71b4a5ce52SShuo Chen int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 729a1e991dSShuo Chen if (ret) 739a1e991dSShuo Chen { 749a1e991dSShuo Chen LOG_SYSERR << "timerfd_settime()"; 759a1e991dSShuo Chen } 769a1e991dSShuo Chen} 779a1e991dSShuo Chen 789a1e991dSShuo Chen} 799a1e991dSShuo Chen} 809a1e991dSShuo Chen 819a1e991dSShuo Chenusing namespace muduo; 829a1e991dSShuo Chenusing namespace muduo::detail; 839a1e991dSShuo Chen 849a1e991dSShuo ChenTimerQueue::TimerQueue(EventLoop* loop) 859a1e991dSShuo Chen : loop_(loop), 869a1e991dSShuo Chen timerfd_(createTimerfd()), 879a1e991dSShuo Chen timerfdChannel_(loop, timerfd_), 889a1e991dSShuo Chen timers_() 899a1e991dSShuo Chen{ 909a1e991dSShuo Chen timerfdChannel_.setReadCallback( 919a1e991dSShuo Chen boost::bind(&TimerQueue::handleRead, this)); 929a1e991dSShuo Chen // we are always reading the timerfd, we disarm it with timerfd_settime. 939a1e991dSShuo Chen timerfdChannel_.enableReading(); 949a1e991dSShuo Chen} 959a1e991dSShuo Chen 969a1e991dSShuo ChenTimerQueue::~TimerQueue() 979a1e991dSShuo Chen{ 989a1e991dSShuo Chen ::close(timerfd_); 999a1e991dSShuo Chen // do not remove channel, since we're in EventLoop::dtor(); 1009a1e991dSShuo Chen for (TimerList::iterator it = timers_.begin(); 1019a1e991dSShuo Chen it != timers_.end(); ++it) 1029a1e991dSShuo Chen { 1039a1e991dSShuo Chen delete it->second; 1049a1e991dSShuo Chen } 1059a1e991dSShuo Chen} 1069a1e991dSShuo Chen 1079a1e991dSShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb, 1089a1e991dSShuo Chen Timestamp when, 1099a1e991dSShuo Chen double interval) 1109a1e991dSShuo Chen{ 1119a1e991dSShuo Chen Timer* timer = new Timer(cb, when, interval); 1129a1e991dSShuo Chen loop_->runInLoop( 113344a2ce1SShuo Chen boost::bind(&TimerQueue::addTimerInLoop, this, timer)); 1149a1e991dSShuo Chen return TimerId(timer); 1159a1e991dSShuo Chen} 1169a1e991dSShuo Chen 117344a2ce1SShuo Chenvoid TimerQueue::addTimerInLoop(Timer* timer) 1189a1e991dSShuo Chen{ 1199a1e991dSShuo Chen loop_->assertInLoopThread(); 1209a1e991dSShuo Chen bool earliestChanged = insert(timer); 1219a1e991dSShuo Chen 1229a1e991dSShuo Chen if (earliestChanged) 1239a1e991dSShuo Chen { 1249a1e991dSShuo Chen resetTimerfd(timerfd_, timer->expiration()); 1259a1e991dSShuo Chen } 1269a1e991dSShuo Chen} 1279a1e991dSShuo Chen 1289a1e991dSShuo Chenvoid TimerQueue::handleRead() 1299a1e991dSShuo Chen{ 1309a1e991dSShuo Chen loop_->assertInLoopThread(); 1319a1e991dSShuo Chen Timestamp now(Timestamp::now()); 1329a1e991dSShuo Chen readTimerfd(timerfd_, now); 1339a1e991dSShuo Chen 1349a1e991dSShuo Chen std::vector<Entry> expired = getExpired(now); 1359a1e991dSShuo Chen 1369a1e991dSShuo Chen // safe to callback outside critical section 1379a1e991dSShuo Chen for (std::vector<Entry>::iterator it = expired.begin(); 1389a1e991dSShuo Chen it != expired.end(); ++it) 1399a1e991dSShuo Chen { 1409a1e991dSShuo Chen it->second->run(); 1419a1e991dSShuo Chen } 1429a1e991dSShuo Chen 1439a1e991dSShuo Chen reset(expired, now); 1449a1e991dSShuo Chen} 1459a1e991dSShuo Chen 1469a1e991dSShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) 1479a1e991dSShuo Chen{ 1489a1e991dSShuo Chen std::vector<Entry> expired; 1499a1e991dSShuo Chen Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); 1509a1e991dSShuo Chen TimerList::iterator it = timers_.lower_bound(sentry); 1519a1e991dSShuo Chen assert(it == timers_.end() || now < it->first); 1529a1e991dSShuo Chen std::copy(timers_.begin(), it, back_inserter(expired)); 1539a1e991dSShuo Chen timers_.erase(timers_.begin(), it); 1549a1e991dSShuo Chen 1559a1e991dSShuo Chen return expired; 1569a1e991dSShuo Chen} 1579a1e991dSShuo Chen 1589a1e991dSShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now) 1599a1e991dSShuo Chen{ 1609a1e991dSShuo Chen Timestamp nextExpire; 1619a1e991dSShuo Chen 1629a1e991dSShuo Chen for (std::vector<Entry>::const_iterator it = expired.begin(); 1639a1e991dSShuo Chen it != expired.end(); ++it) 1649a1e991dSShuo Chen { 1659a1e991dSShuo Chen if (it->second->repeat()) 1669a1e991dSShuo Chen { 1679a1e991dSShuo Chen it->second->restart(now); 1689a1e991dSShuo Chen insert(it->second); 1699a1e991dSShuo Chen } 1709a1e991dSShuo Chen else 1719a1e991dSShuo Chen { 1729a1e991dSShuo Chen // FIXME move to a free list 1739a1e991dSShuo Chen delete it->second; 1749a1e991dSShuo Chen } 1759a1e991dSShuo Chen } 1769a1e991dSShuo Chen 1779a1e991dSShuo Chen if (!timers_.empty()) 1789a1e991dSShuo Chen { 1799a1e991dSShuo Chen nextExpire = timers_.begin()->second->expiration(); 1809a1e991dSShuo Chen } 1819a1e991dSShuo Chen 1829a1e991dSShuo Chen if (nextExpire.valid()) 1839a1e991dSShuo Chen { 1849a1e991dSShuo Chen resetTimerfd(timerfd_, nextExpire); 1859a1e991dSShuo Chen } 1869a1e991dSShuo Chen} 1879a1e991dSShuo Chen 1889a1e991dSShuo Chenbool TimerQueue::insert(Timer* timer) 1899a1e991dSShuo Chen{ 1909a1e991dSShuo Chen bool earliestChanged = false; 1919a1e991dSShuo Chen Timestamp when = timer->expiration(); 1929a1e991dSShuo Chen TimerList::iterator it = timers_.begin(); 1939a1e991dSShuo Chen if (it == timers_.end() || when < it->first) 1949a1e991dSShuo Chen { 1959a1e991dSShuo Chen earliestChanged = true; 1969a1e991dSShuo Chen } 197a20e676dSShuo Chen std::pair<TimerList::iterator, bool> result = 198a20e676dSShuo Chen timers_.insert(std::make_pair(when, timer)); 1999a1e991dSShuo Chen assert(result.second); 2009a1e991dSShuo Chen return earliestChanged; 2019a1e991dSShuo Chen} 2029a1e991dSShuo Chen 203