[Lldb-commits] [lldb] [lldb] Add an Alarm class for coalescing progress reports (PR #85329)
Adrian Prantl via lldb-commits
lldb-commits at lists.llvm.org
Fri Mar 15 08:28:01 PDT 2024
================
@@ -0,0 +1,193 @@
+//===-- 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<void()> 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<HostThread> 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() {
----------------
adrian-prantl wrote:
I feel like this function could use some high-level comments above each code block
https://github.com/llvm/llvm-project/pull/85329
More information about the lldb-commits
mailing list