xref: /aosp_15_r20/external/swiftshader/src/Vulkan/Debug/Thread.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "Thread.hpp"
16 
17 #include "Context.hpp"
18 #include "EventListener.hpp"
19 #include "File.hpp"
20 
21 namespace vk {
22 namespace dbg {
23 
Thread(ID id,Context * ctx)24 Thread::Thread(ID id, Context *ctx)
25     : id(id)
26     , ctx(ctx)
27 {}
28 
setName(const std::string & name)29 void Thread::setName(const std::string &name)
30 {
31 	marl::lock lock(mutex);
32 	name_ = name;
33 }
34 
name() const35 std::string Thread::name() const
36 {
37 	marl::lock lock(mutex);
38 	return name_;
39 }
40 
onLocationUpdate(marl::lock & lock)41 void Thread::onLocationUpdate(marl::lock &lock)
42 {
43 	auto location = frames.back()->location;
44 
45 	if(state_ == State::Running)
46 	{
47 		if(location.file->hasBreakpoint(location.line))
48 		{
49 			ctx->serverEventBroadcast()->onLineBreakpointHit(id);
50 			state_ = State::Paused;
51 		}
52 	}
53 
54 	switch(state_)
55 	{
56 	case State::Paused:
57 		lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
58 		break;
59 
60 	case State::Stepping:
61 		{
62 			bool pause = false;
63 
64 			{
65 				auto frame = pauseAtFrame.lock();
66 				pause = !frame;             // Pause if there's no pause-at-frame...
67 				if(frame == frames.back())  // ... or if we've reached the pause-at-frame
68 				{
69 					pause = true;
70 					pauseAtFrame.reset();
71 				}
72 			}
73 
74 			if(pause)
75 			{
76 				ctx->serverEventBroadcast()->onThreadStepped(id);
77 				state_ = State::Paused;
78 				lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
79 			}
80 		}
81 		break;
82 
83 	case State::Running:
84 		break;
85 	}
86 }
87 
enter(const std::shared_ptr<File> & file,const std::string & function,const UpdateFrame & f)88 void Thread::enter(const std::shared_ptr<File> &file, const std::string &function, const UpdateFrame &f)
89 {
90 	std::shared_ptr<Frame> frame;
91 	bool isFunctionBreakpoint;
92 	{
93 		auto lock = ctx->lock();
94 		frame = lock.createFrame(file, function);
95 		isFunctionBreakpoint = lock.isFunctionBreakpoint(function);
96 	}
97 
98 	{
99 		marl::lock lock(mutex);
100 		frames.push_back(frame);
101 
102 		if(f) { f(*frame); }
103 
104 		if(isFunctionBreakpoint)
105 		{
106 			ctx->serverEventBroadcast()->onFunctionBreakpointHit(id);
107 			state_ = State::Paused;
108 		}
109 
110 		onLocationUpdate(lock);
111 	}
112 }
113 
exit(bool isStep)114 void Thread::exit(bool isStep /* = false */)
115 {
116 	marl::lock lock(mutex);
117 	frames.pop_back();
118 	if(isStep)
119 	{
120 		onLocationUpdate(lock);
121 	}
122 }
123 
update(bool isStep,const UpdateFrame & f)124 void Thread::update(bool isStep, const UpdateFrame &f)
125 {
126 	marl::lock lock(mutex);
127 	auto &frame = *frames.back();
128 	if(isStep)
129 	{
130 		auto oldLocation = frame.location;
131 		f(frame);
132 		if(frame.location != oldLocation)
133 		{
134 			onLocationUpdate(lock);
135 		}
136 	}
137 	else
138 	{
139 		f(frame);
140 	}
141 }
142 
frame() const143 Frame Thread::frame() const
144 {
145 	marl::lock lock(mutex);
146 	return *frames.back();
147 }
148 
stack() const149 std::vector<Frame> Thread::stack() const
150 {
151 	marl::lock lock(mutex);
152 	std::vector<Frame> out;
153 	out.reserve(frames.size());
154 	for(auto frame : frames)
155 	{
156 		out.push_back(*frame);
157 	}
158 	return out;
159 }
160 
depth() const161 size_t Thread::depth() const
162 {
163 	marl::lock lock(mutex);
164 	return frames.size();
165 }
166 
state() const167 Thread::State Thread::state() const
168 {
169 	marl::lock lock(mutex);
170 	return state_;
171 }
172 
resume()173 void Thread::resume()
174 {
175 	{
176 		marl::lock lock(mutex);
177 		state_ = State::Running;
178 	}
179 	stateCV.notify_all();
180 }
181 
pause()182 void Thread::pause()
183 {
184 	marl::lock lock(mutex);
185 	state_ = State::Paused;
186 }
187 
stepIn()188 void Thread::stepIn()
189 {
190 	marl::lock lock(mutex);
191 	state_ = State::Stepping;
192 	pauseAtFrame.reset();
193 	stateCV.notify_all();
194 }
195 
stepOver()196 void Thread::stepOver()
197 {
198 	marl::lock lock(mutex);
199 	state_ = State::Stepping;
200 	pauseAtFrame = frames.back();
201 	stateCV.notify_all();
202 }
203 
stepOut()204 void Thread::stepOut()
205 {
206 	marl::lock lock(mutex);
207 	state_ = State::Stepping;
208 	pauseAtFrame = (frames.size() > 1) ? frames[frames.size() - 2] : nullptr;
209 	stateCV.notify_all();
210 }
211 
212 }  // namespace dbg
213 }  // namespace vk
214