1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ipc_thread_pool.h"
17
18 #include <dlfcn.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21
22 #ifdef CONFIG_ACTV_BINDER
23 #include "binder_invoker.h"
24 #endif
25
26 #include "ipc_debug.h"
27 #include "log_tags.h"
28
29 namespace OHOS {
30 #ifdef CONFIG_IPC_SINGLE
31 namespace IPC_SINGLE {
32 #endif
33
34 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC_COMMON, "IPCWorkThreadPool" };
35
36 static void *g_selfSoHandler = nullptr;
37
38 // this func is called when ipc_single and ipc_core before loading
InitIpcSo()39 extern "C" __attribute__((constructor)) void InitIpcSo()
40 {
41 if (g_selfSoHandler == nullptr) {
42 Dl_info info;
43 // dladdr func return value description
44 // On success, these functions return a nonzero value.
45 // If the address specified in addr could not be matched to a shared object, then these functions return 0
46 int ret = dladdr(reinterpret_cast<void *>(InitIpcSo), &info);
47 if (ret == 0) {
48 ZLOGE(LOG_LABEL, "dladdr func call failed");
49 return;
50 }
51 g_selfSoHandler = dlopen(info.dli_fname, RTLD_LAZY);
52 }
53 }
54
IPCWorkThreadPool(int maxThreadNum)55 IPCWorkThreadPool::IPCWorkThreadPool(int maxThreadNum)
56 : threadSequence_(0),
57 maxThreadNum_(maxThreadNum + maxThreadNum),
58 idleThreadNum_(maxThreadNum),
59 idleSocketThreadNum_(maxThreadNum)
60 {}
61
~IPCWorkThreadPool()62 IPCWorkThreadPool::~IPCWorkThreadPool()
63 {
64 StopAllThreads();
65 }
66
StopAllThreads()67 void IPCWorkThreadPool::StopAllThreads()
68 {
69 std::lock_guard<std::mutex> lock(mutex_);
70 for (auto it = threads_.begin(); it != threads_.end(); it++) {
71 it->second->StopWorkThread();
72 }
73 threads_.clear();
74 }
75
SpawnThread(int policy,int proto)76 bool IPCWorkThreadPool::SpawnThread(int policy, int proto)
77 {
78 std::lock_guard<std::mutex> lock(mutex_);
79 if (!(proto == IRemoteObject::IF_PROT_DEFAULT && idleThreadNum_ > 0) &&
80 !(proto == IRemoteObject::IF_PROT_DATABUS && idleSocketThreadNum_ > 0)) {
81 return false;
82 }
83 #ifdef CONFIG_ACTV_BINDER
84 if ((policy == IPCWorkThread::ACTV_PASSIVE || policy == IPCWorkThread::ACTV_ACTIVE) &&
85 (proto != IRemoteObject::IF_PROT_BINDER || !BinderInvoker::IsActvBinderService())) {
86 return false;
87 }
88 #endif
89 int threadIndex = 0;
90 std::string threadName = MakeThreadName(proto, threadIndex);
91 ZLOGD(LOG_LABEL, "name:%{public}s", threadName.c_str());
92
93 if (threads_.find(threadName) == threads_.end()) {
94 auto ipcThread = new (std::nothrow) IPCWorkThread(threadName);
95 if (ipcThread == nullptr) {
96 ZLOGE(LOG_LABEL, "create IPCWorkThread object failed");
97 return false;
98 }
99 sptr<IPCWorkThread> newThread = sptr<IPCWorkThread>(ipcThread);
100 threads_[threadName] = newThread;
101 if (proto == IRemoteObject::IF_PROT_DEFAULT) {
102 idleThreadNum_--;
103 ZLOGD(LOG_LABEL, "now idleThreadNum:%{public}d", idleThreadNum_);
104 }
105 if (proto == IRemoteObject::IF_PROT_DATABUS) {
106 idleSocketThreadNum_--;
107 ZLOGD(LOG_LABEL, "now idleSocketThreadNum:%{public}d", idleSocketThreadNum_);
108 }
109 newThread->Start(policy, proto, threadIndex);
110 return true;
111 }
112 return false;
113 }
114
MakeThreadName(int proto,int & threadIndex)115 std::string IPCWorkThreadPool::MakeThreadName(int proto, int &threadIndex)
116 {
117 int sequence = threadSequence_.fetch_add(1, std::memory_order_relaxed);
118 threadIndex = sequence;
119 return IPCWorkThread::MakeBasicThreadName(proto, sequence);
120 }
121
RemoveThread(const std::string & threadName)122 bool IPCWorkThreadPool::RemoveThread(const std::string &threadName)
123 {
124 std::lock_guard<std::mutex> lock(mutex_);
125 auto it = threads_.find(threadName);
126 if (it != threads_.end()) {
127 sptr<IPCWorkThread> workThread = it->second;
128 if (workThread == nullptr) {
129 return false;
130 }
131 if (workThread->proto_ == IRemoteObject::IF_PROT_DEFAULT) {
132 idleThreadNum_++;
133 } else if (workThread->proto_ == IRemoteObject::IF_PROT_DATABUS) {
134 idleSocketThreadNum_++;
135 }
136 threads_.erase(it);
137 ZLOGD(LOG_LABEL, "now idleThreadNum:%{public}d", idleSocketThreadNum_);
138 return true;
139 }
140 return false;
141 }
142
GetSocketIdleThreadNum() const143 int IPCWorkThreadPool::GetSocketIdleThreadNum() const
144 {
145 return idleSocketThreadNum_;
146 }
147
GetSocketTotalThreadNum() const148 int IPCWorkThreadPool::GetSocketTotalThreadNum() const
149 {
150 return maxThreadNum_ / PROTO_NUM;
151 }
152
GetMaxThreadNum() const153 int IPCWorkThreadPool::GetMaxThreadNum() const
154 {
155 return maxThreadNum_ / PROTO_NUM;
156 }
157
UpdateMaxThreadNum(int maxThreadNum)158 void IPCWorkThreadPool::UpdateMaxThreadNum(int maxThreadNum)
159 {
160 /*
161 * not support delete thread, because thread is in using
162 */
163 int totalNum = maxThreadNum + maxThreadNum;
164 std::lock_guard<std::mutex> lock(mutex_);
165 if (totalNum <= maxThreadNum_) {
166 return;
167 }
168 int diff = totalNum - maxThreadNum_;
169 maxThreadNum_ = totalNum;
170 idleThreadNum_ += diff / PROTO_NUM;
171 idleSocketThreadNum_ += diff / PROTO_NUM;
172 }
173 #ifdef CONFIG_IPC_SINGLE
174 } // namespace IPC_SINGLE
175 #endif
176 } // namesapce OHOS
177
178