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