1e254a845SShuo Chen// excerpts from http://code.google.com/p/muduo/ 2e254a845SShuo Chen// 3e254a845SShuo Chen// Use of this source code is governed by a BSD-style license 4e254a845SShuo Chen// that can be found in the License file. 5e254a845SShuo Chen// 6e254a845SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 7e254a845SShuo Chen 8e254a845SShuo Chen#define __STDC_LIMIT_MACROS 9e254a845SShuo Chen#include "TimerQueue.h" 10e254a845SShuo Chen 11e254a845SShuo Chen#include "logging/Logging.h" 12e254a845SShuo Chen#include "EventLoop.h" 13e254a845SShuo Chen#include "Timer.h" 14e254a845SShuo Chen#include "TimerId.h" 15e254a845SShuo Chen 16e254a845SShuo Chen#include <boost/bind.hpp> 17e254a845SShuo Chen 18e254a845SShuo Chen#include <sys/timerfd.h> 19e254a845SShuo Chen 20e254a845SShuo Chennamespace muduo 21e254a845SShuo Chen{ 22e254a845SShuo Chennamespace detail 23e254a845SShuo Chen{ 24e254a845SShuo Chen 25e254a845SShuo Chenint createTimerfd() 26e254a845SShuo Chen{ 27e254a845SShuo Chen int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 28e254a845SShuo Chen TFD_NONBLOCK | TFD_CLOEXEC); 29e254a845SShuo Chen if (timerfd < 0) 30e254a845SShuo Chen { 31e254a845SShuo Chen LOG_SYSFATAL << "Failed in timerfd_create"; 32e254a845SShuo Chen } 33e254a845SShuo Chen return timerfd; 34e254a845SShuo Chen} 35e254a845SShuo Chen 36e254a845SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when) 37e254a845SShuo Chen{ 38e254a845SShuo Chen int64_t microseconds = when.microSecondsSinceEpoch() 39e254a845SShuo Chen - Timestamp::now().microSecondsSinceEpoch(); 40e254a845SShuo Chen if (microseconds < 100) 41e254a845SShuo Chen { 42e254a845SShuo Chen microseconds = 100; 43e254a845SShuo Chen } 44e254a845SShuo Chen struct timespec ts; 45e254a845SShuo Chen ts.tv_sec = static_cast<time_t>( 46e254a845SShuo Chen microseconds / Timestamp::kMicroSecondsPerSecond); 47e254a845SShuo Chen ts.tv_nsec = static_cast<long>( 48e254a845SShuo Chen (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 49e254a845SShuo Chen return ts; 50e254a845SShuo Chen} 51e254a845SShuo Chen 52e254a845SShuo Chenvoid readTimerfd(int timerfd, Timestamp now) 53e254a845SShuo Chen{ 54e254a845SShuo Chen uint64_t howmany; 55e254a845SShuo Chen ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 56e254a845SShuo Chen LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 57e254a845SShuo Chen if (n != sizeof howmany) 58e254a845SShuo Chen { 59e254a845SShuo Chen LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 60e254a845SShuo Chen } 61e254a845SShuo Chen} 62e254a845SShuo Chen 63e254a845SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration) 64e254a845SShuo Chen{ 65e254a845SShuo Chen // wake up loop by timerfd_settime() 66e254a845SShuo Chen struct itimerspec newValue; 67e254a845SShuo Chen struct itimerspec oldValue; 68e254a845SShuo Chen bzero(&newValue, sizeof newValue); 69e254a845SShuo Chen bzero(&oldValue, sizeof oldValue); 70e254a845SShuo Chen newValue.it_value = howMuchTimeFromNow(expiration); 71e254a845SShuo Chen int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 72e254a845SShuo Chen if (ret) 73e254a845SShuo Chen { 74e254a845SShuo Chen LOG_SYSERR << "timerfd_settime()"; 75e254a845SShuo Chen } 76e254a845SShuo Chen} 77e254a845SShuo Chen 78e254a845SShuo Chen} 79e254a845SShuo Chen} 80e254a845SShuo Chen 81e254a845SShuo Chenusing namespace muduo; 82e254a845SShuo Chenusing namespace muduo::detail; 83e254a845SShuo Chen 84e254a845SShuo ChenTimerQueue::TimerQueue(EventLoop* loop) 85e254a845SShuo Chen : loop_(loop), 86e254a845SShuo Chen timerfd_(createTimerfd()), 87e254a845SShuo Chen timerfdChannel_(loop, timerfd_), 88e254a845SShuo Chen timers_() 89e254a845SShuo Chen{ 90e254a845SShuo Chen timerfdChannel_.setReadCallback( 91e254a845SShuo Chen boost::bind(&TimerQueue::handleRead, this)); 92e254a845SShuo Chen // we are always reading the timerfd, we disarm it with timerfd_settime. 93e254a845SShuo Chen timerfdChannel_.enableReading(); 94e254a845SShuo Chen} 95e254a845SShuo Chen 96e254a845SShuo ChenTimerQueue::~TimerQueue() 97e254a845SShuo Chen{ 98e254a845SShuo Chen ::close(timerfd_); 99e254a845SShuo Chen // do not remove channel, since we're in EventLoop::dtor(); 100e254a845SShuo Chen for (TimerList::iterator it = timers_.begin(); 101e254a845SShuo Chen it != timers_.end(); ++it) 102e254a845SShuo Chen { 103e254a845SShuo Chen delete it->second; 104e254a845SShuo Chen } 105e254a845SShuo Chen} 106e254a845SShuo Chen 107e254a845SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb, 108e254a845SShuo Chen Timestamp when, 109e254a845SShuo Chen double interval) 110e254a845SShuo Chen{ 111e254a845SShuo Chen Timer* timer = new Timer(cb, when, interval); 112e254a845SShuo Chen loop_->runInLoop( 113344a2ce1SShuo Chen boost::bind(&TimerQueue::addTimerInLoop, this, timer)); 114e254a845SShuo Chen return TimerId(timer); 115e254a845SShuo Chen} 116e254a845SShuo Chen 117344a2ce1SShuo Chenvoid TimerQueue::addTimerInLoop(Timer* timer) 118e254a845SShuo Chen{ 119e254a845SShuo Chen loop_->assertInLoopThread(); 120e254a845SShuo Chen bool earliestChanged = insert(timer); 121e254a845SShuo Chen 122e254a845SShuo Chen if (earliestChanged) 123e254a845SShuo Chen { 124e254a845SShuo Chen resetTimerfd(timerfd_, timer->expiration()); 125e254a845SShuo Chen } 126e254a845SShuo Chen} 127e254a845SShuo Chen 128e254a845SShuo Chenvoid TimerQueue::handleRead() 129e254a845SShuo Chen{ 130e254a845SShuo Chen loop_->assertInLoopThread(); 131e254a845SShuo Chen Timestamp now(Timestamp::now()); 132e254a845SShuo Chen readTimerfd(timerfd_, now); 133e254a845SShuo Chen 134e254a845SShuo Chen std::vector<Entry> expired = getExpired(now); 135e254a845SShuo Chen 136e254a845SShuo Chen // safe to callback outside critical section 137e254a845SShuo Chen for (std::vector<Entry>::iterator it = expired.begin(); 138e254a845SShuo Chen it != expired.end(); ++it) 139e254a845SShuo Chen { 140e254a845SShuo Chen it->second->run(); 141e254a845SShuo Chen } 142e254a845SShuo Chen 143e254a845SShuo Chen reset(expired, now); 144e254a845SShuo Chen} 145e254a845SShuo Chen 146e254a845SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) 147e254a845SShuo Chen{ 148e254a845SShuo Chen std::vector<Entry> expired; 149e254a845SShuo Chen Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); 150e254a845SShuo Chen TimerList::iterator it = timers_.lower_bound(sentry); 151e254a845SShuo Chen assert(it == timers_.end() || now < it->first); 152e254a845SShuo Chen std::copy(timers_.begin(), it, back_inserter(expired)); 153e254a845SShuo Chen timers_.erase(timers_.begin(), it); 154e254a845SShuo Chen 155e254a845SShuo Chen return expired; 156e254a845SShuo Chen} 157e254a845SShuo Chen 158e254a845SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now) 159e254a845SShuo Chen{ 160e254a845SShuo Chen Timestamp nextExpire; 161e254a845SShuo Chen 162e254a845SShuo Chen for (std::vector<Entry>::const_iterator it = expired.begin(); 163e254a845SShuo Chen it != expired.end(); ++it) 164e254a845SShuo Chen { 165e254a845SShuo Chen if (it->second->repeat()) 166e254a845SShuo Chen { 167e254a845SShuo Chen it->second->restart(now); 168e254a845SShuo Chen insert(it->second); 169e254a845SShuo Chen } 170e254a845SShuo Chen else 171e254a845SShuo Chen { 172e254a845SShuo Chen // FIXME move to a free list 173e254a845SShuo Chen delete it->second; 174e254a845SShuo Chen } 175e254a845SShuo Chen } 176e254a845SShuo Chen 177e254a845SShuo Chen if (!timers_.empty()) 178e254a845SShuo Chen { 179e254a845SShuo Chen nextExpire = timers_.begin()->second->expiration(); 180e254a845SShuo Chen } 181e254a845SShuo Chen 182e254a845SShuo Chen if (nextExpire.valid()) 183e254a845SShuo Chen { 184e254a845SShuo Chen resetTimerfd(timerfd_, nextExpire); 185e254a845SShuo Chen } 186e254a845SShuo Chen} 187e254a845SShuo Chen 188e254a845SShuo Chenbool TimerQueue::insert(Timer* timer) 189e254a845SShuo Chen{ 190e254a845SShuo Chen bool earliestChanged = false; 191e254a845SShuo Chen Timestamp when = timer->expiration(); 192e254a845SShuo Chen TimerList::iterator it = timers_.begin(); 193e254a845SShuo Chen if (it == timers_.end() || when < it->first) 194e254a845SShuo Chen { 195e254a845SShuo Chen earliestChanged = true; 196e254a845SShuo Chen } 197e254a845SShuo Chen std::pair<TimerList::iterator, bool> result = 198e254a845SShuo Chen timers_.insert(std::make_pair(when, timer)); 199e254a845SShuo Chen assert(result.second); 200e254a845SShuo Chen return earliestChanged; 201e254a845SShuo Chen} 202e254a845SShuo Chen 203