• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "log.h"
17 #include "uv_status.h"
18 #include <thread>
19 #include <mutex>
20 
21 using namespace std;
22 
23 namespace Hdc {
TimeSub(const uint64_t end,const uint64_t start)24     static int64_t TimeSub(const uint64_t end, const uint64_t start)
25     {
26         return end - start;
27     }
TimeNow(void)28     static uint64_t TimeNow(void)
29     {
30         return uv_hrtime() / NS_PER_MS;
31     }
32 
33     static std::map<uv_loop_t *, LoopStatus *> g_loopStatusMap;
34     static std::mutex g_mapLoopStatusMutex;
DispAllLoopStatus(const string & info)35     void DispAllLoopStatus(const string &info)
36     {
37         std::unique_lock<std::mutex> lock(g_mapLoopStatusMutex);
38         for (auto [loop, stat] : g_loopStatusMap) {
39             stat->Display(info);
40         }
41     }
ReportTimerProc(uv_timer_t * req)42     void LoopStatus::ReportTimerProc(uv_timer_t *req)
43     {
44         LoopStatus *ls = reinterpret_cast<LoopStatus *>(req->data);
45         CALLSTAT_GUARD(*ls, req->loop, "LoopStatus::ReportTimerProc");
46     }
StartReportTimer(void)47     void LoopStatus::StartReportTimer(void)
48     {
49         uv_timer_init(mLoop, &mReportTimer);
50         mReportTimer.data = this;
51         uv_timer_start(&mReportTimer, ReportTimerProc, 0, 1 * MS_PER_SEC);
52     }
LoopStatus(uv_loop_t * loop,const string & loopName)53     LoopStatus::LoopStatus(uv_loop_t *loop, const string &loopName) : mLoop(loop), mLoopName(loopName)
54     {
55         mBusyNow = false;
56         mCallBackTime = 0;
57 
58         std::unique_lock<std::mutex> lock(g_mapLoopStatusMutex);
59         if (g_loopStatusMap.count(mLoop)) {
60             return;
61         }
62         g_loopStatusMap[mLoop] = this;
63     }
~LoopStatus()64     LoopStatus::~LoopStatus()
65     {
66         std::unique_lock<std::mutex> lock(g_mapLoopStatusMutex);
67         if (!g_loopStatusMap.count(mLoop)) {
68             return;
69         }
70         g_loopStatusMap.erase(mLoop);
71     }
HandleStart(const uv_loop_t * loop,const string & handle)72     void LoopStatus::HandleStart(const uv_loop_t *loop, const string &handle)
73     {
74         if (loop != mLoop) {
75             WRITE_LOG(LOG_FATAL, "not match loop [%s] for run [%s]", mLoopName.c_str(), handle.c_str());
76             return;
77         }
78         if (Busy()) {
79             WRITE_LOG(LOG_FATAL, "the loop is busy for [%s] cannt run [%s]", mHandleName.c_str(), handle.c_str());
80             return;
81         }
82         mBusyNow = true;
83         mHandleName = handle;
84         if (loop == nullptr) {
85             WRITE_LOG(LOG_FATAL, "the loop is null for [%s] cannt run [%s]", mHandleName.c_str(), handle.c_str());
86         }
87         mCallBackTime = uv_now(loop);
88     }
HandleEnd(const uv_loop_t * loop)89     void LoopStatus::HandleEnd(const uv_loop_t *loop)
90     {
91         if (loop != mLoop) {
92             WRITE_LOG(LOG_FATAL, "not match loop [%s] for end [%s]", mLoopName.c_str(), mHandleName.c_str());
93             return;
94         }
95         if (!Busy()) {
96             WRITE_LOG(LOG_FATAL, "the loop [%s] is idle now", mLoopName.c_str());
97             return;
98         }
99         mBusyNow = false;
100     }
Busy(void) const101     bool LoopStatus::Busy(void) const
102     {
103         return mBusyNow;
104     }
Display(const string & info,bool all) const105     void LoopStatus::Display(const string &info, bool all) const
106     {
107         if (Busy()) {
108             WRITE_LOG(LOG_FATAL, "%s loop[%s] is busy for [%s] start[%llu] duration[%llu]",
109                       info.c_str(), mLoopName.c_str(), mHandleName.c_str(),
110                       mCallBackTime, TimeSub(TimeNow(), mCallBackTime));
111         } else if (all) {
112             WRITE_LOG(LOG_INFO, "%s loop[%s] is idle", info.c_str(), mLoopName.c_str());
113         }
114     }
HungCheck(int64_t timeout) const115     void LoopStatus::HungCheck(int64_t timeout) const
116     {
117         if (TimeSub(TimeNow(), mCallBackTime) > timeout) {
118             Display("hung :", false);
119         }
120     }
LoopMonitorWorker(void)121     static void LoopMonitorWorker(void)
122     {
123         WRITE_LOG(LOG_FATAL, "LoopMonitorWorker every %d ms check hung %d us",
124                   LOOP_MONITOR_PERIOD, LOOP_HUNG_TIMEOUT);
125         bool exit = false;
126         while (!exit) {
127             // every 1 second check one time
128             uv_sleep(LOOP_MONITOR_PERIOD);
129             std::unique_lock<std::mutex> lock(g_mapLoopStatusMutex);
130             if (g_loopStatusMap.empty()) {
131                 WRITE_LOG(LOG_FATAL, "LoopMonitorWorker the loop status map is empty, stop monitor");
132                 exit = true;
133             }
134             for (auto [loop, stat] : g_loopStatusMap) {
135                 stat->HungCheck(LOOP_HUNG_TIMEOUT);
136             }
137         }
138     }
StartLoopMonitor(void)139     void StartLoopMonitor(void)
140     {
141         static std::once_flag flag;
142         std::call_once(flag, [&]() {
143             std::thread t(LoopMonitorWorker);
144             t.detach();
145         });
146     }
147 } /* namespace Hdc  */
148