258 lines · cpp
1//===-- ThreadPlanStepOverRange.cpp ---------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/ThreadPlanSingleThreadTimeout.h"10#include "lldb/Symbol/Block.h"11#include "lldb/Symbol/CompileUnit.h"12#include "lldb/Symbol/Function.h"13#include "lldb/Symbol/LineTable.h"14#include "lldb/Target/Process.h"15#include "lldb/Target/RegisterContext.h"16#include "lldb/Target/Target.h"17#include "lldb/Target/Thread.h"18#include "lldb/Target/ThreadPlanStepOut.h"19#include "lldb/Target/ThreadPlanStepThrough.h"20#include "lldb/Utility/LLDBLog.h"21#include "lldb/Utility/Log.h"22#include "lldb/Utility/Stream.h"23 24using namespace lldb_private;25using namespace lldb;26 27ThreadPlanSingleThreadTimeout::ThreadPlanSingleThreadTimeout(28 Thread &thread, TimeoutInfoSP &info)29 : ThreadPlan(ThreadPlan::eKindSingleThreadTimeout, "Single thread timeout",30 thread, eVoteNo, eVoteNoOpinion),31 m_info(info), m_state(State::WaitTimeout) {32 m_info->m_isAlive = true;33 m_state = m_info->m_last_state;34 // TODO: reuse m_timer_thread without recreation.35 m_timer_thread = std::thread(TimeoutThreadFunc, this);36}37 38ThreadPlanSingleThreadTimeout::~ThreadPlanSingleThreadTimeout() {39 m_info->m_isAlive = false;40}41 42uint64_t ThreadPlanSingleThreadTimeout::GetRemainingTimeoutMilliSeconds() {43 uint64_t timeout_in_ms = GetThread().GetSingleThreadPlanTimeout();44 std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();45 std::chrono::milliseconds duration_ms =46 std::chrono::duration_cast<std::chrono::milliseconds>(now -47 m_timeout_start);48 return timeout_in_ms - duration_ms.count();49}50 51void ThreadPlanSingleThreadTimeout::GetDescription(52 Stream *s, lldb::DescriptionLevel level) {53 s->Printf("Single thread timeout, state(%s), remaining %" PRIu64 " ms",54 StateToString(m_state).c_str(), GetRemainingTimeoutMilliSeconds());55}56 57std::string ThreadPlanSingleThreadTimeout::StateToString(State state) {58 switch (state) {59 case State::WaitTimeout:60 return "WaitTimeout";61 case State::AsyncInterrupt:62 return "AsyncInterrupt";63 case State::Done:64 return "Done";65 }66 llvm_unreachable("Uncovered state value!");67}68 69void ThreadPlanSingleThreadTimeout::PushNewWithTimeout(Thread &thread,70 TimeoutInfoSP &info) {71 uint64_t timeout_in_ms = thread.GetSingleThreadPlanTimeout();72 if (timeout_in_ms == 0)73 return;74 75 // Do not create timeout if we are not stopping other threads.76 if (!thread.GetCurrentPlan()->StopOthers())77 return;78 79 if (!thread.GetCurrentPlan()->SupportsResumeOthers())80 return;81 82 auto timeout_plan = new ThreadPlanSingleThreadTimeout(thread, info);83 ThreadPlanSP thread_plan_sp(timeout_plan);84 auto status = thread.QueueThreadPlan(thread_plan_sp,85 /*abort_other_plans*/ false);86 Log *log = GetLog(LLDBLog::Step);87 LLDB_LOGF(88 log,89 "ThreadPlanSingleThreadTimeout pushing a brand new one with %" PRIu6490 " ms",91 timeout_in_ms);92}93 94void ThreadPlanSingleThreadTimeout::ResumeFromPrevState(Thread &thread,95 TimeoutInfoSP &info) {96 uint64_t timeout_in_ms = thread.GetSingleThreadPlanTimeout();97 if (timeout_in_ms == 0)98 return;99 100 // There is already an instance alive.101 if (info->m_isAlive)102 return;103 104 // Do not create timeout if we are not stopping other threads.105 if (!thread.GetCurrentPlan()->StopOthers())106 return;107 108 if (!thread.GetCurrentPlan()->SupportsResumeOthers())109 return;110 111 auto timeout_plan = new ThreadPlanSingleThreadTimeout(thread, info);112 ThreadPlanSP thread_plan_sp(timeout_plan);113 auto status = thread.QueueThreadPlan(thread_plan_sp,114 /*abort_other_plans*/ false);115 Log *log = GetLog(LLDBLog::Step);116 LLDB_LOGF(117 log,118 "ThreadPlanSingleThreadTimeout reset from previous state with %" PRIu64119 " ms",120 timeout_in_ms);121}122 123bool ThreadPlanSingleThreadTimeout::WillStop() {124 Log *log = GetLog(LLDBLog::Step);125 LLDB_LOGF(log, "ThreadPlanSingleThreadTimeout::WillStop().");126 127 // Reset the state during stop.128 m_info->m_last_state = State::WaitTimeout;129 return true;130}131 132void ThreadPlanSingleThreadTimeout::DidPop() {133 Log *log = GetLog(LLDBLog::Step);134 {135 std::lock_guard<std::mutex> lock(m_mutex);136 LLDB_LOGF(log, "ThreadPlanSingleThreadTimeout::DidPop().");137 // Tell timer thread to exit.138 m_info->m_isAlive = false;139 }140 m_wakeup_cv.notify_one();141 // Wait for timer thread to exit.142 m_timer_thread.join();143}144 145bool ThreadPlanSingleThreadTimeout::DoPlanExplainsStop(Event *event_ptr) {146 bool is_timeout_interrupt = IsTimeoutAsyncInterrupt(event_ptr);147 Log *log = GetLog(LLDBLog::Step);148 LLDB_LOGF(log,149 "ThreadPlanSingleThreadTimeout::DoPlanExplainsStop() returns %d. "150 "%" PRIu64 " ms remaining.",151 is_timeout_interrupt, GetRemainingTimeoutMilliSeconds());152 return is_timeout_interrupt;153}154 155lldb::StateType ThreadPlanSingleThreadTimeout::GetPlanRunState() {156 return GetPreviousPlan()->GetPlanRunState();157}158 159void ThreadPlanSingleThreadTimeout::TimeoutThreadFunc(160 ThreadPlanSingleThreadTimeout *self) {161 std::unique_lock<std::mutex> lock(self->m_mutex);162 uint64_t timeout_in_ms = self->GetThread().GetSingleThreadPlanTimeout();163 // The thread should wakeup either when timeout or164 // ThreadPlanSingleThreadTimeout has been popped (not alive).165 Log *log = GetLog(LLDBLog::Step);166 self->m_timeout_start = std::chrono::steady_clock::now();167 LLDB_LOGF(168 log,169 "ThreadPlanSingleThreadTimeout::TimeoutThreadFunc(), wait for %" PRIu64170 " ms",171 timeout_in_ms);172 self->m_wakeup_cv.wait_for(lock, std::chrono::milliseconds(timeout_in_ms),173 [self] { return !self->m_info->m_isAlive; });174 LLDB_LOGF(log,175 "ThreadPlanSingleThreadTimeout::TimeoutThreadFunc() wake up with "176 "m_isAlive(%d).",177 self->m_info->m_isAlive);178 if (!self->m_info->m_isAlive)179 return;180 181 self->HandleTimeout();182}183 184bool ThreadPlanSingleThreadTimeout::MischiefManaged() {185 Log *log = GetLog(LLDBLog::Step);186 LLDB_LOGF(log, "ThreadPlanSingleThreadTimeout::MischiefManaged() called.");187 // Need to reset timer on each internal stop/execution progress.188 return true;189}190 191bool ThreadPlanSingleThreadTimeout::ShouldStop(Event *event_ptr) {192 return HandleEvent(event_ptr);193}194 195void ThreadPlanSingleThreadTimeout::SetStopOthers(bool new_value) {196 // Note: this assumes that the SingleThreadTimeout plan is always going to be197 // pushed on behalf of the plan directly above it.198 GetPreviousPlan()->SetStopOthers(new_value);199}200 201bool ThreadPlanSingleThreadTimeout::StopOthers() {202 if (m_state == State::Done)203 return false;204 else205 return GetPreviousPlan()->StopOthers();206}207 208bool ThreadPlanSingleThreadTimeout::IsTimeoutAsyncInterrupt(Event *event_ptr) {209 lldb::StateType stop_state =210 Process::ProcessEventData::GetStateFromEvent(event_ptr);211 Log *log = GetLog(LLDBLog::Step);212 LLDB_LOGF(log,213 "ThreadPlanSingleThreadTimeout::IsTimeoutAsyncInterrupt(): got "214 "event: %s.",215 StateAsCString(stop_state));216 217 lldb::StopInfoSP stop_info = GetThread().GetStopInfo();218 return (m_state == State::AsyncInterrupt &&219 stop_state == lldb::eStateStopped && stop_info &&220 stop_info->GetStopReason() == lldb::eStopReasonInterrupt);221}222 223bool ThreadPlanSingleThreadTimeout::HandleEvent(Event *event_ptr) {224 if (IsTimeoutAsyncInterrupt(event_ptr)) {225 Log *log = GetLog(LLDBLog::Step);226 if (Process::ProcessEventData::GetRestartedFromEvent(event_ptr)) {227 // If we were restarted, we just need to go back up to fetch228 // another event.229 LLDB_LOGF(log,230 "ThreadPlanSingleThreadTimeout::HandleEvent(): Got a stop and "231 "restart, so we'll continue waiting.");232 233 } else {234 LLDB_LOGF(235 log,236 "ThreadPlanSingleThreadTimeout::HandleEvent(): Got async interrupt "237 ", so we will resume all threads.");238 GetThread().GetCurrentPlan()->SetStopOthers(false);239 GetPreviousPlan()->SetStopOthers(false);240 m_state = State::Done;241 }242 }243 // Should not report stop.244 return false;245}246 247void ThreadPlanSingleThreadTimeout::HandleTimeout() {248 Log *log = GetLog(LLDBLog::Step);249 LLDB_LOGF(250 log,251 "ThreadPlanSingleThreadTimeout::HandleTimeout() send async interrupt.");252 m_state = State::AsyncInterrupt;253 254 // Private state thread will only send async interrupt255 // in running state so no need to check state here.256 m_process.SendAsyncInterrupt(&GetThread());257}258