[clangd] Fix warnings
[llvm-project.git] / lldb / tools / lldb-dap / ProgressEvent.h
blobdac21977add2d0465adf87535078d64117f02f66
1 //===-- ProgressEvent.cpp ---------------------------------------*- 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 //===----------------------------------------------------------------------===//
9 #include <atomic>
10 #include <mutex>
11 #include <optional>
12 #include <queue>
13 #include <thread>
15 #include "DAPForward.h"
17 #include "llvm/Support/JSON.h"
19 namespace lldb_dap {
21 enum ProgressEventType { progressStart, progressUpdate, progressEnd };
23 class ProgressEvent;
24 using ProgressEventReportCallback = std::function<void(ProgressEvent &)>;
26 class ProgressEvent {
27 public:
28 /// Actual constructor to use that returns an optional, as the event might be
29 /// not apt for the IDE, e.g. an unnamed start event, or a redundant one.
30 ///
31 /// \param[in] progress_id
32 /// ID for this event.
33 ///
34 /// \param[in] message
35 /// Message to display in the UI. Required for start events.
36 ///
37 /// \param[in] completed
38 /// Number of jobs completed.
39 ///
40 /// \param[in] total
41 /// Total number of jobs, or \b UINT64_MAX if not determined.
42 ///
43 /// \param[in] prev_event
44 /// Previous event if this one is an update. If \b nullptr, then a start
45 /// event will be created.
46 static std::optional<ProgressEvent>
47 Create(uint64_t progress_id, std::optional<llvm::StringRef> message,
48 uint64_t completed, uint64_t total,
49 const ProgressEvent *prev_event = nullptr);
51 llvm::json::Value ToJSON() const;
53 /// \return
54 /// \b true if two event messages would result in the same event for the
55 /// IDE, e.g. same rounded percentage.
56 bool EqualsForIDE(const ProgressEvent &other) const;
58 llvm::StringRef GetEventName() const;
60 ProgressEventType GetEventType() const;
62 /// Report this progress event to the provided callback only if enough time
63 /// has passed since the creation of the event and since the previous reported
64 /// update.
65 bool Report(ProgressEventReportCallback callback);
67 bool Reported() const;
69 private:
70 ProgressEvent(uint64_t progress_id, std::optional<llvm::StringRef> message,
71 uint64_t completed, uint64_t total,
72 const ProgressEvent *prev_event);
74 uint64_t m_progress_id;
75 std::string m_message;
76 ProgressEventType m_event_type;
77 std::optional<uint32_t> m_percentage;
78 std::chrono::duration<double> m_creation_time =
79 std::chrono::system_clock::now().time_since_epoch();
80 std::chrono::duration<double> m_minimum_allowed_report_time;
81 bool m_reported = false;
84 /// Class that keeps the start event and its most recent update.
85 /// It controls when the event should start being reported to the IDE.
86 class ProgressEventManager {
87 public:
88 ProgressEventManager(const ProgressEvent &start_event,
89 ProgressEventReportCallback report_callback);
91 /// Report the start event and the most recent update if the event has lasted
92 /// for long enough.
93 ///
94 /// \return
95 /// \b false if the event hasn't finished and hasn't reported anything
96 /// yet.
97 bool ReportIfNeeded();
99 /// Receive a new progress event for the start event and try to report it if
100 /// appropriate.
101 void Update(uint64_t progress_id, uint64_t completed, uint64_t total);
103 /// \return
104 /// \b true if a \a progressEnd event has been notified. There's no
105 /// need to try to report manually an event that has finished.
106 bool Finished() const;
108 const ProgressEvent &GetMostRecentEvent() const;
110 private:
111 ProgressEvent m_start_event;
112 std::optional<ProgressEvent> m_last_update_event;
113 bool m_finished;
114 ProgressEventReportCallback m_report_callback;
117 using ProgressEventManagerSP = std::shared_ptr<ProgressEventManager>;
119 /// Class that filters out progress event messages that shouldn't be reported
120 /// to the IDE, because they are invalid, they carry no new information, or they
121 /// don't last long enough.
123 /// We need to limit the amount of events that are sent to the IDE, as they slow
124 /// the render thread of the UI user, and they end up spamming the DAP
125 /// connection, which also takes some processing time out of the IDE.
126 class ProgressEventReporter {
127 public:
128 /// \param[in] report_callback
129 /// Function to invoke to report the event to the IDE.
130 ProgressEventReporter(ProgressEventReportCallback report_callback);
132 ~ProgressEventReporter();
134 /// Add a new event to the internal queue and report the event if
135 /// appropriate.
136 void Push(uint64_t progress_id, const char *message, uint64_t completed,
137 uint64_t total);
139 private:
140 /// Report to the IDE events that haven't been reported to the IDE and have
141 /// lasted long enough.
142 void ReportStartEvents();
144 ProgressEventReportCallback m_report_callback;
145 std::map<uint64_t, ProgressEventManagerSP> m_event_managers;
146 /// Queue of start events in chronological order
147 std::queue<ProgressEventManagerSP> m_unreported_start_events;
148 /// Thread used to invoke \a ReportStartEvents periodically.
149 std::thread m_thread;
150 std::atomic<bool> m_thread_should_exit;
151 /// Mutex that prevents running \a Push and \a ReportStartEvents
152 /// simultaneously, as both read and modify the same underlying objects.
153 std::mutex m_mutex;
156 } // namespace lldb_dap