================ @@ -75,45 +81,86 @@ void Progress::ReportProgress() { } } -ProgressManager::ProgressManager() : m_progress_category_map() {} +ProgressManager::ProgressManager() + : m_alarm(std::chrono::milliseconds(100)), m_entries() {} ProgressManager::~ProgressManager() {} +void ProgressManager::Initialize() { + assert(!InstanceImpl() && "Already initialized."); + InstanceImpl().emplace(); +} + +void ProgressManager::Terminate() { + assert(InstanceImpl() && "Already terminated."); + InstanceImpl().reset(); +} + +bool ProgressManager::Enabled() { return InstanceImpl().operator bool(); } + ProgressManager &ProgressManager::Instance() { - static std::once_flag g_once_flag; - static ProgressManager *g_progress_manager = nullptr; - std::call_once(g_once_flag, []() { - // NOTE: known leak to avoid global destructor chain issues. - g_progress_manager = new ProgressManager(); - }); - return *g_progress_manager; + assert(InstanceImpl() && "ProgressManager must be initialized"); + return *InstanceImpl(); +} + +std::optional<ProgressManager> &ProgressManager::InstanceImpl() { + static std::optional<ProgressManager> g_progress_manager; + return g_progress_manager; } void ProgressManager::Increment(const Progress::ProgressData &progress_data) { - std::lock_guard<std::mutex> lock(m_progress_map_mutex); - // If the current category exists in the map then it is not an initial report, - // therefore don't broadcast to the category bit. Also, store the current - // progress data in the map so that we have a note of the ID used for the - // initial progress report. - if (!m_progress_category_map.contains(progress_data.title)) { - m_progress_category_map[progress_data.title].second = progress_data; + std::lock_guard<std::mutex> lock(m_entries_mutex); + llvm::StringRef key = progress_data.title; + + // This is a new progress event. + if (!m_entries.contains(key)) { ReportProgress(progress_data, EventType::Begin); + Entry &entry = m_entries[key]; + entry.data = progress_data; + entry.refcount = 1; + return; + } + + // This is an existing progress event. + Entry &entry = m_entries[key]; + + // The progress event was scheduled to be deleted but a new one came in before + // the timer expired. + if (entry.refcount == 0) { + assert(entry.handle != Alarm::INVALID_HANDLE); + + if (!m_alarm.Cancel(entry.handle)) { + // The timer expired before we had a chance to cancel it. We have to treat + // this as an entirely new progress event. + ReportProgress(progress_data, EventType::Begin); + } + entry.refcount = 1; + entry.handle = Alarm::INVALID_HANDLE; + } else { + entry.refcount++; } - m_progress_category_map[progress_data.title].first++; } void ProgressManager::Decrement(const Progress::ProgressData &progress_data) { - std::lock_guard<std::mutex> lock(m_progress_map_mutex); - auto pos = m_progress_category_map.find(progress_data.title); + std::lock_guard<std::mutex> lock(m_entries_mutex); + llvm::StringRef key = progress_data.title; - if (pos == m_progress_category_map.end()) + if (!m_entries.contains(key)) return; - if (pos->second.first <= 1) { - ReportProgress(pos->second.second, EventType::End); - m_progress_category_map.erase(progress_data.title); + Entry &entry = m_entries[key]; + if (entry.refcount <= 1) { + assert(entry.handle == Alarm::INVALID_HANDLE); + // Start a timer. If it expires before we see another progress event, it + // will be reported. + entry.refcount = 0; + // Copy the key to a std::string so we can pass it by value to the lambda. + // The underlying StringRef will not exist by the time the callback is + // called. + std::string key_str = std::string(key); + entry.handle = m_alarm.Create([=]() { Expire(key_str); }); } else { - --pos->second.first; + entry.refcount--; } ---------------- clayborg wrote:
This can similarly always decrement, similar to previous suggestion: ``` Entry &entry = m_entries[key]; if (entry.refcount > 0 && --entry.refcount == 0) { assert(entry.handle == Alarm::INVALID_HANDLE); // Start a timer. If it expires before we see another progress event, it // will be reported. // Copy the key to a std::string so we can pass it by value to the lambda. // The underlying StringRef will not exist by the time the callback is // called. std::string key_str = std::string(key); entry.handle = m_alarm.Create([=]() { Expire(key_str); }); } ``` This stops the manual editing of `entry.refcount = 0;` and the separate decrement in the else https://github.com/llvm/llvm-project/pull/84854 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits