forked from OSchip/llvm-project
159 lines
5.2 KiB
C++
159 lines
5.2 KiB
C++
//===-- ProgressEvent.cpp ---------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <mutex>
|
|
#include <queue>
|
|
#include <thread>
|
|
|
|
#include "VSCodeForward.h"
|
|
|
|
#include "llvm/Support/JSON.h"
|
|
|
|
namespace lldb_vscode {
|
|
|
|
enum ProgressEventType {
|
|
progressStart,
|
|
progressUpdate,
|
|
progressEnd
|
|
};
|
|
|
|
class ProgressEvent;
|
|
using ProgressEventReportCallback = std::function<void(ProgressEvent &)>;
|
|
|
|
class ProgressEvent {
|
|
public:
|
|
/// Actual constructor to use that returns an optional, as the event might be
|
|
/// not apt for the IDE, e.g. an unnamed start event, or a redundant one.
|
|
///
|
|
/// \param[in] progress_id
|
|
/// ID for this event.
|
|
///
|
|
/// \param[in] message
|
|
/// Message to display in the UI. Required for start events.
|
|
///
|
|
/// \param[in] completed
|
|
/// Number of jobs completed.
|
|
///
|
|
/// \param[in] total
|
|
/// Total number of jobs, or \b UINT64_MAX if not determined.
|
|
///
|
|
/// \param[in] prev_event
|
|
/// Previous event if this one is an update. If \b nullptr, then a start
|
|
/// event will be created.
|
|
static llvm::Optional<ProgressEvent>
|
|
Create(uint64_t progress_id, llvm::Optional<llvm::StringRef> message,
|
|
uint64_t completed, uint64_t total,
|
|
const ProgressEvent *prev_event = nullptr);
|
|
|
|
llvm::json::Value ToJSON() const;
|
|
|
|
/// \return
|
|
/// \b true if two event messages would result in the same event for the
|
|
/// IDE, e.g. same rounded percentage.
|
|
bool EqualsForIDE(const ProgressEvent &other) const;
|
|
|
|
llvm::StringRef GetEventName() const;
|
|
|
|
ProgressEventType GetEventType() const;
|
|
|
|
/// Report this progress event to the provided callback only if enough time
|
|
/// has passed since the creation of the event and since the previous reported
|
|
/// update.
|
|
bool Report(ProgressEventReportCallback callback);
|
|
|
|
bool Reported() const;
|
|
|
|
private:
|
|
ProgressEvent(uint64_t progress_id, llvm::Optional<llvm::StringRef> message,
|
|
uint64_t completed, uint64_t total,
|
|
const ProgressEvent *prev_event);
|
|
|
|
uint64_t m_progress_id;
|
|
std::string m_message;
|
|
ProgressEventType m_event_type;
|
|
llvm::Optional<uint32_t> m_percentage;
|
|
std::chrono::duration<double> m_creation_time =
|
|
std::chrono::system_clock::now().time_since_epoch();
|
|
std::chrono::duration<double> m_minimum_allowed_report_time;
|
|
bool m_reported = false;
|
|
};
|
|
|
|
/// Class that keeps the start event and its most recent update.
|
|
/// It controls when the event should start being reported to the IDE.
|
|
class ProgressEventManager {
|
|
public:
|
|
ProgressEventManager(const ProgressEvent &start_event,
|
|
ProgressEventReportCallback report_callback);
|
|
|
|
/// Report the start event and the most recent update if the event has lasted
|
|
/// for long enough.
|
|
///
|
|
/// \return
|
|
/// \b false if the event hasn't finished and hasn't reported anything
|
|
/// yet.
|
|
bool ReportIfNeeded();
|
|
|
|
/// Receive a new progress event for the start event and try to report it if
|
|
/// appropriate.
|
|
void Update(uint64_t progress_id, uint64_t completed, uint64_t total);
|
|
|
|
/// \return
|
|
/// \b true if a \a progressEnd event has been notified. There's no
|
|
/// need to try to report manually an event that has finished.
|
|
bool Finished() const;
|
|
|
|
const ProgressEvent &GetMostRecentEvent() const;
|
|
|
|
private:
|
|
ProgressEvent m_start_event;
|
|
llvm::Optional<ProgressEvent> m_last_update_event;
|
|
bool m_finished;
|
|
ProgressEventReportCallback m_report_callback;
|
|
};
|
|
|
|
using ProgressEventManagerSP = std::shared_ptr<ProgressEventManager>;
|
|
|
|
/// Class that filters out progress event messages that shouldn't be reported
|
|
/// to the IDE, because they are invalid, they carry no new information, or they
|
|
/// don't last long enough.
|
|
///
|
|
/// We need to limit the amount of events that are sent to the IDE, as they slow
|
|
/// the render thread of the UI user, and they end up spamming the DAP
|
|
/// connection, which also takes some processing time out of the IDE.
|
|
class ProgressEventReporter {
|
|
public:
|
|
/// \param[in] report_callback
|
|
/// Function to invoke to report the event to the IDE.
|
|
ProgressEventReporter(ProgressEventReportCallback report_callback);
|
|
|
|
~ProgressEventReporter();
|
|
|
|
/// Add a new event to the internal queue and report the event if
|
|
/// appropriate.
|
|
void Push(uint64_t progress_id, const char *message, uint64_t completed,
|
|
uint64_t total);
|
|
|
|
private:
|
|
/// Report to the IDE events that haven't been reported to the IDE and have
|
|
/// lasted long enough.
|
|
void ReportStartEvents();
|
|
|
|
ProgressEventReportCallback m_report_callback;
|
|
std::map<uint64_t, ProgressEventManagerSP> m_event_managers;
|
|
/// Queue of start events in chronological order
|
|
std::queue<ProgressEventManagerSP> m_unreported_start_events;
|
|
/// Thread used to invoke \a ReportStartEvents periodically.
|
|
std::thread m_thread;
|
|
bool m_thread_should_exit;
|
|
/// Mutex that prevents running \a Push and \a ReportStartEvents
|
|
/// simultaneously, as both read and modify the same underlying objects.
|
|
std::mutex m_mutex;
|
|
};
|
|
|
|
} // namespace lldb_vscode
|