ef85375171ff5f4f65be06b3192ae835f7a809b4
[folly.git] / folly / executors / GlobalExecutor.cpp
1 /*
2  * Copyright 2017 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 #include <folly/Singleton.h>
18 #include <folly/executors/IOExecutor.h>
19 #include <folly/executors/IOThreadPoolExecutor.h>
20 #include <folly/executors/InlineExecutor.h>
21
22 using namespace folly;
23
24 namespace {
25
26 // lock protecting global CPU executor
27 struct CPUExecutorLock {};
28 Singleton<RWSpinLock, CPUExecutorLock> globalCPUExecutorLock;
29 // global CPU executor
30 Singleton<std::weak_ptr<Executor>> globalCPUExecutor;
31 // default global CPU executor is an InlineExecutor
32 Singleton<std::shared_ptr<InlineExecutor>> globalInlineExecutor([] {
33   return new std::shared_ptr<InlineExecutor>(
34       std::make_shared<InlineExecutor>());
35 });
36
37 // lock protecting global IO executor
38 struct IOExecutorLock {};
39 Singleton<RWSpinLock, IOExecutorLock> globalIOExecutorLock;
40 // global IO executor
41 Singleton<std::weak_ptr<IOExecutor>> globalIOExecutor;
42 // default global IO executor is an IOThreadPoolExecutor
43 Singleton<std::shared_ptr<IOThreadPoolExecutor>> globalIOThreadPool([] {
44   return new std::shared_ptr<IOThreadPoolExecutor>(
45       std::make_shared<IOThreadPoolExecutor>(
46           sysconf(_SC_NPROCESSORS_ONLN),
47           std::make_shared<NamedThreadFactory>("GlobalIOThreadPool")));
48 });
49 }
50
51 namespace folly {
52
53 template <class Exe, class DefaultExe, class LockTag>
54 std::shared_ptr<Exe> getExecutor(
55     Singleton<std::weak_ptr<Exe>>& sExecutor,
56     Singleton<std::shared_ptr<DefaultExe>>& sDefaultExecutor,
57     Singleton<RWSpinLock, LockTag>& sExecutorLock) {
58   std::shared_ptr<Exe> executor;
59   auto singleton = sExecutor.try_get();
60   auto lock = sExecutorLock.try_get();
61
62   {
63     RWSpinLock::ReadHolder guard(lock.get());
64     if ((executor = sExecutor.try_get()->lock())) {
65       return executor;
66     }
67   }
68
69   RWSpinLock::WriteHolder guard(lock.get());
70   executor = singleton->lock();
71   if (!executor) {
72     std::weak_ptr<Exe> defaultExecutor = *sDefaultExecutor.try_get().get();
73     executor = defaultExecutor.lock();
74     sExecutor.try_get().get()->swap(defaultExecutor);
75   }
76   return executor;
77 }
78
79 template <class Exe, class LockTag>
80 void setExecutor(
81     std::weak_ptr<Exe> executor,
82     Singleton<std::weak_ptr<Exe>>& sExecutor,
83     Singleton<RWSpinLock, LockTag>& sExecutorLock) {
84   auto lock = sExecutorLock.try_get();
85   RWSpinLock::WriteHolder guard(*lock);
86   std::weak_ptr<Exe> executor_weak = std::move(executor);
87   sExecutor.try_get().get()->swap(executor_weak);
88 }
89
90 std::shared_ptr<Executor> getCPUExecutor() {
91   return getExecutor(
92       globalCPUExecutor, globalInlineExecutor, globalCPUExecutorLock);
93 }
94
95 void setCPUExecutor(std::weak_ptr<Executor> executor) {
96   setExecutor(std::move(executor), globalCPUExecutor, globalCPUExecutorLock);
97 }
98
99 std::shared_ptr<IOExecutor> getIOExecutor() {
100   return getExecutor(
101       globalIOExecutor, globalIOThreadPool, globalIOExecutorLock);
102 }
103
104 EventBase* getEventBase() {
105   return getIOExecutor()->getEventBase();
106 }
107
108 void setIOExecutor(std::weak_ptr<IOExecutor> executor) {
109   setExecutor(std::move(executor), globalIOExecutor, globalIOExecutorLock);
110 }
111
112 } // namespace folly