capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

timer.c++ (3726B)


      1 // Copyright (c) 2014 Google Inc. (contributed by Remy Blank <rblank@google.com>)
      2 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      3 // Licensed under the MIT License:
      4 //
      5 // Permission is hereby granted, free of charge, to any person obtaining a copy
      6 // of this software and associated documentation files (the "Software"), to deal
      7 // in the Software without restriction, including without limitation the rights
      8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9 // copies of the Software, and to permit persons to whom the Software is
     10 // furnished to do so, subject to the following conditions:
     11 //
     12 // The above copyright notice and this permission notice shall be included in
     13 // all copies or substantial portions of the Software.
     14 //
     15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     21 // THE SOFTWARE.
     22 
     23 #include "timer.h"
     24 #include "debug.h"
     25 #include <set>
     26 
     27 namespace kj {
     28 
     29 kj::Exception Timer::makeTimeoutException() {
     30   return KJ_EXCEPTION(OVERLOADED, "operation timed out");
     31 }
     32 
     33 struct TimerImpl::Impl {
     34   struct TimerBefore {
     35     bool operator()(TimerPromiseAdapter* lhs, TimerPromiseAdapter* rhs) const;
     36   };
     37   using Timers = std::multiset<TimerPromiseAdapter*, TimerBefore>;
     38   Timers timers;
     39 };
     40 
     41 class TimerImpl::TimerPromiseAdapter {
     42 public:
     43   TimerPromiseAdapter(PromiseFulfiller<void>& fulfiller, TimerImpl::Impl& impl, TimePoint time)
     44       : time(time), fulfiller(fulfiller), impl(impl) {
     45     pos = impl.timers.insert(this);
     46   }
     47 
     48   ~TimerPromiseAdapter() {
     49     if (pos != impl.timers.end()) {
     50       impl.timers.erase(pos);
     51     }
     52   }
     53 
     54   void fulfill() {
     55     fulfiller.fulfill();
     56     impl.timers.erase(pos);
     57     pos = impl.timers.end();
     58   }
     59 
     60   const TimePoint time;
     61 
     62 private:
     63   PromiseFulfiller<void>& fulfiller;
     64   TimerImpl::Impl& impl;
     65   Impl::Timers::const_iterator pos;
     66 };
     67 
     68 inline bool TimerImpl::Impl::TimerBefore::operator()(
     69     TimerPromiseAdapter* lhs, TimerPromiseAdapter* rhs) const {
     70   return lhs->time < rhs->time;
     71 }
     72 
     73 Promise<void> TimerImpl::atTime(TimePoint time) {
     74   return newAdaptedPromise<void, TimerPromiseAdapter>(*impl, time);
     75 }
     76 
     77 Promise<void> TimerImpl::afterDelay(Duration delay) {
     78   return newAdaptedPromise<void, TimerPromiseAdapter>(*impl, time + delay);
     79 }
     80 
     81 TimerImpl::TimerImpl(TimePoint startTime)
     82     : time(startTime), impl(heap<Impl>()) {}
     83 
     84 TimerImpl::~TimerImpl() noexcept(false) {}
     85 
     86 Maybe<TimePoint> TimerImpl::nextEvent() {
     87   auto iter = impl->timers.begin();
     88   if (iter == impl->timers.end()) {
     89     return nullptr;
     90   } else {
     91     return (*iter)->time;
     92   }
     93 }
     94 
     95 Maybe<uint64_t> TimerImpl::timeoutToNextEvent(TimePoint start, Duration unit, uint64_t max) {
     96   return nextEvent().map([&](TimePoint nextTime) -> uint64_t {
     97     if (nextTime <= start) return 0;
     98 
     99     Duration timeout = nextTime - start;
    100 
    101     uint64_t result = timeout / unit;
    102     bool roundUp = timeout % unit > 0 * SECONDS;
    103 
    104     if (result >= max) {
    105       return max;
    106     } else {
    107       return result + roundUp;
    108     }
    109   });
    110 }
    111 
    112 void TimerImpl::advanceTo(TimePoint newTime) {
    113   KJ_REQUIRE(newTime >= time, "can't advance backwards in time") { return; }
    114 
    115   time = newTime;
    116   for (;;) {
    117     auto front = impl->timers.begin();
    118     if (front == impl->timers.end() || (*front)->time > time) {
    119       break;
    120     }
    121     (*front)->fulfill();
    122   }
    123 }
    124 
    125 }  // namespace kj