blob: 753b7db5e41df4baa5620c4cd8f83334bbc16677 [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)
, broadcast(ctx->broadcast())
{}
void Thread::setName(const std::string &name)
{
std::unique_lock<std::mutex> lock(mutex);
name_ = name;
}
std::string Thread::name() const
{
std::unique_lock<std::mutex> lock(mutex);
return name_;
}
void Thread::onLocationUpdate(std::unique_lock<std::mutex> &lock)
{
auto location = frames.back()->location;
if(state_ == State::Running)
{
if(location.file->hasBreakpoint(location.line))
{
broadcast->onLineBreakpointHit(id);
state_ = State::Paused;
}
}
switch(state_)
{
case State::Paused:
{
stateCV.wait(lock, [this] { return state_ != State::Paused; });
break;
}
case State::Stepping:
{
if(!pauseAtFrame || pauseAtFrame == frames.back())
{
broadcast->onThreadStepped(id);
state_ = State::Paused;
stateCV.wait(lock, [this] { return state_ != State::Paused; });
pauseAtFrame = 0;
}
break;
}
case State::Running:
break;
}
}
void Thread::enter(Context::Lock &ctxlck, const std::shared_ptr<File> &file, const std::string &function)
{
auto frame = ctxlck.createFrame(file, function);
auto isFunctionBreakpoint = ctxlck.isFunctionBreakpoint(function);
std::unique_lock<std::mutex> lock(mutex);
frames.push_back(frame);
if(isFunctionBreakpoint)
{
broadcast->onFunctionBreakpointHit(id);
state_ = State::Paused;
}
}
void Thread::exit()
{
std::unique_lock<std::mutex> lock(mutex);
frames.pop_back();
}
void Thread::update(std::function<void(Frame &)> f)
{
std::unique_lock<std::mutex> lock(mutex);
auto &frame = *frames.back();
auto oldLocation = frame.location;
f(frame);
if(frame.location != oldLocation)
{
onLocationUpdate(lock);
}
}
Frame Thread::frame() const
{
std::unique_lock<std::mutex> lock(mutex);
return *frames.back();
}
std::vector<Frame> Thread::stack() const
{
std::unique_lock<std::mutex> lock(mutex);
std::vector<Frame> out;
out.reserve(frames.size());
for(auto frame : frames)
{
out.push_back(*frame);
}
return out;
}
Thread::State Thread::state() const
{
std::unique_lock<std::mutex> lock(mutex);
return state_;
}
void Thread::resume()
{
std::unique_lock<std::mutex> lock(mutex);
state_ = State::Running;
lock.unlock();
stateCV.notify_all();
}
void Thread::pause()
{
std::unique_lock<std::mutex> lock(mutex);
state_ = State::Paused;
}
void Thread::stepIn()
{
std::unique_lock<std::mutex> lock(mutex);
state_ = State::Stepping;
pauseAtFrame.reset();
stateCV.notify_all();
}
void Thread::stepOver()
{
std::unique_lock<std::mutex> lock(mutex);
state_ = State::Stepping;
pauseAtFrame = frames.back();
stateCV.notify_all();
}
void Thread::stepOut()
{
std::unique_lock<std::mutex> lock(mutex);
state_ = State::Stepping;
pauseAtFrame = (frames.size() > 1) ? frames[frames.size() - 1] : nullptr;
stateCV.notify_all();
}
} // namespace dbg
} // namespace vk