2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <folly/Baton.h>
22 #include <folly/Executor.h>
23 #include <folly/io/async/EventBase.h>
28 * VirtualEventBase implements a light-weight view onto existing EventBase.
30 * Multiple VirtualEventBases can be backed by a single EventBase. Similarly
31 * to EventBase, VirtualEventBase implements loopKeepAlive() functionality,
32 * which allows callbacks holding KeepAlive token to keep EventBase looping
33 * until they are complete.
35 * VirtualEventBase destructor blocks until all its KeepAliveTokens are released
36 * and all tasks scheduled through it are complete. EventBase destructor also
37 * blocks until all VirtualEventBases backed by it are released.
39 class VirtualEventBase : public folly::Executor, public folly::TimeoutManager {
41 explicit VirtualEventBase(EventBase& evb);
43 VirtualEventBase(const VirtualEventBase&) = delete;
44 VirtualEventBase& operator=(const VirtualEventBase&) = delete;
48 EventBase& getEventBase() {
53 * Adds the given callback to a queue of things run before destruction
54 * of current VirtualEventBase.
56 * This allows users of VirtualEventBase that run in it, but don't control it,
57 * to be notified before VirtualEventBase gets destructed.
59 * Note: this will be called from the loop of the EventBase, backing this
62 void runOnDestruction(EventBase::LoopCallback* callback);
65 * @see EventBase::runInLoop
68 void runInLoop(F&& f, bool thisIteration = false) {
69 evb_.runInLoop(std::forward<F>(f), thisIteration);
73 * VirtualEventBase destructor blocks until all tasks scheduled through its
74 * runInEventBaseThread are complete.
76 * @see EventBase::runInEventBaseThread
79 void runInEventBaseThread(F&& f) {
80 // KeepAlive token has to be released in the EventBase thread. If
81 // runInEventBaseThread() fails, we can't extract the KeepAlive token
82 // from the callback to properly release it.
83 CHECK(evb_.runInEventBaseThread([
84 keepAliveToken = getKeepAliveToken(),
85 f = std::forward<F>(f)
86 ]() mutable { f(); }));
89 HHWheelTimer& timer() {
93 void attachTimeoutManager(
95 TimeoutManager::InternalEnum internal) override {
96 evb_.attachTimeoutManager(obj, internal);
99 void detachTimeoutManager(AsyncTimeout* obj) override {
100 evb_.detachTimeoutManager(obj);
103 bool scheduleTimeout(AsyncTimeout* obj, TimeoutManager::timeout_type timeout)
105 return evb_.scheduleTimeout(obj, timeout);
108 void cancelTimeout(AsyncTimeout* obj) override {
109 evb_.cancelTimeout(obj);
112 void bumpHandlingTime() override {
113 evb_.bumpHandlingTime();
116 bool isInTimeoutManagerThread() override {
117 return evb_.isInTimeoutManagerThread();
121 * @see runInEventBaseThread
123 void add(folly::Func f) override {
124 runInEventBaseThread(std::move(f));
128 * Returns you a handle which prevents VirtualEventBase from being destroyed.
129 * KeepAlive handle can be released from EventBase loop only.
131 KeepAlive getKeepAliveToken() override {
132 if (evb_.inRunningEventBaseThread()) {
133 ++loopKeepAliveCount_;
135 ++loopKeepAliveCountAtomic_;
137 return makeKeepAlive();
140 bool inRunningEventBaseThread() const {
141 return evb_.inRunningEventBaseThread();
145 void keepAliveRelease() override {
146 DCHECK(getEventBase().inRunningEventBaseThread());
147 if (loopKeepAliveCountAtomic_.load()) {
148 loopKeepAliveCount_ += loopKeepAliveCountAtomic_.exchange(0);
150 DCHECK(loopKeepAliveCount_ > 0);
151 if (--loopKeepAliveCount_ == 0) {
157 friend class EventBase;
159 std::future<void> destroy();
162 using LoopCallbackList = EventBase::LoopCallback::List;
166 ssize_t loopKeepAliveCount_{0};
167 std::atomic<ssize_t> loopKeepAliveCountAtomic_{0};
168 std::promise<void> destroyPromise_;
169 std::future<void> destroyFuture_{destroyPromise_.get_future()};
170 KeepAlive loopKeepAlive_;
172 KeepAlive evbLoopKeepAlive_;
174 folly::Synchronized<LoopCallbackList> onDestructionCallbacks_;