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