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
17namespace 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
55class Progress {
56public:
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
91private:
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