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 | /// Used to indicate a non-deterministic progress report |
97 | static constexpr uint64_t kNonDeterministicTotal = UINT64_MAX; |
98 | |
99 | private: |
100 | void ReportProgress(); |
101 | static std::atomic<uint64_t> g_id; |
102 | /// The title of the progress activity. |
103 | std::string m_title; |
104 | std::string m_details; |
105 | std::mutex m_mutex; |
106 | /// A unique integer identifier for progress reporting. |
107 | const uint64_t m_id; |
108 | /// How much work ([0...m_total]) that has been completed. |
109 | uint64_t m_completed; |
110 | /// Total amount of work, use a std::nullopt in the constructor for non |
111 | /// deterministic progress. |
112 | uint64_t m_total; |
113 | /// The optional debugger ID to report progress to. If this has no value then |
114 | /// all debuggers will receive this event. |
115 | std::optional<lldb::user_id_t> m_debugger_id; |
116 | /// Set to true when progress has been reported where m_completed == m_total |
117 | /// to ensure that we don't send progress updates after progress has |
118 | /// completed. |
119 | bool m_complete = false; |
120 | }; |
121 | |
122 | } // namespace lldb_private |
123 | |
124 | #endif // LLDB_CORE_PROGRESS_H |
125 | |