diff --git a/lldb/include/lldb/Core/Progress.h b/lldb/include/lldb/Core/Progress.h index 5876eae717e96..3003568e8946b 100644 --- a/lldb/include/lldb/Core/Progress.h +++ b/lldb/include/lldb/Core/Progress.h @@ -9,7 +9,6 @@ #ifndef LLDB_CORE_PROGRESS_H #define LLDB_CORE_PROGRESS_H -#include "lldb/Host/Alarm.h" #include "lldb/Utility/Timeout.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" @@ -18,6 +17,7 @@ #include #include #include +#include namespace lldb_private { @@ -115,21 +115,6 @@ class Progress { /// Used to indicate a non-deterministic progress report static constexpr uint64_t kNonDeterministicTotal = UINT64_MAX; - /// Data belonging to this Progress event that is used for bookkeeping by - /// ProgressManager. - struct ProgressData { - /// The title of the progress activity, also used as a category. - std::string title; - /// A unique integer identifier for progress reporting. - uint64_t progress_id; - /// The optional debugger ID to report progress to. If this has no value - /// then all debuggers will receive this event. - std::optional debugger_id; - - /// The origin of the progress event, wheter it is internal or external. - Origin origin; - }; - private: void ReportProgress(); static std::atomic g_id; @@ -141,8 +126,18 @@ class Progress { // Minimum amount of time between two progress reports. const Timeout m_minimum_report_time; - /// Data needed by the debugger to broadcast a progress event. - const ProgressData m_progress_data; + /// The title of the progress activity, also used as a category. + const std::string m_title; + + /// A unique integer identifier for progress reporting. + const uint64_t m_progress_id; + + /// The optional debugger ID to report progress to. If this has no value + /// then all debuggers will receive this event. + const std::optional m_debugger_id; + + /// The origin of the progress event, whether it is internal or external. + const Origin m_origin; /// How much work ([0...m_total]) that has been completed. std::atomic m_completed = 0; @@ -161,60 +156,6 @@ class Progress { std::optional m_prev_completed; }; -/// A class used to group progress reports by category. This is done by using a -/// map that maintains a refcount of each category of progress reports that have -/// come in. Keeping track of progress reports this way will be done if a -/// debugger is listening to the eBroadcastBitProgressByCategory broadcast bit. -class ProgressManager { -public: - ProgressManager(); - ~ProgressManager(); - - /// Control the refcount of the progress report category as needed. - void Increment(const Progress::ProgressData &); - void Decrement(const Progress::ProgressData &); - - static void Initialize(); - static void Terminate(); - static bool Enabled(); - static ProgressManager &Instance(); - -protected: - enum class EventType { - Begin, - End, - }; - static void ReportProgress(const Progress::ProgressData &progress_data, - EventType type); - - static std::optional &InstanceImpl(); - - /// Helper function for reporting progress when the alarm in the corresponding - /// entry in the map expires. - void Expire(llvm::StringRef key); - - /// Entry used for bookkeeping. - struct Entry { - /// Reference count used for overlapping events. - uint64_t refcount = 0; - - /// Data used to emit progress events. - Progress::ProgressData data; - - /// Alarm handle used when the refcount reaches zero. - Alarm::Handle handle = Alarm::INVALID_HANDLE; - }; - - /// Map used for bookkeeping. - llvm::StringMap m_entries; - - /// Mutex to provide the map. - std::mutex m_entries_mutex; - - /// Alarm instance to coalesce progress events. - Alarm m_alarm; -}; - } // namespace lldb_private #endif // LLDB_CORE_PROGRESS_H diff --git a/lldb/include/lldb/Host/Alarm.h b/lldb/include/lldb/Host/Alarm.h deleted file mode 100644 index 23b1ff1af5689..0000000000000 --- a/lldb/include/lldb/Host/Alarm.h +++ /dev/null @@ -1,115 +0,0 @@ -//===-- Alarm.h -------------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_HOST_ALARM_H -#define LLDB_HOST_ALARM_H - -#include "lldb/Host/HostThread.h" -#include "lldb/lldb-types.h" -#include "llvm/Support/Chrono.h" - -#include -#include - -namespace lldb_private { - -/// \class Alarm abstraction that enables scheduling a callback function after a -/// specified timeout. Creating an alarm for a callback returns a Handle that -/// can be used to restart or cancel the alarm. -class Alarm { -public: - using Handle = uint64_t; - using Callback = std::function; - using TimePoint = llvm::sys::TimePoint<>; - using Duration = std::chrono::milliseconds; - - Alarm(Duration timeout, bool run_callback_on_exit = false); - ~Alarm(); - - /// Create an alarm for the given callback. The alarm will expire and the - /// callback will be called after the timeout. - /// - /// \returns - /// Handle which can be used to restart or cancel the alarm. - Handle Create(Callback callback); - - /// Restart the alarm for the given Handle. The alarm will expire and the - /// callback will be called after the timeout. - /// - /// \returns - /// True if the alarm was successfully restarted. False if there is no alarm - /// for the given Handle or the alarm already expired. - bool Restart(Handle handle); - - /// Cancel the alarm for the given Handle. The alarm and its handle will be - /// removed. - /// - /// \returns - /// True if the alarm was successfully canceled and the Handle removed. - /// False if there is no alarm for the given Handle or the alarm already - /// expired. - bool Cancel(Handle handle); - - static constexpr Handle INVALID_HANDLE = 0; - -private: - /// Helper functions to start, stop and check the status of the alarm thread. - /// @{ - void StartAlarmThread(); - void StopAlarmThread(); - bool AlarmThreadRunning(); - /// @} - - /// Return an unique, monotonically increasing handle. - static Handle GetNextUniqueHandle(); - - /// Helper to compute the next time the alarm thread needs to wake up. - TimePoint GetNextExpiration() const; - - /// Alarm entry. - struct Entry { - Handle handle; - Callback callback; - TimePoint expiration; - - Entry(Callback callback, TimePoint expiration); - bool operator==(const Entry &rhs) { return handle == rhs.handle; } - }; - - /// List of alarm entries. - std::vector m_entries; - - /// Timeout between when an alarm is created and when it fires. - Duration m_timeout; - - /// The alarm thread. - /// @{ - HostThread m_alarm_thread; - lldb::thread_result_t AlarmThread(); - /// @} - - /// Synchronize access between the alarm thread and the main thread. - std::mutex m_alarm_mutex; - - /// Condition variable used to wake up the alarm thread. - std::condition_variable m_alarm_cv; - - /// Flag to signal the alarm thread that something changed and we need to - /// recompute the next alarm. - bool m_recompute_next_alarm = false; - - /// Flag to signal the alarm thread to exit. - bool m_exit = false; - - /// Flag to signal we should run all callbacks on exit. - bool m_run_callbacks_on_exit = false; -}; - -} // namespace lldb_private - -#endif // LLDB_HOST_ALARM_H diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index fecf9cbb765f7..e30ce5be57b69 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -1356,9 +1356,9 @@ enum DebuggerBroadcastBit { eBroadcastBitWarning = (1 << 1), eBroadcastBitError = (1 << 2), eBroadcastSymbolChange = (1 << 3), - eBroadcastBitProgressCategory = (1 << 4), + eBroadcastBitProgressCategory = (1 << 4), ///< Deprecated eBroadcastBitExternalProgress = (1 << 5), - eBroadcastBitExternalProgressCategory = (1 << 6), + eBroadcastBitExternalProgressCategory = (1 << 6), ///< Deprecated }; /// Used for expressing severity in logs and diagnostics. diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp index 31f3a9f30b81f..9cc3779d1895f 100644 --- a/lldb/source/API/SystemInitializerFull.cpp +++ b/lldb/source/API/SystemInitializerFull.cpp @@ -68,9 +68,6 @@ llvm::Error SystemInitializerFull::Initialize() { const char *arg0 = "lldb"; llvm::cl::ParseCommandLineOptions(1, &arg0); - // Initialize the progress manager. - ProgressManager::Initialize(); - #define LLDB_PLUGIN(p) LLDB_PLUGIN_INITIALIZE(p); #include "Plugins/Plugins.def" @@ -104,9 +101,6 @@ void SystemInitializerFull::Terminate() { #define LLDB_PLUGIN(p) LLDB_PLUGIN_TERMINATE(p); #include "Plugins/Plugins.def" - // Terminate the progress manager. - ProgressManager::Terminate(); - // Now shutdown the common parts, in reverse order. SystemInitializerCommon::Terminate(); } diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index dbe3d72e5efa4..8c705f889983a 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1548,7 +1548,7 @@ void Debugger::ReportProgress(uint64_t progress_id, std::string title, std::string details, uint64_t completed, uint64_t total, std::optional debugger_id, - uint32_t progress_category_bit) { + uint32_t progress_broadcast_bit) { // Check if this progress is for a specific debugger. if (debugger_id) { // It is debugger specific, grab it and deliver the event if the debugger @@ -1558,7 +1558,7 @@ void Debugger::ReportProgress(uint64_t progress_id, std::string title, PrivateReportProgress(*debugger_sp, progress_id, std::move(title), std::move(details), completed, total, /*is_debugger_specific*/ true, - progress_category_bit); + progress_broadcast_bit); return; } // The progress event is not debugger specific, iterate over all debuggers @@ -1569,7 +1569,7 @@ void Debugger::ReportProgress(uint64_t progress_id, std::string title, for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) PrivateReportProgress(*(*pos), progress_id, title, details, completed, total, /*is_debugger_specific*/ false, - progress_category_bit); + progress_broadcast_bit); } } diff --git a/lldb/source/Core/Progress.cpp b/lldb/source/Core/Progress.cpp index 63f9804320809..d29dce0a688c0 100644 --- a/lldb/source/Core/Progress.cpp +++ b/lldb/source/Core/Progress.cpp @@ -31,11 +31,11 @@ Progress::Progress(std::string title, std::string details, Timeout minimum_report_time, Progress::Origin origin) : m_total(total.value_or(Progress::kNonDeterministicTotal)), - m_minimum_report_time(minimum_report_time), - m_progress_data{title, ++g_id, - debugger ? std::optional(debugger->GetID()) - : std::nullopt, - origin}, + m_minimum_report_time(minimum_report_time), m_title(title), + m_progress_id(++g_id), + m_debugger_id(debugger ? std::optional(debugger->GetID()) + : std::nullopt), + m_origin(origin), m_last_report_time_ns( std::chrono::nanoseconds( std::chrono::steady_clock::now().time_since_epoch()) @@ -44,27 +44,19 @@ Progress::Progress(std::string title, std::string details, std::lock_guard guard(m_mutex); ReportProgress(); - // Report to the ProgressManager if that subsystem is enabled. - if (ProgressManager::Enabled()) - ProgressManager::Instance().Increment(m_progress_data); - // Start signpost interval right before the meaningful work starts. - g_progress_signposts->startInterval(this, m_progress_data.title); + g_progress_signposts->startInterval(this, m_title); } Progress::~Progress() { // End signpost interval as soon as possible. - g_progress_signposts->endInterval(this, m_progress_data.title); + g_progress_signposts->endInterval(this, m_title); // Make sure to always report progress completed when this object is // destructed so it indicates the progress dialog/activity should go away. std::lock_guard guard(m_mutex); m_completed = m_total; ReportProgress(); - - // Report to the ProgressManager if that subsystem is enabled. - if (ProgressManager::Enabled()) - ProgressManager::Instance().Decrement(m_progress_data); } void Progress::Increment(uint64_t amount, @@ -109,128 +101,11 @@ void Progress::ReportProgress() { return; // An overflow in the m_completed counter. Just ignore these events. // Change the category bit if we're an internal or external progress. - uint32_t progress_category_bit = - m_progress_data.origin == Progress::Origin::eExternal - ? lldb::eBroadcastBitExternalProgress - : lldb::eBroadcastBitProgress; - - Debugger::ReportProgress(m_progress_data.progress_id, m_progress_data.title, - m_details, completed, m_total, - m_progress_data.debugger_id, progress_category_bit); - m_prev_completed = completed; -} - -ProgressManager::ProgressManager() - : m_entries(), m_alarm(std::chrono::milliseconds(100)) {} - -ProgressManager::~ProgressManager() {} - -void ProgressManager::Initialize() { - assert(!InstanceImpl() && "Already initialized."); - InstanceImpl().emplace(); -} - -void ProgressManager::Terminate() { - assert(InstanceImpl() && "Already terminated."); - InstanceImpl().reset(); -} - -bool ProgressManager::Enabled() { return InstanceImpl().operator bool(); } - -ProgressManager &ProgressManager::Instance() { - assert(InstanceImpl() && "ProgressManager must be initialized"); - return *InstanceImpl(); -} - -std::optional &ProgressManager::InstanceImpl() { - static std::optional g_progress_manager; - return g_progress_manager; -} - -void ProgressManager::Increment(const Progress::ProgressData &progress_data) { - std::lock_guard lock(m_entries_mutex); - - llvm::StringRef key = progress_data.title; - bool new_entry = !m_entries.contains(key); - Entry &entry = m_entries[progress_data.title]; - - if (new_entry) { - // This is a new progress event. Report progress and store the progress - // data. - ReportProgress(progress_data, EventType::Begin); - entry.data = progress_data; - } else if (entry.refcount == 0) { - // This is an existing entry that was scheduled to be deleted but a new one - // came in before the timer expired. - assert(entry.handle != Alarm::INVALID_HANDLE); - - if (!m_alarm.Cancel(entry.handle)) { - // The timer expired before we had a chance to cancel it. We have to treat - // this as an entirely new progress event. - ReportProgress(progress_data, EventType::Begin); - } - // Clear the alarm handle. - entry.handle = Alarm::INVALID_HANDLE; - } - - // Regardless of how we got here, we need to bump the reference count. - entry.refcount++; -} - -void ProgressManager::Decrement(const Progress::ProgressData &progress_data) { - std::lock_guard lock(m_entries_mutex); - llvm::StringRef key = progress_data.title; - - auto it = m_entries.find(key); - if (it == m_entries.end()) - return; - - Entry &entry = it->second; - entry.refcount--; - - if (entry.refcount == 0) { - assert(entry.handle == Alarm::INVALID_HANDLE); - - // Copy the key to a std::string so we can pass it by value to the lambda. - // The underlying StringRef will not exist by the time the callback is - // called. - std::string key_str = std::string(key); - - // Start a timer. If it expires before we see another progress event, it - // will be reported. - entry.handle = m_alarm.Create([=]() { Expire(key_str); }); - } -} - -void ProgressManager::ReportProgress( - const Progress::ProgressData &progress_data, EventType type) { - // The category bit only keeps track of when progress report categories have - // started and ended, so clear the details and reset other fields when - // broadcasting to it since that bit doesn't need that information. - const uint64_t completed = - (type == EventType::Begin) ? 0 : Progress::kNonDeterministicTotal; - const uint32_t progress_category_bit = - progress_data.origin == Progress::Origin::eExternal - ? lldb::eBroadcastBitExternalProgressCategory - : lldb::eBroadcastBitProgressCategory; - Debugger::ReportProgress(progress_data.progress_id, progress_data.title, "", - completed, Progress::kNonDeterministicTotal, - progress_data.debugger_id, progress_category_bit); -} + uint32_t progress_category_bit = m_origin == Progress::Origin::eExternal + ? lldb::eBroadcastBitExternalProgress + : lldb::eBroadcastBitProgress; -void ProgressManager::Expire(llvm::StringRef key) { - std::lock_guard lock(m_entries_mutex); - - // This shouldn't happen but be resilient anyway. - if (!m_entries.contains(key)) - return; - - // A new event came in and the alarm fired before we had a chance to restart - // it. - if (m_entries[key].refcount != 0) - return; - - // We're done with this entry. - ReportProgress(m_entries[key].data, EventType::End); - m_entries.erase(key); + Debugger::ReportProgress(m_progress_id, m_title, m_details, completed, + m_total, m_debugger_id, progress_category_bit); + m_prev_completed = completed; } diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index f4be151756b3b..9be0c06a516ba 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -13,7 +13,6 @@ macro(add_host_subdirectory group) endmacro() add_host_subdirectory(common - common/Alarm.cpp common/FileAction.cpp common/FileCache.cpp common/File.cpp diff --git a/lldb/source/Host/common/Alarm.cpp b/lldb/source/Host/common/Alarm.cpp deleted file mode 100644 index afc770d20d7b1..0000000000000 --- a/lldb/source/Host/common/Alarm.cpp +++ /dev/null @@ -1,222 +0,0 @@ -//===-- Alarm.cpp ---------------------------------------------------------===// -// -// 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 "lldb/Host/Alarm.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" - -using namespace lldb; -using namespace lldb_private; - -Alarm::Alarm(Duration timeout, bool run_callback_on_exit) - : m_timeout(timeout), m_run_callbacks_on_exit(run_callback_on_exit) { - StartAlarmThread(); -} - -Alarm::~Alarm() { StopAlarmThread(); } - -Alarm::Handle Alarm::Create(std::function callback) { - // Gracefully deal with the unlikely event that the alarm thread failed to - // launch. - if (!AlarmThreadRunning()) - return INVALID_HANDLE; - - // Compute the next expiration before we take the lock. This ensures that - // waiting on the lock doesn't eat into the timeout. - const TimePoint expiration = GetNextExpiration(); - - Handle handle = INVALID_HANDLE; - - { - std::lock_guard alarm_guard(m_alarm_mutex); - - // Create a new unique entry and remember its handle. - m_entries.emplace_back(callback, expiration); - handle = m_entries.back().handle; - - // Tell the alarm thread we need to recompute the next alarm. - m_recompute_next_alarm = true; - } - - m_alarm_cv.notify_one(); - return handle; -} - -bool Alarm::Restart(Handle handle) { - // Gracefully deal with the unlikely event that the alarm thread failed to - // launch. - if (!AlarmThreadRunning()) - return false; - - // Compute the next expiration before we take the lock. This ensures that - // waiting on the lock doesn't eat into the timeout. - const TimePoint expiration = GetNextExpiration(); - - { - std::lock_guard alarm_guard(m_alarm_mutex); - - // Find the entry corresponding to the given handle. - const auto it = - std::find_if(m_entries.begin(), m_entries.end(), - [handle](Entry &entry) { return entry.handle == handle; }); - if (it == m_entries.end()) - return false; - - // Update the expiration. - it->expiration = expiration; - - // Tell the alarm thread we need to recompute the next alarm. - m_recompute_next_alarm = true; - } - - m_alarm_cv.notify_one(); - return true; -} - -bool Alarm::Cancel(Handle handle) { - // Gracefully deal with the unlikely event that the alarm thread failed to - // launch. - if (!AlarmThreadRunning()) - return false; - - { - std::lock_guard alarm_guard(m_alarm_mutex); - - const auto it = - std::find_if(m_entries.begin(), m_entries.end(), - [handle](Entry &entry) { return entry.handle == handle; }); - - if (it == m_entries.end()) - return false; - - m_entries.erase(it); - } - - // No need to notify the alarm thread. This only affects the alarm thread if - // we removed the entry that corresponds to the next alarm. If that's the - // case, the thread will wake up as scheduled, find no expired events, and - // recompute the next alarm time. - return true; -} - -Alarm::Entry::Entry(Alarm::Callback callback, Alarm::TimePoint expiration) - : handle(Alarm::GetNextUniqueHandle()), callback(std::move(callback)), - expiration(std::move(expiration)) {} - -void Alarm::StartAlarmThread() { - if (!m_alarm_thread.IsJoinable()) { - llvm::Expected alarm_thread = ThreadLauncher::LaunchThread( - "lldb.debugger.alarm-thread", [this] { return AlarmThread(); }, - 8 * 1024 * 1024); // Use larger 8MB stack for this thread - if (alarm_thread) { - m_alarm_thread = *alarm_thread; - } else { - LLDB_LOG_ERROR(GetLog(LLDBLog::Host), alarm_thread.takeError(), - "failed to launch host thread: {0}"); - } - } -} - -void Alarm::StopAlarmThread() { - if (m_alarm_thread.IsJoinable()) { - { - std::lock_guard alarm_guard(m_alarm_mutex); - m_exit = true; - } - m_alarm_cv.notify_one(); - m_alarm_thread.Join(nullptr); - } -} - -bool Alarm::AlarmThreadRunning() { return m_alarm_thread.IsJoinable(); } - -lldb::thread_result_t Alarm::AlarmThread() { - bool exit = false; - std::optional next_alarm; - - const auto predicate = [this] { return m_exit || m_recompute_next_alarm; }; - - while (!exit) { - // Synchronization between the main thread and the alarm thread using a - // mutex and condition variable. There are 2 reasons the thread can wake up: - // - // 1. The timeout for the next alarm expired. - // - // 2. The condition variable is notified that one of our shared variables - // (see predicate) was modified. Either the thread is asked to shut down - // or a new alarm came in and we need to recompute the next timeout. - // - // Below we only deal with the timeout expiring and fall through for dealing - // with the rest. - llvm::SmallVector callbacks; - { - std::unique_lock alarm_lock(m_alarm_mutex); - if (next_alarm) { - if (!m_alarm_cv.wait_until(alarm_lock, *next_alarm, predicate)) { - // The timeout for the next alarm expired. - - // Clear the next timeout to signal that we need to recompute the next - // timeout. - next_alarm.reset(); - - // Iterate over all the callbacks. Call the ones that have expired - // and remove them from the list. - const TimePoint now = std::chrono::system_clock::now(); - auto it = m_entries.begin(); - while (it != m_entries.end()) { - if (it->expiration <= now) { - callbacks.emplace_back(std::move(it->callback)); - it = m_entries.erase(it); - } else { - it++; - } - } - } - } else { - m_alarm_cv.wait(alarm_lock, predicate); - } - - // Fall through after waiting on the condition variable. At this point - // either the predicate is true or we woke up because an alarm expired. - - // The alarm thread is shutting down. - if (m_exit) { - exit = true; - if (m_run_callbacks_on_exit) { - for (Entry &entry : m_entries) - callbacks.emplace_back(std::move(entry.callback)); - } - } - - // A new alarm was added or an alarm expired. Either way we need to - // recompute when this thread should wake up for the next alarm. - if (m_recompute_next_alarm || !next_alarm) { - for (Entry &entry : m_entries) { - if (!next_alarm || entry.expiration < *next_alarm) - next_alarm = entry.expiration; - } - m_recompute_next_alarm = false; - } - } - - // Outside the lock, call the callbacks. - for (Callback &callback : callbacks) - callback(); - } - return {}; -} - -Alarm::TimePoint Alarm::GetNextExpiration() const { - return std::chrono::system_clock::now() + m_timeout; -} - -Alarm::Handle Alarm::GetNextUniqueHandle() { - static std::atomic g_next_handle = 1; - return g_next_handle++; -} diff --git a/lldb/test/API/python_api/sbprogress/TestSBProgress.py b/lldb/test/API/python_api/sbprogress/TestSBProgress.py index 2a0689a52a185..b64c4b9c7206e 100644 --- a/lldb/test/API/python_api/sbprogress/TestSBProgress.py +++ b/lldb/test/API/python_api/sbprogress/TestSBProgress.py @@ -43,7 +43,7 @@ def test_progress_finalize_non_deterministic_progress(self): progress = lldb.SBProgress("Test SBProgress", "Test finalize", self.dbg) listener = lldb.SBListener("Test listener") broadcaster = self.dbg.GetBroadcaster() - broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgressCategory) + broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgress) event = lldb.SBEvent() progress.Finalize() self.assertTrue(listener.WaitForEvent(5, event)) @@ -57,7 +57,7 @@ def test_progress_finalize_deterministic_progress(self): progress = lldb.SBProgress("Test SBProgress", "Test finalize", 13, self.dbg) listener = lldb.SBListener("Test listener") broadcaster = self.dbg.GetBroadcaster() - broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgressCategory) + broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgress) event = lldb.SBEvent() progress.Finalize() self.assertTrue(listener.WaitForEvent(5, event)) diff --git a/lldb/unittests/Callback/TestBreakpointSetCallback.cpp b/lldb/unittests/Callback/TestBreakpointSetCallback.cpp index 3dba4a9eb719e..c29cac5d2e5e7 100644 --- a/lldb/unittests/Callback/TestBreakpointSetCallback.cpp +++ b/lldb/unittests/Callback/TestBreakpointSetCallback.cpp @@ -52,8 +52,7 @@ class BreakpointSetCallbackTest : public ::testing::Test { DebuggerSP m_debugger_sp; PlatformSP m_platform_sp; - SubsystemRAII - subsystems; + SubsystemRAII subsystems; }; TEST_F(BreakpointSetCallbackTest, TestBreakpointSetCallback) { diff --git a/lldb/unittests/Core/ProgressReportTest.cpp b/lldb/unittests/Core/ProgressReportTest.cpp index 0943d7b990809..592e13a79e8d7 100644 --- a/lldb/unittests/Core/ProgressReportTest.cpp +++ b/lldb/unittests/Core/ProgressReportTest.cpp @@ -57,8 +57,7 @@ class ProgressReportTest : public ::testing::Test { DebuggerSP m_debugger_sp; ListenerSP m_listener_sp; - SubsystemRAII - subsystems; + SubsystemRAII subsystems; }; TEST_F(ProgressReportTest, TestReportCreation) { @@ -313,119 +312,6 @@ TEST_F(ProgressReportTest, TestMinimumReportTime) { ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT)); } -TEST_F(ProgressReportTest, TestProgressManager) { - ListenerSP listener_sp = - CreateListenerFor(lldb::eBroadcastBitProgressCategory); - EventSP event_sp; - const ProgressEventData *data; - - // Create three progress events with the same category then try to pop 2 - // events from the queue in a row before the progress reports are destroyed. - // Since only 1 event should've been broadcast for this category, the second - // GetEvent() call should return false. - { - Progress progress1("Progress report 1", "Starting report 1"); - Progress progress2("Progress report 1", "Starting report 2"); - Progress progress3("Progress report 1", "Starting report 3"); - ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); - ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT)); - } - - data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); - - EXPECT_EQ(data->GetDetails(), ""); - EXPECT_FALSE(data->IsFinite()); - EXPECT_FALSE(data->GetCompleted()); - EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); - EXPECT_EQ(data->GetMessage(), "Progress report 1"); - - // Pop another event from the queue, this should be the event for the final - // report for this category. - ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); - data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); - - EXPECT_EQ(data->GetDetails(), ""); - EXPECT_FALSE(data->IsFinite()); - EXPECT_TRUE(data->GetCompleted()); - EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); - EXPECT_EQ(data->GetMessage(), "Progress report 1"); -} - -TEST_F(ProgressReportTest, TestOverlappingEvents) { - ListenerSP listener_sp = - CreateListenerFor(lldb::eBroadcastBitProgressCategory); - EventSP event_sp; - const ProgressEventData *data; - - // Create two progress reports of the same category that overlap with each - // other. Here we want to ensure that the ID broadcasted for the initial and - // final reports for this category are the same. - std::unique_ptr overlap_progress1 = - std::make_unique("Overlapping report 1", "Starting report 1"); - std::unique_ptr overlap_progress2 = - std::make_unique("Overlapping report 1", "Starting report 2"); - overlap_progress1.reset(); - - ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); - data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); - // Get the ID used in the first report for this category. - uint64_t expected_progress_id = data->GetID(); - - EXPECT_EQ(data->GetDetails(), ""); - EXPECT_FALSE(data->IsFinite()); - EXPECT_FALSE(data->GetCompleted()); - EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); - EXPECT_EQ(data->GetMessage(), "Overlapping report 1"); - - overlap_progress2.reset(); - - ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); - data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); - - EXPECT_EQ(data->GetDetails(), ""); - EXPECT_FALSE(data->IsFinite()); - EXPECT_TRUE(data->GetCompleted()); - EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); - EXPECT_EQ(data->GetMessage(), "Overlapping report 1"); - // The progress ID for the final report should be the same as that for the - // initial report. - EXPECT_EQ(data->GetID(), expected_progress_id); -} - -TEST_F(ProgressReportTest, TestProgressManagerDisjointReports) { - ListenerSP listener_sp = - CreateListenerFor(lldb::eBroadcastBitProgressCategory); - EventSP event_sp; - const ProgressEventData *data; - uint64_t expected_progress_id; - - { Progress progress("Coalesced report 1", "Starting report 1"); } - { Progress progress("Coalesced report 1", "Starting report 2"); } - { Progress progress("Coalesced report 1", "Starting report 3"); } - - ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); - data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); - expected_progress_id = data->GetID(); - - EXPECT_EQ(data->GetDetails(), ""); - EXPECT_FALSE(data->IsFinite()); - EXPECT_FALSE(data->GetCompleted()); - EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); - EXPECT_EQ(data->GetMessage(), "Coalesced report 1"); - - ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); - data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); - - EXPECT_EQ(data->GetID(), expected_progress_id); - EXPECT_EQ(data->GetDetails(), ""); - EXPECT_FALSE(data->IsFinite()); - EXPECT_TRUE(data->GetCompleted()); - EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); - EXPECT_EQ(data->GetMessage(), "Coalesced report 1"); - - ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT)); -} - TEST_F(ProgressReportTest, TestExternalReportCreation) { ListenerSP listener_sp = CreateListenerFor(lldb::eBroadcastBitExternalProgress); diff --git a/lldb/unittests/Host/AlarmTest.cpp b/lldb/unittests/Host/AlarmTest.cpp deleted file mode 100644 index 94e72af3ffe8d..0000000000000 --- a/lldb/unittests/Host/AlarmTest.cpp +++ /dev/null @@ -1,172 +0,0 @@ -//===-- AlarmTest.cpp -----------------------------------------------------===// -// -// 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 "lldb/Host/Alarm.h" -#include "gtest/gtest.h" - -#include -#include - -using namespace lldb_private; -using namespace std::chrono_literals; - -// Increase the timeout tenfold when running under ASan as it can have about the -// same performance overhead. -#if __has_feature(address_sanitizer) -static constexpr auto TEST_TIMEOUT = 10000ms; -#else -static constexpr auto TEST_TIMEOUT = 1000ms; -#endif - -// The time between scheduling a callback and it getting executed. This should -// NOT be increased under ASan. -static constexpr auto ALARM_TIMEOUT = 500ms; - -// If there are any pending callbacks, make sure they run before the Alarm -// object is destroyed. -static constexpr bool RUN_CALLBACKS_ON_EXIT = true; - -TEST(AlarmTest, Create) { - std::mutex m; - - std::vector callbacks_actual; - std::vector callbacks_expected; - - Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); - - // Create 5 alarms some time apart. - for (size_t i = 0; i < 5; ++i) { - callbacks_actual.emplace_back(); - callbacks_expected.emplace_back(std::chrono::system_clock::now() + - ALARM_TIMEOUT); - - alarm.Create([&callbacks_actual, &m, i]() { - std::lock_guard guard(m); - callbacks_actual[i] = std::chrono::system_clock::now(); - }); - - std::this_thread::sleep_for(ALARM_TIMEOUT / 5); - } - - // Leave plenty of time for all the alarms to fire. - std::this_thread::sleep_for(TEST_TIMEOUT); - - // Acquire the lock to check the callbacks. - std::lock_guard guard(m); - - // Make sure all the alarms fired around the expected time. - for (size_t i = 0; i < 5; ++i) - EXPECT_GE(callbacks_actual[i], callbacks_expected[i]); -} - -TEST(AlarmTest, Exit) { - std::mutex m; - - std::vector handles; - std::vector callbacks; - - { - Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); - - // Create 5 alarms. - for (size_t i = 0; i < 5; ++i) { - callbacks.emplace_back(false); - - handles.push_back(alarm.Create([&callbacks, &m, i]() { - std::lock_guard guard(m); - callbacks[i] = true; - })); - } - - // Let the alarm go out of scope before any alarm had a chance to fire. - } - - // Acquire the lock to check the callbacks. - std::lock_guard guard(m); - - // Make sure none of the alarms fired. - for (bool callback : callbacks) - EXPECT_TRUE(callback); -} - -TEST(AlarmTest, Cancel) { - std::mutex m; - - std::vector handles; - std::vector callbacks; - - Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); - - // Create 5 alarms. - for (size_t i = 0; i < 5; ++i) { - callbacks.emplace_back(false); - - handles.push_back(alarm.Create([&callbacks, &m, i]() { - std::lock_guard guard(m); - callbacks[i] = true; - })); - } - - // Make sure we can cancel the first 4 alarms. - for (size_t i = 0; i < 4; ++i) - EXPECT_TRUE(alarm.Cancel(handles[i])); - - // Leave plenty of time for all the alarms to fire. - std::this_thread::sleep_for(TEST_TIMEOUT); - - // Acquire the lock to check the callbacks. - std::lock_guard guard(m); - - // Make sure none of the first 4 alarms fired. - for (size_t i = 0; i < 4; ++i) - EXPECT_FALSE(callbacks[i]); - - // Make sure the fifth alarm still fired. - EXPECT_TRUE(callbacks[4]); -} - -TEST(AlarmTest, Restart) { - std::mutex m; - - std::vector handles; - std::vector callbacks_actual; - std::vector callbacks_expected; - - Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); - - // Create 5 alarms some time apart. - for (size_t i = 0; i < 5; ++i) { - callbacks_actual.emplace_back(); - callbacks_expected.emplace_back(std::chrono::system_clock::now() + - ALARM_TIMEOUT); - - handles.push_back(alarm.Create([&callbacks_actual, &m, i]() { - std::lock_guard guard(m); - callbacks_actual[i] = std::chrono::system_clock::now(); - })); - - std::this_thread::sleep_for(ALARM_TIMEOUT / 5); - } - - // Update the last 2 alarms. - for (size_t i = 3; i < 5; ++i) { - std::lock_guard guard(m); - callbacks_expected[i] = std::chrono::system_clock::now() + ALARM_TIMEOUT; - EXPECT_TRUE(alarm.Restart(handles[i])); - } - - // Leave plenty of time for all the alarms to fire. - std::this_thread::sleep_for(TEST_TIMEOUT); - - // Acquire the lock to check the callbacks. - std::lock_guard guard(m); - - // Make sure all the alarms around the expected time. - for (size_t i = 0; i < 5; ++i) - EXPECT_GE(callbacks_actual[i], callbacks_expected[i]); -} diff --git a/lldb/unittests/Host/CMakeLists.txt b/lldb/unittests/Host/CMakeLists.txt index 7c09932b39c2a..c959478970d18 100644 --- a/lldb/unittests/Host/CMakeLists.txt +++ b/lldb/unittests/Host/CMakeLists.txt @@ -1,5 +1,4 @@ set (FILES - AlarmTest.cpp ConnectionFileDescriptorTest.cpp FileActionTest.cpp FileSystemTest.cpp