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