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;
46 ~VirtualEventBase() override;
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 * VirtualEventBase destructor blocks until all tasks scheduled through its
66 * runInEventBaseThread are complete.
68 * @see EventBase::runInEventBaseThread
71 void runInEventBaseThread(F&& f) {
72 // KeepAlive token has to be released in the EventBase thread. If
73 // runInEventBaseThread() fails, we can't extract the KeepAlive token
74 // from the callback to properly release it.
75 CHECK(evb_.runInEventBaseThread([
76 keepAliveToken = getKeepAliveToken(),
77 f = std::forward<F>(f)
78 ]() mutable { f(); }));
81 HHWheelTimer& timer() {
85 void attachTimeoutManager(
87 TimeoutManager::InternalEnum internal) override {
88 evb_.attachTimeoutManager(obj, internal);
91 void detachTimeoutManager(AsyncTimeout* obj) override {
92 evb_.detachTimeoutManager(obj);
95 bool scheduleTimeout(AsyncTimeout* obj, TimeoutManager::timeout_type timeout)
97 return evb_.scheduleTimeout(obj, timeout);
100 void cancelTimeout(AsyncTimeout* obj) override {
101 evb_.cancelTimeout(obj);
104 void bumpHandlingTime() override {
105 evb_.bumpHandlingTime();
108 bool isInTimeoutManagerThread() override {
109 return evb_.isInTimeoutManagerThread();
113 * @see runInEventBaseThread
115 void add(folly::Func f) override {
116 runInEventBaseThread(std::move(f));
120 * Returns you a handle which prevents VirtualEventBase from being destroyed.
122 KeepAlive getKeepAliveToken() override {
124 return makeKeepAlive();
127 bool inRunningEventBaseThread() const {
128 return evb_.inRunningEventBaseThread();
132 void keepAliveAcquire() override {
133 DCHECK(loopKeepAliveCount_ + loopKeepAliveCountAtomic_.load() > 0);
135 if (evb_.inRunningEventBaseThread()) {
136 ++loopKeepAliveCount_;
138 ++loopKeepAliveCountAtomic_;
142 void keepAliveRelease() override {
143 if (!inRunningEventBaseThread()) {
144 return add([=] { keepAliveRelease(); });
146 if (loopKeepAliveCountAtomic_.load()) {
147 loopKeepAliveCount_ += loopKeepAliveCountAtomic_.exchange(0);
149 DCHECK(loopKeepAliveCount_ > 0);
150 if (--loopKeepAliveCount_ == 0) {
156 friend class EventBase;
158 ssize_t keepAliveCount() {
159 if (loopKeepAliveCountAtomic_.load()) {
160 loopKeepAliveCount_ += loopKeepAliveCountAtomic_.exchange(0);
162 return loopKeepAliveCount_;
165 std::future<void> destroy();
168 using LoopCallbackList = EventBase::LoopCallback::List;
172 ssize_t loopKeepAliveCount_{1};
173 std::atomic<ssize_t> loopKeepAliveCountAtomic_{0};
174 std::promise<void> destroyPromise_;
175 std::future<void> destroyFuture_{destroyPromise_.get_future()};
176 KeepAlive loopKeepAlive_{makeKeepAlive()};
178 KeepAlive evbLoopKeepAlive_;
180 folly::Synchronized<LoopCallbackList> onDestructionCallbacks_;