1 //===-- Progress.h ----------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_CORE_PROGRESS_H 10 #define LLDB_CORE_PROGRESS_H 11 12 #include "lldb/Utility/ConstString.h" 13 #include "lldb/lldb-types.h" 14 #include <atomic> 15 #include <mutex> 16 #include <optional> 17 18 namespace lldb_private { 19 20 /// A Progress indicator helper class. 21 /// 22 /// Any potentially long running sections of code in LLDB should report 23 /// progress so that clients are aware of delays that might appear during 24 /// debugging. Delays commonly include indexing debug information, parsing 25 /// symbol tables for object files, downloading symbols from remote 26 /// repositories, and many more things. 27 /// 28 /// The Progress class helps make sure that progress is correctly reported 29 /// and will always send an initial progress update, updates when 30 /// Progress::Increment() is called, and also will make sure that a progress 31 /// completed update is reported even if the user doesn't explicitly cause one 32 /// to be sent. 33 /// 34 /// The progress is reported via a callback whose type is ProgressCallback: 35 /// 36 /// typedef void (*ProgressCallback)(uint64_t progress_id, 37 /// const char *message, 38 /// uint64_t completed, 39 /// uint64_t total, 40 /// void *baton); 41 /// 42 /// This callback will always initially be called with "completed" set to zero 43 /// and "total" set to the total amount specified in the contructor. This is 44 /// considered the progress start event. As Progress::Increment() is called, 45 /// the callback will be called as long as the Progress::m_completed has not 46 /// yet exceeded the Progress::m_total. When the callback is called with 47 /// Progress::m_completed == Progress::m_total, that is considered a progress 48 /// completed event. If Progress::m_completed is non-zero and less than 49 /// Progress::m_total, then this is considered a progress update event. 50 /// 51 /// This callback will be called in the destructor if Progress::m_completed is 52 /// not equal to Progress::m_total with the "completed" set to 53 /// Progress::m_total. This ensures we always send a progress completed update 54 /// even if the user does not. 55 56 class Progress { 57 public: 58 /// Construct a progress object that will report information. 59 /// 60 /// The constructor will create a unique progress reporting object and 61 /// immediately send out a progress update by calling the installed callback 62 /// with completed set to zero out of the specified total. 63 /// 64 /// @param [in] title The title of this progress activity. 65 /// 66 /// @param [in] total The total units of work to be done if specified, if 67 /// set to std::nullopt then an indeterminate progress indicator should be 68 /// displayed. 69 /// 70 /// @param [in] debugger An optional debugger pointer to specify that this 71 /// progress is to be reported only to specific debuggers. 72 Progress(std::string title, std::string details = {}, 73 std::optional<uint64_t> total = std::nullopt, 74 lldb_private::Debugger *debugger = nullptr); 75 76 /// Destroy the progress object. 77 /// 78 /// If the progress has not yet sent a completion update, the destructor 79 /// will send out a notification where the completed == m_total. This ensures 80 /// that we always send out a progress complete notification. 81 ~Progress(); 82 83 /// Increment the progress and send a notification to the intalled callback. 84 /// 85 /// If incrementing ends up exceeding m_total, m_completed will be updated 86 /// to match m_total and no subsequent progress notifications will be sent. 87 /// If no total was specified in the constructor, this function will not do 88 /// anything nor send any progress updates. 89 /// 90 /// @param [in] amount The amount to increment m_completed by. 91 /// 92 /// @param [in] an optional message associated with this update. 93 void Increment(uint64_t amount = 1, 94 std::optional<std::string> updated_detail = {}); 95 96 private: 97 void ReportProgress(); 98 static std::atomic<uint64_t> g_id; 99 /// The title of the progress activity. 100 std::string m_title; 101 std::string m_details; 102 std::mutex m_mutex; 103 /// A unique integer identifier for progress reporting. 104 const uint64_t m_id; 105 /// How much work ([0...m_total]) that has been completed. 106 uint64_t m_completed; 107 /// Total amount of work, use a std::nullopt in the constructor for non 108 /// deterministic progress. 109 uint64_t m_total; 110 /// The optional debugger ID to report progress to. If this has no value then 111 /// all debuggers will receive this event. 112 std::optional<lldb::user_id_t> m_debugger_id; 113 /// Set to true when progress has been reported where m_completed == m_total 114 /// to ensure that we don't send progress updates after progress has 115 /// completed. 116 bool m_complete = false; 117 }; 118 119 } // namespace lldb_private 120 121 #endif // LLDB_CORE_PROGRESS_H 122