/mordor/streams/timeout.cpp
C++ | 186 lines | 160 code | 17 blank | 9 comment | 24 complexity | 70fc8d141bc9bf1fedde0dcd05c082ab MD5 | raw file
1// Copyright (c) 2010 - Mozy, Inc. 2 3#include "timeout.h" 4 5#include "mordor/assert.h" 6#include "mordor/exception.h" 7#include "mordor/log.h" 8#include "mordor/socket.h" 9#include "mordor/timer.h" 10 11namespace Mordor { 12 13static Logger::ptr g_log = Log::lookup("mordor:streams:timeout"); 14 15static void cancelReadLocal(Stream::ptr stream) { stream->cancelRead(); } 16static void cancelWriteLocal(Stream::ptr stream) { stream->cancelWrite(); } 17static void cancelReadWriteLocal(Stream::ptr stream) 18{ 19 cancelReadLocal(stream); 20 cancelWriteLocal(stream); 21} 22 23TimeoutHandler::~TimeoutHandler() 24{ 25 if (m_timer) 26 cancelTimer(); 27} 28 29void 30TimeoutHandler::onTimeout() 31{ 32 if (m_lastTimedOut == TIMING) { 33 MORDOR_LOG_DEBUG(g_log) << this << " timeout"; 34 m_lastTimedOut = m_permaTimedOut = TIMEDOUT; 35 if (m_timeoutDg) 36 m_timeoutDg(); 37 } else { 38 MORDOR_LOG_DEBUG(g_log) << this << " timeout no longer registered"; 39 } 40} 41 42void 43TimeoutHandler::setTimeout(unsigned long long timeout, TimeoutDg dg) 44{ 45 m_timeout = timeout; 46 m_timeoutDg = dg; 47 if (m_timer) { 48 // timer is running, need to stop it or reset its counting down 49 if (!isTimeoutSet()) { 50 cancelTimer(); 51 } else { 52 m_timer->reset(timeout, true); 53 } 54 } else { 55 // timer is not running, start it 56 if (isTimeoutSet()) { 57 // start new timer if read/write is ongoing 58 // OR auto start is set 59 if (m_lastTimedOut == TIMING || m_autoStart) { 60 m_timer = m_timerManager.registerConditionTimer(timeout, 61 boost::bind(&TimeoutHandler::onTimeout, this), 62 shared_from_this()); 63 } 64 } 65 } 66} 67 68void 69TimeoutHandler::startTimer() 70{ 71 MORDOR_LOG_TRACE(g_log) << this << " startTimer()"; 72 if (m_permaTimedOut == TIMEDOUT) 73 MORDOR_THROW_EXCEPTION(TimedOutException()); 74 MORDOR_ASSERT(!m_timer); 75 m_lastTimedOut = TIMING; 76 if (isTimeoutSet()) 77 m_timer = m_timerManager.registerConditionTimer(m_timeout, 78 boost::bind(&TimeoutHandler::onTimeout, this), 79 shared_from_this()); 80} 81 82bool 83TimeoutHandler::cancelTimer() 84{ 85 MORDOR_LOG_TRACE(g_log) << this << " cancelTimer()"; 86 bool res = (m_lastTimedOut == TIMEDOUT); 87 if (m_timer) { 88 m_timer->cancel(); 89 m_timer.reset(); 90 } 91 m_lastTimedOut = NONE; 92 return res; 93} 94 95bool 96TimeoutHandler::refreshTimer() 97{ 98 MORDOR_LOG_TRACE(g_log) << this << " refreshTimer()"; 99 bool res = (m_lastTimedOut == TIMEDOUT); 100 if (m_timer) { 101 m_timer->refresh(); 102 } 103 m_lastTimedOut = TIMING; 104 return res; 105} 106 107void 108TimeoutStream::readTimeout(unsigned long long readTimeout) 109{ 110 FiberMutex::ScopedLock lock(m_mutex); 111 m_reader->setTimeout(readTimeout, boost::bind(&cancelReadLocal, parent())); 112} 113 114void 115TimeoutStream::writeTimeout(unsigned long long writeTimeout) 116{ 117 FiberMutex::ScopedLock lock(m_mutex); 118 m_writer->setTimeout(writeTimeout, boost::bind(&cancelWriteLocal, parent())); 119} 120 121void 122TimeoutStream::idleTimeout(unsigned long long idleTimeout) 123{ 124 FiberMutex::ScopedLock lock(m_mutex); 125 m_idler->setTimeout(idleTimeout, boost::bind(&cancelReadWriteLocal, parent())); 126} 127 128size_t 129TimeoutStream::read(Buffer &buffer, size_t length) 130{ 131 FiberMutex::ScopedLock lock(m_mutex); 132 // start read timer & tickle idle 133 m_reader->startTimer(); 134 m_idler->refreshTimer(); 135 lock.unlock(); 136 size_t result; 137 try { 138 result = parent()->read(buffer, length); 139 } catch (OperationAbortedException &) { 140 lock.lock(); 141 if (m_reader->cancelTimer() || m_idler->cancelTimer()) 142 MORDOR_THROW_EXCEPTION(TimedOutException()); 143 throw; 144 } catch (...) { 145 lock.lock(); 146 m_reader->cancelTimer(); 147 m_idler->cancelTimer(); 148 throw; 149 } 150 lock.lock(); 151 // read done, stop read timer & tickle idle 152 m_reader->cancelTimer(); 153 m_idler->refreshTimer(); 154 return result; 155} 156 157size_t 158TimeoutStream::write(const Buffer &buffer, size_t length) 159{ 160 FiberMutex::ScopedLock lock(m_mutex); 161 // start write timer & tickle idle 162 m_writer->startTimer(); 163 m_idler->refreshTimer(); 164 lock.unlock(); 165 size_t result; 166 try { 167 result = parent()->write(buffer, length); 168 } catch (OperationAbortedException &) { 169 lock.lock(); 170 if (m_writer->cancelTimer() || m_idler->cancelTimer()) 171 MORDOR_THROW_EXCEPTION(TimedOutException()); 172 throw; 173 } catch (...) { 174 lock.lock(); 175 m_writer->cancelTimer(); 176 m_idler->cancelTimer(); 177 throw; 178 } 179 lock.lock(); 180 // write done, stop write timer & tickle idle 181 m_writer->cancelTimer(); 182 m_idler->refreshTimer(); 183 return result; 184} 185 186}