1/*
2 * Copyright 2018-present 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#pragma once
18
19#include <folly/DefaultKeepAliveExecutor.h>
20
21namespace folly {
22
23/**
24 * VirtualExecutor implements a light-weight view onto existing Executor.
25 *
26 * Multiple VirtualExecutors can be backed by a single Executor.
27 *
28 * VirtualExecutor's destructor blocks until all tasks scheduled through it are
29 * complete. Executor's destructor also blocks until all VirtualExecutors
30 * backed by it are released.
31 */
32class VirtualExecutor : public DefaultKeepAliveExecutor {
33 auto wrapFunc(Func f) {
34 class FuncAndKeepAlive {
35 public:
36 FuncAndKeepAlive(Func&& f, VirtualExecutor* executor)
37 : keepAlive_(getKeepAliveToken(executor)), f_(std::move(f)) {}
38
39 void operator()() {
40 f_();
41 }
42
43 private:
44 Executor::KeepAlive<VirtualExecutor> keepAlive_;
45 Func f_;
46 };
47
48 return FuncAndKeepAlive(std::move(f), this);
49 }
50
51 public:
52 explicit VirtualExecutor(KeepAlive<> executor)
53 : executor_(std::move(executor)) {
54 assert(!isKeepAliveDummy(executor_));
55 }
56
57 explicit VirtualExecutor(Executor* executor)
58 : VirtualExecutor(getKeepAliveToken(executor)) {}
59
60 explicit VirtualExecutor(Executor& executor)
61 : VirtualExecutor(getKeepAliveToken(executor)) {}
62
63 VirtualExecutor(const VirtualExecutor&) = delete;
64 VirtualExecutor& operator=(const VirtualExecutor&) = delete;
65
66 uint8_t getNumPriorities() const override {
67 return executor_->getNumPriorities();
68 }
69
70 void add(Func f) override {
71 executor_->add(wrapFunc(std::move(f)));
72 }
73
74 void addWithPriority(Func f, int8_t priority) override {
75 executor_->addWithPriority(wrapFunc(std::move(f)), priority);
76 }
77
78 ~VirtualExecutor() override {
79 joinKeepAlive();
80 }
81
82 private:
83 const KeepAlive<> executor_;
84};
85
86} // namespace folly
87