X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Fio%2Fasync%2FEventBase.h;h=50d2aef8cd240bff0558be48c1ce7229ef2b1fa4;hp=cc23fed266b4799fd750a0f81420f53f4896bb18;hb=cacdd1d54a32c2740fa9dda4ac83b11d2d398820;hpb=b2dd1005bb5bb6435214d541f3902e022d237f03 diff --git a/folly/io/async/EventBase.h b/folly/io/async/EventBase.h index cc23fed2..50d2aef8 100644 --- a/folly/io/async/EventBase.h +++ b/folly/io/async/EventBase.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Facebook, Inc. + * Copyright 2017-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #pragma once #include +#include +#include #include -#include #include #include -#include #include #include #include @@ -33,20 +32,20 @@ #include #include +#include #include #include #include #include +#include #include -#include #include #include #include #include -#include - -#include // libevent +#include +#include namespace folly { @@ -62,7 +61,7 @@ class EventBaseLocalBaseBase { virtual void onEventBaseDestruction(EventBase& evb) = 0; virtual ~EventBaseLocalBaseBase() = default; }; -} +} // namespace detail template class EventBaseLocal; @@ -95,6 +94,10 @@ class RequestEventBase : public RequestData { std::unique_ptr(new RequestEventBase(eb))); } + bool hasCallback() override { + return false; + } + private: explicit RequestEventBase(EventBase* eb) : eb_(eb) {} EventBase* eb_; @@ -126,7 +129,6 @@ class EventBase : private boost::noncopyable, public DrivableExecutor { public: using Func = folly::Function; - using FuncRef = folly::FunctionRef; /** * A callback interface to use with runInLoop() @@ -147,6 +149,7 @@ class EventBase : private boost::noncopyable, virtual void runLoopCallback() noexcept = 0; void cancelLoopCallback() { + context_.reset(); unlink(); } @@ -195,6 +198,13 @@ class EventBase : private boost::noncopyable, Func function_; }; + /** + * Create a new EventBase object. + * + * Same as EventBase(true), which constructs an EventBase that measures time. + */ + EventBase() : EventBase(true) {} + /** * Create a new EventBase object. * @@ -204,7 +214,7 @@ class EventBase : private boost::noncopyable, * that relies on time-measurement, including: * observer, max latency and avg loop time. */ - explicit EventBase(bool enableTimeMeasurement = true); + explicit EventBase(bool enableTimeMeasurement); /** * Create a new EventBase object that will use the specified libevent @@ -220,7 +230,7 @@ class EventBase : private boost::noncopyable, * observer, max latency and avg loop time. */ explicit EventBase(event_base* evb, bool enableTimeMeasurement = true); - ~EventBase(); + ~EventBase() override; /** * Runs the event loop. @@ -416,7 +426,7 @@ class EventBase : private boost::noncopyable, * Like runInEventBaseThread, but the caller waits for the callback to be * executed. */ - bool runInEventBaseThreadAndWait(FuncRef fn); + bool runInEventBaseThreadAndWait(Func fn); /* * Like runInEventBaseThreadAndWait, except if the caller is already in the @@ -429,7 +439,7 @@ class EventBase : private boost::noncopyable, * Like runInEventBaseThreadAndWait, except if the caller is already in the * event base thread, the functor is simply run inline. */ - bool runImmediatelyOrRunInEventBaseThreadAndWait(FuncRef fn); + bool runImmediatelyOrRunInEventBaseThreadAndWait(Func fn); /** * Set the maximum desired latency in us and provide a callback which will be @@ -491,6 +501,18 @@ class EventBase : private boost::noncopyable, std::this_thread::get_id(); } + /** + * Equivalent to CHECK(isInEventBaseThread()) (and assert/DCHECK for + * dcheckIsInEventBaseThread), but it prints more information on + * failure. + */ + void checkIsInEventBaseThread() const; + void dcheckIsInEventBaseThread() const { + if (kIsDebug) { + checkIsInEventBaseThread(); + } + } + HHWheelTimer& timer() { if (!wheelTimer_) { wheelTimer_ = HHWheelTimer::newTimer(this); @@ -514,7 +536,7 @@ class EventBase : private boost::noncopyable, * first handler fired within that cycle. * */ - void bumpHandlingTime() override final; + void bumpHandlingTime() final; class SmoothLoopTime { public: @@ -591,8 +613,6 @@ class EventBase : private boost::noncopyable, /// Implements the DrivableExecutor interface void drive() override { - // We can't use loopKeepAlive() here since LoopKeepAlive token can only be - // released inside a loop. ++loopKeepAliveCount_; SCOPE_EXIT { --loopKeepAliveCount_; @@ -600,51 +620,55 @@ class EventBase : private boost::noncopyable, loopOnce(); } - struct LoopKeepAliveDeleter { - void operator()(EventBase* evb) { - DCHECK(evb->isInEventBaseThread()); - evb->loopKeepAliveCount_--; - } - }; - using LoopKeepAlive = std::unique_ptr; - /// Returns you a handle which make loop() behave like loopForever() until /// destroyed. loop() will return to its original behavior only when all - /// loop keep-alives are released. Loop holder is safe to release only from - /// EventBase thread. - /// - /// May return no op LoopKeepAlive if loopForever() is already running. - LoopKeepAlive loopKeepAlive() { - DCHECK(isInEventBaseThread()); - loopKeepAliveCount_++; - return LoopKeepAlive(this); - } - - // Thread-safe version of loopKeepAlive() - LoopKeepAlive loopKeepAliveAtomic() { - if (inRunningEventBaseThread()) { - return loopKeepAlive(); - } - loopKeepAliveCountAtomic_.fetch_add(1, std::memory_order_relaxed); - return LoopKeepAlive(this); + /// loop keep-alives are released. + KeepAlive getKeepAliveToken() override { + keepAliveAcquire(); + return makeKeepAlive(); } // TimeoutManager void attachTimeoutManager( AsyncTimeout* obj, - TimeoutManager::InternalEnum internal) override final; + TimeoutManager::InternalEnum internal) final; - void detachTimeoutManager(AsyncTimeout* obj) override final; + void detachTimeoutManager(AsyncTimeout* obj) final; bool scheduleTimeout(AsyncTimeout* obj, TimeoutManager::timeout_type timeout) - override final; + final; - void cancelTimeout(AsyncTimeout* obj) override final; + void cancelTimeout(AsyncTimeout* obj) final; - bool isInTimeoutManagerThread() override final { + bool isInTimeoutManagerThread() final { return isInEventBaseThread(); } + // Returns a VirtualEventBase attached to this EventBase. Can be used to + // pass to APIs which expect VirtualEventBase. This VirtualEventBase will be + // destroyed together with the EventBase. + // + // Any number of VirtualEventBases instances may be independently constructed, + // which are backed by this EventBase. This method should be only used if you + // don't need to manage the life time of the VirtualEventBase used. + folly::VirtualEventBase& getVirtualEventBase(); + + protected: + void keepAliveAcquire() override { + if (inRunningEventBaseThread()) { + loopKeepAliveCount_++; + } else { + loopKeepAliveCountAtomic_.fetch_add(1, std::memory_order_relaxed); + } + } + + void keepAliveRelease() override { + if (!inRunningEventBaseThread()) { + return add([=] { keepAliveRelease(); }); + } + loopKeepAliveCount_--; + } + private: void applyLoopKeepAlive(); @@ -743,9 +767,11 @@ class EventBase : private boost::noncopyable, // see EventBaseLocal friend class detail::EventBaseLocalBase; template friend class EventBaseLocal; - std::mutex localStorageMutex_; std::unordered_map> localStorage_; std::unordered_set localStorageToDtor_; + + folly::once_flag virtualEventBaseInitFlag_; + std::unique_ptr virtualEventBase_; }; template @@ -765,4 +791,4 @@ bool EventBase::runImmediatelyOrRunInEventBaseThreadAndWait( return runImmediatelyOrRunInEventBaseThreadAndWait([=] { fn(arg); }); } -} // folly +} // namespace folly