Consistency in namespace-closing comments
[folly.git] / folly / io / async / EventBase.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __STDC_FORMAT_MACROS
18 #define __STDC_FORMAT_MACROS
19 #endif
20
21 #include <folly/io/async/EventBase.h>
22
23 #include <fcntl.h>
24
25 #include <mutex>
26 #include <thread>
27
28 #include <folly/Baton.h>
29 #include <folly/Memory.h>
30 #include <folly/ThreadName.h>
31 #include <folly/io/async/NotificationQueue.h>
32 #include <folly/io/async/VirtualEventBase.h>
33 #include <folly/portability/Unistd.h>
34
35 namespace folly {
36
37 /*
38  * EventBase::FunctionRunner
39  */
40
41 class EventBase::FunctionRunner
42     : public NotificationQueue<EventBase::Func>::Consumer {
43  public:
44   void messageAvailable(Func&& msg) noexcept override {
45     // In libevent2, internal events do not break the loop.
46     // Most users would expect loop(), followed by runInEventBaseThread(),
47     // to break the loop and check if it should exit or not.
48     // To have similar bejaviour to libevent1.4, tell the loop to break here.
49     // Note that loop() may still continue to loop, but it will also check the
50     // stop_ flag as well as runInLoop callbacks, etc.
51     event_base_loopbreak(getEventBase()->evb_);
52
53     if (!msg) {
54       // terminateLoopSoon() sends a null message just to
55       // wake up the loop.  We can ignore these messages.
56       return;
57     }
58     msg();
59   }
60 };
61
62 // The interface used to libevent is not thread-safe.  Calls to
63 // event_init() and event_base_free() directly modify an internal
64 // global 'current_base', so a mutex is required to protect this.
65 //
66 // event_init() should only ever be called once.  Subsequent calls
67 // should be made to event_base_new().  We can recognise that
68 // event_init() has already been called by simply inspecting current_base.
69 static std::mutex libevent_mutex_;
70
71 /*
72  * EventBase methods
73  */
74
75 EventBase::EventBase(bool enableTimeMeasurement)
76   : runOnceCallbacks_(nullptr)
77   , stop_(false)
78   , loopThread_()
79   , queue_(nullptr)
80   , fnRunner_(nullptr)
81   , maxLatency_(0)
82   , avgLoopTime_(std::chrono::seconds(2))
83   , maxLatencyLoopTime_(avgLoopTime_)
84   , enableTimeMeasurement_(enableTimeMeasurement)
85   , nextLoopCnt_(uint64_t(-40)) // Early wrap-around so bugs will manifest soon
86   , latestLoopCnt_(nextLoopCnt_)
87   , startWork_()
88   , observer_(nullptr)
89   , observerSampleCount_(0)
90   , executionObserver_(nullptr) {
91   struct event ev;
92   {
93     std::lock_guard<std::mutex> lock(libevent_mutex_);
94
95     // The value 'current_base' (libevent 1) or
96     // 'event_global_current_base_' (libevent 2) is filled in by event_set(),
97     // allowing examination of its value without an explicit reference here.
98     // If ev.ev_base is nullptr, then event_init() must be called, otherwise
99     // call event_base_new().
100     event_set(&ev, 0, 0, nullptr, nullptr);
101     if (!ev.ev_base) {
102       evb_ = event_init();
103     }
104   }
105
106   if (ev.ev_base) {
107     evb_ = event_base_new();
108   }
109
110   if (UNLIKELY(evb_ == nullptr)) {
111     LOG(ERROR) << "EventBase(): Failed to init event base.";
112     folly::throwSystemError("error in EventBase::EventBase()");
113   }
114   VLOG(5) << "EventBase(): Created.";
115   initNotificationQueue();
116   RequestContext::saveContext();
117 }
118
119 // takes ownership of the event_base
120 EventBase::EventBase(event_base* evb, bool enableTimeMeasurement)
121   : runOnceCallbacks_(nullptr)
122   , stop_(false)
123   , loopThread_()
124   , evb_(evb)
125   , queue_(nullptr)
126   , fnRunner_(nullptr)
127   , maxLatency_(0)
128   , avgLoopTime_(std::chrono::seconds(2))
129   , maxLatencyLoopTime_(avgLoopTime_)
130   , enableTimeMeasurement_(enableTimeMeasurement)
131   , nextLoopCnt_(uint64_t(-40)) // Early wrap-around so bugs will manifest soon
132   , latestLoopCnt_(nextLoopCnt_)
133   , startWork_()
134   , observer_(nullptr)
135   , observerSampleCount_(0)
136   , executionObserver_(nullptr) {
137   if (UNLIKELY(evb_ == nullptr)) {
138     LOG(ERROR) << "EventBase(): Pass nullptr as event base.";
139     throw std::invalid_argument("EventBase(): event base cannot be nullptr");
140   }
141   initNotificationQueue();
142   RequestContext::saveContext();
143 }
144
145 EventBase::~EventBase() {
146   std::future<void> virtualEventBaseDestroyFuture;
147   if (virtualEventBase_) {
148     virtualEventBaseDestroyFuture = virtualEventBase_->destroy();
149   }
150
151   // Keep looping until all keep-alive handles are released. Each keep-alive
152   // handle signals that some external code will still schedule some work on
153   // this EventBase (so it's not safe to destroy it).
154   while (loopKeepAliveCount() > 0) {
155     applyLoopKeepAlive();
156     loopOnce();
157   }
158
159   if (virtualEventBaseDestroyFuture.valid()) {
160     virtualEventBaseDestroyFuture.get();
161   }
162
163   // Call all destruction callbacks, before we start cleaning up our state.
164   while (!onDestructionCallbacks_.empty()) {
165     LoopCallback* callback = &onDestructionCallbacks_.front();
166     onDestructionCallbacks_.pop_front();
167     callback->runLoopCallback();
168   }
169
170   clearCobTimeouts();
171
172   DCHECK_EQ(0u, runBeforeLoopCallbacks_.size());
173
174   (void)runLoopCallbacks();
175
176   if (!fnRunner_->consumeUntilDrained()) {
177     LOG(ERROR) << "~EventBase(): Unable to drain notification queue";
178   }
179
180   // Stop consumer before deleting NotificationQueue
181   fnRunner_->stopConsuming();
182   {
183     std::lock_guard<std::mutex> lock(libevent_mutex_);
184     event_base_free(evb_);
185   }
186
187   for (auto storage : localStorageToDtor_) {
188     storage->onEventBaseDestruction(*this);
189   }
190
191   VLOG(5) << "EventBase(): Destroyed.";
192 }
193
194 size_t EventBase::getNotificationQueueSize() const {
195   return queue_->size();
196 }
197
198 void EventBase::setMaxReadAtOnce(uint32_t maxAtOnce) {
199   fnRunner_->setMaxReadAtOnce(maxAtOnce);
200 }
201
202 void EventBase::checkIsInEventBaseThread() const {
203   auto evbTid = loopThread_.load(std::memory_order_relaxed);
204   if (evbTid == std::thread::id()) {
205     return;
206   }
207
208   // Using getThreadName(evbTid) instead of name_ will work also if
209   // the thread name is set outside of EventBase (and name_ is empty).
210   auto curTid = std::this_thread::get_id();
211   CHECK(evbTid == curTid)
212       << "This logic must be executed in the event base thread. "
213       << "Event base thread name: \""
214       << folly::getThreadName(evbTid).value_or("")
215       << "\", current thread name: \""
216       << folly::getThreadName(curTid).value_or("") << "\"";
217 }
218
219 // Set smoothing coefficient for loop load average; input is # of milliseconds
220 // for exp(-1) decay.
221 void EventBase::setLoadAvgMsec(std::chrono::milliseconds ms) {
222   assert(enableTimeMeasurement_);
223   std::chrono::microseconds us = std::chrono::milliseconds(ms);
224   if (ms > std::chrono::milliseconds::zero()) {
225     maxLatencyLoopTime_.setTimeInterval(us);
226     avgLoopTime_.setTimeInterval(us);
227   } else {
228     LOG(ERROR) << "non-positive arg to setLoadAvgMsec()";
229   }
230 }
231
232 void EventBase::resetLoadAvg(double value) {
233   assert(enableTimeMeasurement_);
234   avgLoopTime_.reset(value);
235   maxLatencyLoopTime_.reset(value);
236 }
237
238 static std::chrono::milliseconds
239 getTimeDelta(std::chrono::steady_clock::time_point* prev) {
240   auto result = std::chrono::steady_clock::now() - *prev;
241   *prev = std::chrono::steady_clock::now();
242
243   return std::chrono::duration_cast<std::chrono::milliseconds>(result);
244 }
245
246 void EventBase::waitUntilRunning() {
247   while (!isRunning()) {
248     std::this_thread::yield();
249   }
250 }
251
252 // enters the event_base loop -- will only exit when forced to
253 bool EventBase::loop() {
254   return loopBody();
255 }
256
257 bool EventBase::loopOnce(int flags) {
258   return loopBody(flags | EVLOOP_ONCE);
259 }
260
261 bool EventBase::loopBody(int flags) {
262   VLOG(5) << "EventBase(): Starting loop.";
263
264   DCHECK(!invokingLoop_)
265       << "Your code just tried to loop over an event base from inside another "
266       << "event base loop. Since libevent is not reentrant, this leads to "
267       << "undefined behavior in opt builds. Please fix immediately. For the "
268       << "common case of an inner function that needs to do some synchronous "
269       << "computation on an event-base, replace getEventBase() by a new, "
270       << "stack-allocated EvenBase.";
271   invokingLoop_ = true;
272   SCOPE_EXIT {
273     invokingLoop_ = false;
274   };
275
276   int res = 0;
277   bool ranLoopCallbacks;
278   bool blocking = !(flags & EVLOOP_NONBLOCK);
279   bool once = (flags & EVLOOP_ONCE);
280
281   // time-measurement variables.
282   std::chrono::steady_clock::time_point prev;
283   std::chrono::steady_clock::time_point idleStart = {};
284   std::chrono::microseconds busy;
285   std::chrono::microseconds idle;
286
287   loopThread_.store(std::this_thread::get_id(), std::memory_order_release);
288
289   if (!name_.empty()) {
290     setThreadName(name_);
291   }
292
293   if (enableTimeMeasurement_) {
294     prev = std::chrono::steady_clock::now();
295     idleStart = std::chrono::steady_clock::now();
296   }
297
298   while (!stop_.load(std::memory_order_acquire)) {
299     applyLoopKeepAlive();
300     ++nextLoopCnt_;
301
302     // Run the before loop callbacks
303     LoopCallbackList callbacks;
304     callbacks.swap(runBeforeLoopCallbacks_);
305
306     while(!callbacks.empty()) {
307       auto* item = &callbacks.front();
308       callbacks.pop_front();
309       item->runLoopCallback();
310     }
311
312     // nobody can add loop callbacks from within this thread if
313     // we don't have to handle anything to start with...
314     if (blocking && loopCallbacks_.empty()) {
315       res = event_base_loop(evb_, EVLOOP_ONCE);
316     } else {
317       res = event_base_loop(evb_, EVLOOP_ONCE | EVLOOP_NONBLOCK);
318     }
319
320     ranLoopCallbacks = runLoopCallbacks();
321
322     if (enableTimeMeasurement_) {
323       busy = std::chrono::duration_cast<std::chrono::microseconds>(
324           std::chrono::steady_clock::now() - startWork_);
325       idle = std::chrono::duration_cast<std::chrono::microseconds>(
326           startWork_ - idleStart);
327
328       avgLoopTime_.addSample(std::chrono::microseconds(idle),
329         std::chrono::microseconds(busy));
330       maxLatencyLoopTime_.addSample(std::chrono::microseconds(idle),
331         std::chrono::microseconds(busy));
332
333       if (observer_) {
334         if (observerSampleCount_++ == observer_->getSampleRate()) {
335           observerSampleCount_ = 0;
336           observer_->loopSample(busy.count(), idle.count());
337         }
338       }
339
340       VLOG(11) << "EventBase "  << this         << " did not timeout " <<
341         " loop time guess: "    << (busy + idle).count()  <<
342         " idle time: "          << idle.count()         <<
343         " busy time: "          << busy.count()         <<
344         " avgLoopTime: "        << avgLoopTime_.get() <<
345         " maxLatencyLoopTime: " << maxLatencyLoopTime_.get() <<
346         " maxLatency_: "        << maxLatency_.count() << "us" <<
347         " notificationQueueSize: " << getNotificationQueueSize() <<
348         " nothingHandledYet(): " << nothingHandledYet();
349
350       // see if our average loop time has exceeded our limit
351       if ((maxLatency_ > std::chrono::microseconds::zero()) &&
352           (maxLatencyLoopTime_.get() > double(maxLatency_.count()))) {
353         maxLatencyCob_();
354         // back off temporarily -- don't keep spamming maxLatencyCob_
355         // if we're only a bit over the limit
356         maxLatencyLoopTime_.dampen(0.9);
357       }
358
359       // Our loop run did real work; reset the idle timer
360       idleStart = std::chrono::steady_clock::now();
361     } else {
362       VLOG(11) << "EventBase " << this << " did not timeout";
363     }
364
365     // If the event loop indicate that there were no more events, and
366     // we also didn't have any loop callbacks to run, there is nothing left to
367     // do.
368     if (res != 0 && !ranLoopCallbacks) {
369       // Since Notification Queue is marked 'internal' some events may not have
370       // run.  Run them manually if so, and continue looping.
371       //
372       if (getNotificationQueueSize() > 0) {
373         fnRunner_->handlerReady(0);
374       } else {
375         break;
376       }
377     }
378
379     if (enableTimeMeasurement_) {
380       VLOG(11) << "EventBase " << this << " loop time: " <<
381         getTimeDelta(&prev).count();
382     }
383
384     if (once) {
385       break;
386     }
387   }
388   // Reset stop_ so loop() can be called again
389   stop_ = false;
390
391   if (res < 0) {
392     LOG(ERROR) << "EventBase: -- error in event loop, res = " << res;
393     return false;
394   } else if (res == 1) {
395     VLOG(5) << "EventBase: ran out of events (exiting loop)!";
396   } else if (res > 1) {
397     LOG(ERROR) << "EventBase: unknown event loop result = " << res;
398     return false;
399   }
400
401   loopThread_.store({}, std::memory_order_release);
402
403   VLOG(5) << "EventBase(): Done with loop.";
404   return true;
405 }
406
407 ssize_t EventBase::loopKeepAliveCount() {
408   if (loopKeepAliveCountAtomic_.load(std::memory_order_relaxed)) {
409     loopKeepAliveCount_ +=
410         loopKeepAliveCountAtomic_.exchange(0, std::memory_order_relaxed);
411   }
412   DCHECK_GE(loopKeepAliveCount_, 0);
413
414   return loopKeepAliveCount_;
415 }
416
417 void EventBase::applyLoopKeepAlive() {
418   auto keepAliveCount = loopKeepAliveCount();
419   // Make sure default VirtualEventBase won't hold EventBase::loop() forever.
420   if (virtualEventBase_ && virtualEventBase_->keepAliveCount() == 1) {
421     --keepAliveCount;
422   }
423
424   if (loopKeepAliveActive_ && keepAliveCount == 0) {
425     // Restore the notification queue internal flag
426     fnRunner_->stopConsuming();
427     fnRunner_->startConsumingInternal(this, queue_.get());
428     loopKeepAliveActive_ = false;
429   } else if (!loopKeepAliveActive_ && keepAliveCount > 0) {
430     // Update the notification queue event to treat it as a normal
431     // (non-internal) event.  The notification queue event always remains
432     // installed, and the main loop won't exit with it installed.
433     fnRunner_->stopConsuming();
434     fnRunner_->startConsuming(this, queue_.get());
435     loopKeepAliveActive_ = true;
436   }
437 }
438
439 void EventBase::loopForever() {
440   bool ret;
441   {
442     SCOPE_EXIT {
443       applyLoopKeepAlive();
444     };
445     // Make sure notification queue events are treated as normal events.
446     // We can't use loopKeepAlive() here since LoopKeepAlive token can only be
447     // released inside a loop.
448     ++loopKeepAliveCount_;
449     SCOPE_EXIT {
450       --loopKeepAliveCount_;
451     };
452     ret = loop();
453   }
454
455   if (!ret) {
456     folly::throwSystemError("error in EventBase::loopForever()");
457   }
458 }
459
460 void EventBase::bumpHandlingTime() {
461   if (!enableTimeMeasurement_) {
462     return;
463   }
464
465   VLOG(11) << "EventBase " << this << " " << __PRETTY_FUNCTION__ <<
466     " (loop) latest " << latestLoopCnt_ << " next " << nextLoopCnt_;
467   if (nothingHandledYet()) {
468     latestLoopCnt_ = nextLoopCnt_;
469     // set the time
470     startWork_ = std::chrono::steady_clock::now();
471
472     VLOG(11) << "EventBase " << this << " " << __PRETTY_FUNCTION__
473              << " (loop) startWork_ " << startWork_.time_since_epoch().count();
474   }
475 }
476
477 void EventBase::terminateLoopSoon() {
478   VLOG(5) << "EventBase(): Received terminateLoopSoon() command.";
479
480   // Set stop to true, so the event loop will know to exit.
481   // TODO: We should really use an atomic operation here with a release
482   // barrier.
483   stop_ = true;
484
485   // Call event_base_loopbreak() so that libevent will exit the next time
486   // around the loop.
487   event_base_loopbreak(evb_);
488
489   // If terminateLoopSoon() is called from another thread,
490   // the EventBase thread might be stuck waiting for events.
491   // In this case, it won't wake up and notice that stop_ is set until it
492   // receives another event.  Send an empty frame to the notification queue
493   // so that the event loop will wake up even if there are no other events.
494   //
495   // We don't care about the return value of trySendFrame().  If it fails
496   // this likely means the EventBase already has lots of events waiting
497   // anyway.
498   try {
499     queue_->putMessage(nullptr);
500   } catch (...) {
501     // We don't care if putMessage() fails.  This likely means
502     // the EventBase already has lots of events waiting anyway.
503   }
504 }
505
506 void EventBase::runInLoop(LoopCallback* callback, bool thisIteration) {
507   dcheckIsInEventBaseThread();
508   callback->cancelLoopCallback();
509   callback->context_ = RequestContext::saveContext();
510   if (runOnceCallbacks_ != nullptr && thisIteration) {
511     runOnceCallbacks_->push_back(*callback);
512   } else {
513     loopCallbacks_.push_back(*callback);
514   }
515 }
516
517 void EventBase::runInLoop(Func cob, bool thisIteration) {
518   dcheckIsInEventBaseThread();
519   auto wrapper = new FunctionLoopCallback(std::move(cob));
520   wrapper->context_ = RequestContext::saveContext();
521   if (runOnceCallbacks_ != nullptr && thisIteration) {
522     runOnceCallbacks_->push_back(*wrapper);
523   } else {
524     loopCallbacks_.push_back(*wrapper);
525   }
526 }
527
528 void EventBase::runOnDestruction(LoopCallback* callback) {
529   std::lock_guard<std::mutex> lg(onDestructionCallbacksMutex_);
530   callback->cancelLoopCallback();
531   onDestructionCallbacks_.push_back(*callback);
532 }
533
534 void EventBase::runBeforeLoop(LoopCallback* callback) {
535   dcheckIsInEventBaseThread();
536   callback->cancelLoopCallback();
537   runBeforeLoopCallbacks_.push_back(*callback);
538 }
539
540 bool EventBase::runInEventBaseThread(Func fn) {
541   // Send the message.
542   // It will be received by the FunctionRunner in the EventBase's thread.
543
544   // We try not to schedule nullptr callbacks
545   if (!fn) {
546     LOG(ERROR) << "EventBase " << this
547                << ": Scheduling nullptr callbacks is not allowed";
548     return false;
549   }
550
551   // Short-circuit if we are already in our event base
552   if (inRunningEventBaseThread()) {
553     runInLoop(std::move(fn));
554     return true;
555
556   }
557
558   try {
559     queue_->putMessage(std::move(fn));
560   } catch (const std::exception& ex) {
561     LOG(ERROR) << "EventBase " << this << ": failed to schedule function "
562                << "for EventBase thread: " << ex.what();
563     return false;
564   }
565
566   return true;
567 }
568
569 bool EventBase::runInEventBaseThreadAndWait(FuncRef fn) {
570   if (inRunningEventBaseThread()) {
571     LOG(ERROR) << "EventBase " << this << ": Waiting in the event loop is not "
572                << "allowed";
573     return false;
574   }
575
576   Baton<> ready;
577   runInEventBaseThread([&] {
578     SCOPE_EXIT {
579       ready.post();
580     };
581     fn();
582   });
583   ready.wait();
584
585   return true;
586 }
587
588 bool EventBase::runImmediatelyOrRunInEventBaseThreadAndWait(FuncRef fn) {
589   if (isInEventBaseThread()) {
590     fn();
591     return true;
592   } else {
593     return runInEventBaseThreadAndWait(std::move(fn));
594   }
595 }
596
597 bool EventBase::runLoopCallbacks() {
598   if (!loopCallbacks_.empty()) {
599     bumpHandlingTime();
600     // Swap the loopCallbacks_ list with a temporary list on our stack.
601     // This way we will only run callbacks scheduled at the time
602     // runLoopCallbacks() was invoked.
603     //
604     // If any of these callbacks in turn call runInLoop() to schedule more
605     // callbacks, those new callbacks won't be run until the next iteration
606     // around the event loop.  This prevents runInLoop() callbacks from being
607     // able to start file descriptor and timeout based events.
608     LoopCallbackList currentCallbacks;
609     currentCallbacks.swap(loopCallbacks_);
610     runOnceCallbacks_ = &currentCallbacks;
611
612     while (!currentCallbacks.empty()) {
613       LoopCallback* callback = &currentCallbacks.front();
614       currentCallbacks.pop_front();
615       folly::RequestContextScopeGuard rctx(callback->context_);
616       callback->runLoopCallback();
617     }
618
619     runOnceCallbacks_ = nullptr;
620     return true;
621   }
622   return false;
623 }
624
625 void EventBase::initNotificationQueue() {
626   // Infinite size queue
627   queue_.reset(new NotificationQueue<Func>());
628
629   // We allocate fnRunner_ separately, rather than declaring it directly
630   // as a member of EventBase solely so that we don't need to include
631   // NotificationQueue.h from EventBase.h
632   fnRunner_.reset(new FunctionRunner());
633
634   // Mark this as an internal event, so event_base_loop() will return if
635   // there are no other events besides this one installed.
636   //
637   // Most callers don't care about the internal notification queue used by
638   // EventBase.  The queue is always installed, so if we did count the queue as
639   // an active event, loop() would never exit with no more events to process.
640   // Users can use loopForever() if they do care about the notification queue.
641   // (This is useful for EventBase threads that do nothing but process
642   // runInEventBaseThread() notifications.)
643   fnRunner_->startConsumingInternal(this, queue_.get());
644 }
645
646 void EventBase::SmoothLoopTime::setTimeInterval(
647     std::chrono::microseconds timeInterval) {
648   expCoeff_ = -1.0 / timeInterval.count();
649   VLOG(11) << "expCoeff_ " << expCoeff_ << " " << __PRETTY_FUNCTION__;
650 }
651
652 void EventBase::SmoothLoopTime::reset(double value) {
653   value_ = value;
654 }
655
656 void EventBase::SmoothLoopTime::addSample(
657     std::chrono::microseconds idle,
658     std::chrono::microseconds busy) {
659   /*
660    * Position at which the busy sample is considered to be taken.
661    * (Allows to quickly skew our average without editing much code)
662    */
663   enum BusySamplePosition {
664     RIGHT = 0, // busy sample placed at the end of the iteration
665     CENTER = 1, // busy sample placed at the middle point of the iteration
666     LEFT = 2, // busy sample placed at the beginning of the iteration
667   };
668
669   // See http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
670   // and D676020 for more info on this calculation.
671   VLOG(11) << "idle " << idle.count() << " oldBusyLeftover_ "
672            << oldBusyLeftover_.count() << " idle + oldBusyLeftover_ "
673            << (idle + oldBusyLeftover_).count() << " busy " << busy.count()
674            << " " << __PRETTY_FUNCTION__;
675   idle += oldBusyLeftover_ + busy;
676   oldBusyLeftover_ = (busy * BusySamplePosition::CENTER) / 2;
677   idle -= oldBusyLeftover_;
678
679   double coeff = exp(idle.count() * expCoeff_);
680   value_ *= coeff;
681   value_ += (1.0 - coeff) * busy.count();
682 }
683
684 bool EventBase::nothingHandledYet() const noexcept {
685   VLOG(11) << "latest " << latestLoopCnt_ << " next " << nextLoopCnt_;
686   return (nextLoopCnt_ != latestLoopCnt_);
687 }
688
689 void EventBase::attachTimeoutManager(AsyncTimeout* obj,
690                                       InternalEnum internal) {
691
692   struct event* ev = obj->getEvent();
693   assert(ev->ev_base == nullptr);
694
695   event_base_set(getLibeventBase(), ev);
696   if (internal == AsyncTimeout::InternalEnum::INTERNAL) {
697     // Set the EVLIST_INTERNAL flag
698     event_ref_flags(ev) |= EVLIST_INTERNAL;
699   }
700 }
701
702 void EventBase::detachTimeoutManager(AsyncTimeout* obj) {
703   cancelTimeout(obj);
704   struct event* ev = obj->getEvent();
705   ev->ev_base = nullptr;
706 }
707
708 bool EventBase::scheduleTimeout(AsyncTimeout* obj,
709                                  TimeoutManager::timeout_type timeout) {
710   dcheckIsInEventBaseThread();
711   // Set up the timeval and add the event
712   struct timeval tv;
713   tv.tv_sec = long(timeout.count() / 1000LL);
714   tv.tv_usec = long((timeout.count() % 1000LL) * 1000LL);
715
716   struct event* ev = obj->getEvent();
717   if (event_add(ev, &tv) < 0) {
718     LOG(ERROR) << "EventBase: failed to schedule timeout: " << strerror(errno);
719     return false;
720   }
721
722   return true;
723 }
724
725 void EventBase::cancelTimeout(AsyncTimeout* obj) {
726   dcheckIsInEventBaseThread();
727   struct event* ev = obj->getEvent();
728   if (EventUtil::isEventRegistered(ev)) {
729     event_del(ev);
730   }
731 }
732
733 void EventBase::setName(const std::string& name) {
734   dcheckIsInEventBaseThread();
735   name_ = name;
736
737   if (isRunning()) {
738     setThreadName(loopThread_.load(std::memory_order_relaxed),
739                   name_);
740   }
741 }
742
743 const std::string& EventBase::getName() {
744   dcheckIsInEventBaseThread();
745   return name_;
746 }
747
748 const char* EventBase::getLibeventVersion() { return event_get_version(); }
749 const char* EventBase::getLibeventMethod() { return event_get_method(); }
750
751 VirtualEventBase& EventBase::getVirtualEventBase() {
752   folly::call_once(virtualEventBaseInitFlag_, [&] {
753     virtualEventBase_ = std::make_unique<VirtualEventBase>(*this);
754   });
755
756   return *virtualEventBase_;
757 }
758
759 } // namespace folly