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.
19 #include <folly/Baton.h>
20 #include <folly/Executor.h>
21 #include <folly/io/async/EventBase.h>
26 * VirtualEventBase implements a light-weight view onto existing EventBase.
28 * Multiple VirtualEventBases can be backed by a single EventBase. Similarly
29 * to EventBase, VirtualEventBase implements loopKeepAlive() functionality,
30 * which allows callbacks holding LoopKeepAlive token to keep EventBase looping
31 * until they are complete.
33 * VirtualEventBase destructor blocks until all its KeepAliveTokens are released
34 * and all tasks scheduled through it are complete. EventBase destructor also
35 * blocks until all VirtualEventBases backed by it are released.
37 class VirtualEventBase : public folly::Executor, public folly::TimeoutManager {
39 explicit VirtualEventBase(EventBase& evb);
41 VirtualEventBase(const VirtualEventBase&) = delete;
42 VirtualEventBase& operator=(const VirtualEventBase&) = delete;
46 EventBase& getEventBase() {
51 * Adds the given callback to a queue of things run before destruction
52 * of current VirtualEventBase.
54 * This allows users of VirtualEventBase that run in it, but don't control it,
55 * to be notified before VirtualEventBase gets destructed.
57 * Note: this will be called from the loop of the EventBase, backing this
60 void runOnDestruction(EventBase::LoopCallback* callback);
63 * @see EventBase::runInLoop
66 void runInLoop(F&& f, bool thisIteration = false) {
67 evb_.runInLoop(std::forward<F>(f), thisIteration);
71 * VirtualEventBase destructor blocks until all tasks scheduled through its
72 * runInEventBaseThread are complete.
74 * @see EventBase::runInEventBaseThread
77 void runInEventBaseThread(F&& f) {
78 // LoopKeepAlive token has to be released in the EventBase thread. If
79 // runInEventBaseThread() fails, we can't extract the LoopKeepAlive token
80 // from the callback to properly release it.
81 CHECK(evb_.runInEventBaseThread([
82 keepAlive = loopKeepAliveAtomic(),
83 f = std::forward<F>(f)
84 ]() mutable { f(); }));
87 HHWheelTimer& timer() {
91 void attachTimeoutManager(
93 TimeoutManager::InternalEnum internal) override {
94 evb_.attachTimeoutManager(obj, internal);
97 void detachTimeoutManager(AsyncTimeout* obj) override {
98 evb_.detachTimeoutManager(obj);
101 bool scheduleTimeout(AsyncTimeout* obj, TimeoutManager::timeout_type timeout)
103 return evb_.scheduleTimeout(obj, timeout);
106 void cancelTimeout(AsyncTimeout* obj) override {
107 evb_.cancelTimeout(obj);
110 void bumpHandlingTime() override {
111 evb_.bumpHandlingTime();
114 bool isInTimeoutManagerThread() override {
115 return evb_.isInTimeoutManagerThread();
119 * @see runInEventBaseThread
121 void add(folly::Func f) override {
122 runInEventBaseThread(std::move(f));
125 struct LoopKeepAliveDeleter {
126 void operator()(VirtualEventBase* evb) {
127 DCHECK(evb->getEventBase().inRunningEventBaseThread());
128 if (evb->loopKeepAliveCountAtomic_.load()) {
129 evb->loopKeepAliveCount_ += evb->loopKeepAliveCountAtomic_.exchange(0);
131 DCHECK(evb->loopKeepAliveCount_ > 0);
132 if (--evb->loopKeepAliveCount_ == 0) {
133 evb->loopKeepAliveBaton_.post();
137 using LoopKeepAlive = std::unique_ptr<VirtualEventBase, LoopKeepAliveDeleter>;
140 * Returns you a handle which prevents VirtualEventBase from being destroyed.
141 * LoopKeepAlive handle can be released from EventBase loop only.
143 * loopKeepAlive() can be called from EventBase thread only.
145 LoopKeepAlive loopKeepAlive() {
146 DCHECK(evb_.isInEventBaseThread());
147 ++loopKeepAliveCount_;
148 return LoopKeepAlive(this);
152 * Thread-safe version of loopKeepAlive()
154 LoopKeepAlive loopKeepAliveAtomic() {
155 if (evb_.inRunningEventBaseThread()) {
156 return loopKeepAlive();
158 ++loopKeepAliveCountAtomic_;
159 return LoopKeepAlive(this);
162 bool inRunningEventBaseThread() const {
163 return evb_.inRunningEventBaseThread();
167 using LoopCallbackList = EventBase::LoopCallback::List;
171 ssize_t loopKeepAliveCount_{0};
172 std::atomic<ssize_t> loopKeepAliveCountAtomic_{0};
173 folly::Baton<> loopKeepAliveBaton_;
174 LoopKeepAlive loopKeepAlive_;
176 EventBase::LoopKeepAlive evbLoopKeepAlive_;
178 folly::Synchronized<LoopCallbackList> onDestructionCallbacks_;