blob: dd9e22de8201734d67b5733effeb43c26d1ad01a [file] [log] [blame]
// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "Thread.hpp"
#include "Context.hpp"
#include "EventListener.hpp"
#include "File.hpp"
namespace vk {
namespace dbg {
Thread::Thread(ID id, Context *ctx)
: id(id)
, ctx(ctx)
{}
void Thread::setName(const std::string &name)
{
marl::lock lock(mutex);
name_ = name;
}
std::string Thread::name() const
{
marl::lock lock(mutex);
return name_;
}
void Thread::onLocationUpdate(marl::lock &lock)
{
auto location = frames.back()->location;
if(state_ == State::Running)
{
if(location.file->hasBreakpoint(location.line))
{
ctx->serverEventBroadcast()->onLineBreakpointHit(id);
state_ = State::Paused;
}
}
switch(state_)
{
case State::Paused:
{
lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
break;
}
case State::Stepping:
{
bool pause = false;
{
auto frame = pauseAtFrame.lock();
pause = !frame; // Pause if there's no pause-at-frame...
if(frame == frames.back()) // ... or if we've reached the pause-at-frame
{
pause = true;
pauseAtFrame.reset();
}
}
if(pause)
{
ctx->serverEventBroadcast()->onThreadStepped(id);
state_ = State::Paused;
lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
}
break;
}
case State::Running:
break;
}
}
void Thread::enter(const std::shared_ptr<File> &file, const std::string &function, const UpdateFrame &f)
{
std::shared_ptr<Frame> frame;
bool isFunctionBreakpoint;
{
auto lock = ctx->lock();
frame = lock.createFrame(file, function);
isFunctionBreakpoint = lock.isFunctionBreakpoint(function);
}
{
marl::lock lock(mutex);
frames.push_back(frame);
if(f) { f(*frame); }
if(isFunctionBreakpoint)
{
ctx->serverEventBroadcast()->onFunctionBreakpointHit(id);
state_ = State::Paused;
}
onLocationUpdate(lock);
}
}
void Thread::exit(bool isStep /* = false */)
{
marl::lock lock(mutex);
frames.pop_back();
if(isStep)
{
onLocationUpdate(lock);
}
}
void Thread::update(bool isStep, const UpdateFrame &f)
{
marl::lock lock(mutex);
auto &frame = *frames.back();
if(isStep)
{
auto oldLocation = frame.location;
f(frame);
if(frame.location != oldLocation)
{
onLocationUpdate(lock);
}
}
else
{
f(frame);
}
}
Frame Thread::frame() const
{
marl::lock lock(mutex);
return *frames.back();
}
std::vector<Frame> Thread::stack() const
{
marl::lock lock(mutex);
std::vector<Frame> out;
out.reserve(frames.size());
for(auto frame : frames)
{
out.push_back(*frame);
}
return out;
}
size_t Thread::depth() const
{
marl::lock lock(mutex);
return frames.size();
}
Thread::State Thread::state() const
{
marl::lock lock(mutex);
return state_;
}
void Thread::resume()
{
{
marl::lock lock(mutex);
state_ = State::Running;
}
stateCV.notify_all();
}
void Thread::pause()
{
marl::lock lock(mutex);
state_ = State::Paused;
}
void Thread::stepIn()
{
marl::lock lock(mutex);
state_ = State::Stepping;
pauseAtFrame.reset();
stateCV.notify_all();
}
void Thread::stepOver()
{
marl::lock lock(mutex);
state_ = State::Stepping;
pauseAtFrame = frames.back();
stateCV.notify_all();
}
void Thread::stepOut()
{
marl::lock lock(mutex);
state_ = State::Stepping;
pauseAtFrame = (frames.size() > 1) ? frames[frames.size() - 2] : nullptr;
stateCV.notify_all();
}
} // namespace dbg
} // namespace vk