Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 : #include "adx_server_manager.h"
11 : #include "log/adx_log.h"
12 : #include "memory_utils.h"
13 : #include "device/adx_hdc_device.h"
14 : #include "hdc_api.h"
15 : #include "adcore_api.h"
16 : namespace Adx {
17 : namespace {
18 : constexpr uint32_t RECONNECT_TIMES = 3U;
19 : }
20 :
21 24 : AdxServerManager::AdxServerManager() noexcept
22 24 : : waitOver_(true),
23 24 : pid_(0),
24 24 : loadMode_(0),
25 24 : deviceId_(-1),
26 24 : type_(OptType::NR_COMM),
27 24 : info_(""),
28 24 : epoll_(nullptr),
29 24 : handleQue_(DEFAULT_EPOLL_HANDLE_QUEUE_SIZE),
30 24 : linkNum_(0),
31 72 : serverInittedFlag_(false)
32 : {
33 24 : servers_.clear();
34 24 : }
35 :
36 2 : AdxServerManager::AdxServerManager(int32_t loadMode, int32_t deviceId) noexcept
37 2 : : waitOver_(true),
38 2 : pid_(0),
39 2 : loadMode_(loadMode),
40 2 : deviceId_(deviceId),
41 2 : type_(OptType::NR_COMM),
42 2 : info_(""),
43 2 : epoll_(nullptr),
44 2 : handleQue_(DEFAULT_EPOLL_HANDLE_QUEUE_SIZE),
45 2 : linkNum_(0),
46 6 : serverInittedFlag_(false)
47 : {
48 2 : servers_.clear();
49 2 : }
50 :
51 26 : AdxServerManager::~AdxServerManager()
52 : {
53 26 : (void)Exit();
54 26 : }
55 :
56 17 : bool AdxServerManager::RegisterEpoll(std::unique_ptr<AdxEpoll> &epoll)
57 : {
58 17 : if (epoll == nullptr) {
59 1 : IDE_LOGE("register epoll input error");
60 1 : return false;
61 : }
62 :
63 16 : if (epoll_ == nullptr) {
64 16 : epoll_ = std::move(epoll);
65 16 : return true;
66 : }
67 :
68 0 : return false;
69 : }
70 :
71 21 : bool AdxServerManager::RegisterCommOpt(std::unique_ptr<AdxCommOpt> &opt,
72 : const std::string &info)
73 : {
74 21 : if (opt == nullptr) {
75 5 : IDE_LOGE("register commopt input error");
76 5 : return false;
77 : }
78 :
79 16 : info_ = info;
80 16 : type_ = opt->GetOptType();
81 16 : return AdxCommOptManager::Instance().CommOptsRegister(opt);
82 : }
83 :
84 22 : bool AdxServerManager::ServerInit(const std::map<std::string, std::string> &info)
85 : {
86 : EpollEvent event;
87 22 : if (epoll_ == nullptr || type_ == OptType::NR_COMM || info.empty()) {
88 7 : IDE_LOGE("server init failed for epoll not register");
89 7 : return false;
90 : }
91 :
92 15 : CommHandle handle = AdxCommOptManager::Instance().OpenServer(type_, info);
93 15 : if (handle.session == ADX_OPT_INVALID_HANDLE) {
94 0 : return false;
95 : }
96 :
97 15 : event.events = ADX_EPOLL_CONN_IN;
98 15 : event.data = handle.session;
99 15 : if (epoll_->EpollCreate(DEFAULT_EPOLL_SIZE) == IDE_DAEMON_ERROR) {
100 0 : IDE_LOGE("create epoll failed");
101 0 : (void)AdxCommOptManager::Instance().CloseServer(handle);
102 0 : return false;
103 : }
104 :
105 15 : if (epoll_->EpollAdd(handle.session, event) != IDE_DAEMON_OK) {
106 1 : IDE_LOGE("epoll add listen event failed");
107 1 : (void)AdxCommOptManager::Instance().CloseServer(handle);
108 1 : return false;
109 : }
110 :
111 14 : auto it = info.find(OPT_DEVICE_KEY);
112 14 : if (it != info.end()) {
113 14 : servers_[it->second] = handle.session;
114 : }
115 14 : IDE_LOGI("create server info");
116 14 : return true;
117 : }
118 :
119 21 : bool AdxServerManager::ServerUnInit(OptHandle epHandle)
120 : {
121 : EpollEvent event;
122 21 : if (epoll_ == nullptr || epHandle == ADX_OPT_INVALID_HANDLE) {
123 2 : IDE_LOGE("server uninit failed for epoll not register");
124 2 : return false;
125 : }
126 19 : event.events = ADX_EPOLL_CONN_IN;
127 19 : event.data = epHandle;
128 19 : if (epoll_->EpollDel(epHandle, event) == IDE_DAEMON_ERROR) {
129 2 : IDE_LOGE("epoll del listen event failed");
130 2 : return false;
131 : }
132 :
133 17 : CommHandle handle = {type_, epHandle, NR_COMPONENTS, -1, nullptr};
134 17 : if (AdxCommOptManager::Instance().CloseServer(handle) != IDE_DAEMON_OK) {
135 1 : IDE_LOGE("close server failed");
136 1 : return false;
137 : }
138 :
139 16 : return true;
140 : }
141 :
142 15 : bool AdxServerManager::ComponentAdd(std::unique_ptr<AdxComponent> &comp)
143 : {
144 15 : if (comp == nullptr) {
145 2 : IDE_LOGE("add component input error");
146 2 : return false;
147 : }
148 :
149 13 : auto it = compMap_.find(comp->GetType());
150 13 : if (it != compMap_.end()) {
151 1 : return false;
152 : }
153 12 : IDE_LOGI("server manager add component (%d)", static_cast<int32_t>(comp->GetType()));
154 12 : compMap_[comp->GetType()] = std::move(comp);
155 12 : return true;
156 : }
157 :
158 3 : bool AdxServerManager::ComponentErase(ComponentType type)
159 : {
160 3 : auto it = compMap_.find(type);
161 3 : if (it == compMap_.end()) {
162 1 : return false;
163 : }
164 2 : IDE_LOGI("server manager erase component (%d)", type);
165 2 : (void)compMap_.erase(type);
166 2 : return (compMap_.count(type) == 0);
167 : }
168 :
169 10 : bool AdxServerManager::ComponentInit() const
170 : {
171 10 : if (epoll_ == nullptr) {
172 1 : return false;
173 : }
174 :
175 9 : auto it = compMap_.begin();
176 18 : while (it != compMap_.end()) {
177 9 : (void)it->second->Init();
178 9 : it++;
179 : }
180 9 : IDE_LOGI("server manager components init successfully");
181 9 : return true;
182 : }
183 :
184 9 : void AdxServerManager::HandleConnectEvent(CommHandle handle)
185 : {
186 9 : CommHandle conHandle = AdxCommOptManager::Instance().Accept(handle);
187 9 : if (conHandle.session == ADX_OPT_INVALID_HANDLE) {
188 0 : return;
189 : }
190 9 : handleQue_.Push(conHandle.session);
191 9 : IDE_LOGD("handle queue push: %lx", conHandle.session);
192 : mmUserBlock_t funcBlock;
193 9 : funcBlock.procFunc = AdxServerManager::ThreadProcess;
194 9 : funcBlock.pulArg = this;
195 9 : mmThread tid = 0;
196 9 : int32_t ret = Thread::CreateDetachTask(tid, funcBlock);
197 9 : if (ret != EN_OK) {
198 1 : EpollHandle epHandle = ADX_INVALID_HANDLE;
199 1 : if (handleQue_.Pop(epHandle) == true) {
200 1 : IDE_LOGD("handle queue pop: %lx", epHandle);
201 1 : CommHandle curHandle {type_, epHandle, NR_COMPONENTS, -1, nullptr};
202 1 : (void)AdxCommOptManager::Instance().Close(curHandle);
203 : }
204 1 : char errBuf[MAX_ERRSTR_LEN + 1] = {0};
205 1 : IDE_LOGE("create component process thread failed, strerror is %s",
206 : mmGetErrorFormatMessage(mmGetErrorCode(), errBuf, MAX_ERRSTR_LEN));
207 : }
208 : }
209 10 : bool AdxServerManager::ComponentWaitEvent()
210 : {
211 10 : IDE_CTRL_VALUE_FAILED(epoll_ != nullptr, return false, "epoll_ check failed, nullptr");
212 9 : const int32_t epollSize = epoll_->EpollGetSize();
213 9 : std::vector<EpollEvent> events(epollSize);
214 1161 : for (int32_t i = 0; i < epollSize; i++) {
215 1152 : events[i].data = 0;
216 1152 : events[i].events = 0;
217 : }
218 9 : IDE_RUN_LOGI("Run Server(%d) Process", static_cast<int32_t>(type_));
219 9 : waitOver_ = false;
220 27 : while (!IsQuit()) {
221 9 : TimerProcess();
222 9 : int32_t handles = epoll_->EpollWait(events, epollSize, DEFAULT_EPOLL_TIMEOUT);
223 36 : for (int32_t i = 0; i < handles && i < epollSize; i++) {
224 27 : IDE_LOGI("sock EpollWait accept event %d", handles);
225 27 : if ((events[i].events & ADX_EPOLL_CONN_IN) != 0) {
226 9 : IDE_LOGI("sock connect EpollWait event %d", handles);
227 9 : CommHandle handle = {type_, events[i].data, NR_COMPONENTS, -1, nullptr};
228 9 : HandleConnectEvent(handle);
229 18 : } else if ((events[i].events & ADX_EPOLL_DATA_IN) != 0) {
230 0 : IDE_LOGI("data in");
231 18 : } else if ((events[i].events & ADX_EPOLL_HANG_UP) != 0) {
232 0 : IDE_LOGW("hang up state");
233 : } else {
234 18 : IDE_LOGW("other epoll state");
235 18 : epoll_->EpollErrorHandle();
236 : }
237 : }
238 9 : if (handles < 0) {
239 0 : epoll_->EpollErrorHandle();
240 : }
241 : }
242 :
243 9 : waitOver_ = true;
244 9 : return true;
245 9 : }
246 :
247 9 : void AdxServerManager::Run()
248 : {
249 9 : pid_ = mmGetPid();
250 9 : if (ComponentWaitEvent()) {
251 9 : IDE_RUN_LOGI("server manager stop");
252 : }
253 9 : }
254 :
255 8 : IdeThreadArg AdxServerManager::ThreadProcess(IdeThreadArg arg)
256 : {
257 8 : if (arg == nullptr) {
258 0 : return nullptr;
259 : }
260 8 : auto runnable = reinterpret_cast<AdxServerManager *>(arg);
261 8 : (void)mmSetCurrentThreadName("adx_component_process");
262 8 : runnable->ComponentProcess();
263 8 : return nullptr;
264 : }
265 :
266 8 : void AdxServerManager::ComponentProcess()
267 : {
268 8 : EpollHandle epHandle = ADX_INVALID_HANDLE;
269 8 : IDE_LOGI("process new connect");
270 8 : if (handleQue_.Pop(epHandle) == false) {
271 0 : return;
272 : }
273 8 : IDE_LOGD("handle queue pop: %lx", epHandle);
274 :
275 8 : if (epHandle == ADX_INVALID_HANDLE) {
276 0 : IDE_LOGE("server run process handle invalid");
277 0 : return;
278 : }
279 :
280 8 : AdxCommHandle handle = static_cast<AdxCommHandle>(IdeXmalloc(sizeof(CommHandle)));
281 8 : IDE_CTRL_VALUE_FAILED(handle != nullptr, return, "malloc handle failed.");
282 8 : handle->type = type_;
283 8 : handle->session = epHandle;
284 8 : handle->comp = ComponentType::NR_COMPONENTS;
285 8 : handle->timeout = 0;
286 8 : handle->client = nullptr;
287 8 : ComponentType comp = ComponentType::NR_COMPONENTS;
288 8 : bool ret = SubComponentProcess(*handle, comp);
289 8 : if (((comp != ComponentType::COMPONENT_LOG_BACKHAUL) && (comp != ComponentType::COMPONENT_TRACE) &&
290 8 : (comp != ComponentType::COMPONENT_SYS_REPORT) && (comp != ComponentType::COMPONENT_FILE_REPORT) &&
291 8 : (comp != ComponentType::COMPONENT_CPU_DETECT)) || !ret) {
292 8 : (void)AdxCommOptManager::Instance().Close(*handle);
293 8 : handle->session = ADX_OPT_INVALID_HANDLE;
294 8 : IDE_XFREE_AND_SET_NULL(handle);
295 : }
296 : }
297 :
298 8 : bool AdxServerManager::SubComponentProcess(CommHandle &handle, ComponentType &comp)
299 : {
300 8 : MsgProto *req = nullptr;
301 8 : int32_t length = 0;
302 :
303 8 : int32_t ret = AdxCommOptManager::Instance().Read(handle, reinterpret_cast<IdeRecvBuffT>(&req), length,
304 : COMM_OPT_NOBLOCK);
305 8 : if (ret == IDE_DAEMON_ERROR || req == nullptr || length <= 0) {
306 1 : IDE_LOGE("receive request failed ret %d, length(%d bytes)", ret, length);
307 1 : return false;
308 : }
309 :
310 7 : SharedPtr<MsgProto> msgPtr(req, IdeXfree);
311 7 : req = nullptr;
312 7 : if (msgPtr->sliceLen + sizeof(MsgProto) != (uint32_t)length) {
313 1 : IDE_LOGE("receive request package(%u bytes) length(%d bytes) exception", msgPtr->sliceLen, length);
314 1 : return false;
315 : }
316 :
317 6 : HDC_SESSION session = reinterpret_cast<HDC_SESSION>(handle.session);
318 6 : int32_t devId = -1;
319 6 : ret = IdeGetDevIdBySession(session, &devId);
320 6 : if (ret != IDE_DAEMON_OK || devId < 0 || devId > UINT16_MAX) {
321 1 : IDE_LOGE("get dev id by session fail, ret=%d", ret);
322 1 : return false;
323 : }
324 5 : msgPtr->devId = static_cast<uint16_t>(devId);
325 :
326 5 : IDE_LOGI("commopt type(%d), request type(%u), device id(%d)", static_cast<int32_t>(type_), msgPtr->reqType, devId);
327 5 : return DispatchComponent(handle, msgPtr, session, comp);
328 7 : }
329 :
330 5 : bool AdxServerManager::DispatchComponent(CommHandle &handle, SharedPtr<MsgProto> &msgPtr, HDC_SESSION session,
331 : ComponentType &comp)
332 : {
333 5 : comp = GetComponentTypeByReqType(static_cast<CmdClassT>(msgPtr->reqType));
334 5 : auto it = compMap_.find(comp);
335 5 : if (it == compMap_.end()) {
336 1 : IDE_LOGE("Unable to find the corresponding component type(%d)", static_cast<int32_t>(comp));
337 1 : return false;
338 : }
339 :
340 4 : handle.comp = comp;
341 4 : if (handle.comp == ComponentType::COMPONENT_GETD_FILE || handle.comp == COMPONENT_LOG_LEVEL) {
342 4 : std::lock_guard<std::mutex> lck(linkMtx_);
343 4 : if (IsLinkOverload(session)) {
344 3 : return false;
345 : }
346 1 : linkNum_++;
347 4 : }
348 1 : std::string compInfo = it->second->GetInfo();
349 1 : IDE_LOGI("begin to process [%s] component", compInfo.c_str());
350 1 : if (it->second->Process(handle, msgPtr) != IDE_DAEMON_OK) {
351 0 : IDE_LOGE("end of processing [%s] component failed, req->type: %u", compInfo.c_str(), msgPtr->reqType);
352 : } else {
353 1 : IDE_LOGI("end of processing [%s] component successfully", compInfo.c_str());
354 : }
355 1 : if (handle.comp == ComponentType::COMPONENT_GETD_FILE || handle.comp == COMPONENT_LOG_LEVEL) {
356 1 : std::lock_guard<std::mutex> lck(linkMtx_);
357 1 : linkNum_--;
358 1 : }
359 1 : return true;
360 1 : }
361 :
362 5 : ComponentType AdxServerManager::GetComponentTypeByReqType(CmdClassT cmdType) const
363 : {
364 5 : ComponentType cmptType = ComponentType::NR_COMPONENTS;
365 5 : for (uint32_t i = 0; i < ARRAY_LEN(g_componentsInfo, AdxComponentMap); i++) {
366 5 : if (cmdType == g_componentsInfo[i].cmdType) {
367 5 : cmptType = g_componentsInfo[i].cmptType;
368 5 : break;
369 : }
370 : }
371 5 : return cmptType;
372 : }
373 :
374 14 : void AdxServerManager::TimerProcess()
375 : {
376 14 : std::vector<std::string> devLogIds;
377 14 : SharedPtr<AdxDevice> device = AdxCommOptManager::Instance().GetDevice(type_);
378 14 : if (device == nullptr) {
379 0 : return;
380 : }
381 :
382 : // initialize the devices on the first time(AdxCommOptManager is singleton object)
383 : // create HDC server on th enable device
384 14 : device->GetAllEnableDevices(loadMode_, deviceId_, devLogIds);
385 14 : std::map<std::string, std::string> info;
386 14 : info[OPT_SERVICE_KEY] = info_;
387 28 : for (const auto& deviceId : devLogIds) {
388 14 : auto server = servers_.find(deviceId);
389 : // filter the device that created HDC server(or not the specified device)
390 14 : if (server != servers_.end() || !(deviceId_ == -1 || std::to_string(deviceId_) == deviceId)) {
391 12 : continue;
392 : }
393 :
394 5 : IDE_LOGI("device up %s", deviceId.c_str());
395 5 : info[OPT_DEVICE_KEY] = deviceId;
396 5 : if (ServerInit(info)) {
397 1 : faultyDevices_.erase(deviceId);
398 1 : continue;
399 : }
400 :
401 : // record retry times of connection for the faulty device
402 4 : auto faultDevice = faultyDevices_.find(deviceId);
403 4 : if (faultDevice == faultyDevices_.end()) {
404 2 : faultyDevices_[deviceId] = 1;
405 2 : continue;
406 : }
407 2 : ++(faultDevice->second);
408 2 : if (faultDevice->second >= RECONNECT_TIMES) {
409 1 : faultyDevices_.erase(faultDevice);
410 : // set the device to disable if connection is timeout
411 1 : device->DisableNotify(deviceId);
412 : }
413 : }
414 :
415 14 : device->GetDisableDevices(devLogIds);
416 15 : for (const auto& deviceId : devLogIds) {
417 1 : auto server = servers_.find(deviceId);
418 1 : if (server == servers_.end()) {
419 1 : continue;
420 : }
421 0 : IDE_LOGI("device suspend %s", deviceId.c_str());
422 0 : if (ServerUnInit(server->second)) {
423 0 : servers_.erase(server);
424 : }
425 : }
426 14 : serverInittedFlag_ = true;
427 14 : AdxCommOptManager::Instance().Timer(type_);
428 14 : }
429 :
430 77 : int32_t AdxServerManager::Exit()
431 : {
432 77 : serverInittedFlag_ = false;
433 77 : if (pid_ == mmGetPid()) { // not fork
434 10 : Terminate();
435 : // wait epoll wait timeout
436 10 : while (!waitOver_) {
437 0 : mmSleep(DEFAULT_EPOLL_TIMEOUT);
438 : }
439 : }
440 :
441 : // terminate the running components before close servers(close client sessions)
442 87 : for (auto& component : compMap_) {
443 10 : (void)component.second->Terminate();
444 : }
445 :
446 : // finalize the servers(delete epoll and close session)
447 91 : for (auto& server : servers_) {
448 14 : if (!ServerUnInit(server.second)) {
449 0 : return IDE_DAEMON_ERROR;
450 : }
451 : }
452 77 : servers_.clear();
453 :
454 : // finalize the components
455 87 : for (auto& component : compMap_) {
456 10 : (void)component.second->UnInit();
457 : }
458 : // make sure no longer use it in ComponentProcess/SubComponentProcess
459 77 : compMap_.clear();
460 :
461 77 : if (epoll_ != nullptr) {
462 16 : if (epoll_->EpollDestroy() != IDE_DAEMON_OK) {
463 1 : return IDE_DAEMON_ERROR;
464 : }
465 15 : epoll_ = nullptr;
466 : }
467 76 : return IDE_DAEMON_OK;
468 : }
469 :
470 9 : void AdxServerManager::SetMode(int32_t loadMode)
471 : {
472 9 : loadMode_ = loadMode;
473 9 : }
474 :
475 9 : void AdxServerManager::SetDeviceId(int32_t deviceId)
476 : {
477 9 : deviceId_ = deviceId;
478 9 : }
479 :
480 2 : bool AdxServerManager::IsLinkOverload(HDC_SESSION session) const
481 : {
482 2 : const int32_t maxLinkNum = 16; // limit max links num is 16 at the same time
483 2 : if (linkNum_ >= maxLinkNum) {
484 1 : int32_t pid = -1;
485 1 : (void)IdeGetPidBySession(session, &pid);
486 1 : IDE_LOGE("server manager overload, pid: %d.", pid);
487 1 : return true;
488 : }
489 1 : return false;
490 : }
491 :
492 49 : bool AdxServerManager::WaitServerInitted() const
493 : {
494 : // 最大等待60s,等待serverInittedFlag_为true,每等待一轮等待时间增加1毫秒
495 49 : const int32_t maxRetryTimes = 346; // 60s (1 + 2 + ... + 346)ms
496 49 : int32_t retryTime = 1;
497 16609 : while (retryTime < maxRetryTimes) {
498 16561 : if (serverInittedFlag_) {
499 1 : IDE_LOGI("The server is initialized after waiting %d times.", retryTime);
500 1 : return true;
501 : }
502 16560 : mmSleep(retryTime);
503 16560 : retryTime++;
504 : }
505 :
506 48 : if (retryTime >= maxRetryTimes) {
507 48 : IDE_LOGW("The server is not initialized after waiting %d times.", retryTime);
508 : }
509 :
510 48 : return false;
511 : }
512 : }
|