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 {
58 lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
59 break;
60 }
61
62 case State::Stepping:
63 {
64 bool pause = false;
65
66 {
67 auto frame = pauseAtFrame.lock();
68 pause = !frame; // Pause if there's no pause-at-frame...
69 if(frame == frames.back()) // ... or if we've reached the pause-at-frame
70 {
71 pause = true;
72 pauseAtFrame.reset();
73 }
74 }
75
76 if(pause)
77 {
78 ctx->serverEventBroadcast()->onThreadStepped(id);
79 state_ = State::Paused;
80 lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
81 }
82 break;
83 }
84
85 case State::Running:
86 break;
87 }
88 }
89
enter(const std::shared_ptr<File> & file,const std::string & function,const UpdateFrame & f)90 void Thread::enter(const std::shared_ptr<File> &file, const std::string &function, const UpdateFrame &f)
91 {
92 std::shared_ptr<Frame> frame;
93 bool isFunctionBreakpoint;
94 {
95 auto lock = ctx->lock();
96 frame = lock.createFrame(file, function);
97 isFunctionBreakpoint = lock.isFunctionBreakpoint(function);
98 }
99
100 {
101 marl::lock lock(mutex);
102 frames.push_back(frame);
103
104 if(f) { f(*frame); }
105
106 if(isFunctionBreakpoint)
107 {
108 ctx->serverEventBroadcast()->onFunctionBreakpointHit(id);
109 state_ = State::Paused;
110 }
111
112 onLocationUpdate(lock);
113 }
114 }
115
exit(bool isStep)116 void Thread::exit(bool isStep /* = false */)
117 {
118 marl::lock lock(mutex);
119 frames.pop_back();
120 if(isStep)
121 {
122 onLocationUpdate(lock);
123 }
124 }
125
update(bool isStep,const UpdateFrame & f)126 void Thread::update(bool isStep, const UpdateFrame &f)
127 {
128 marl::lock lock(mutex);
129 auto &frame = *frames.back();
130 if(isStep)
131 {
132 auto oldLocation = frame.location;
133 f(frame);
134 if(frame.location != oldLocation)
135 {
136 onLocationUpdate(lock);
137 }
138 }
139 else
140 {
141 f(frame);
142 }
143 }
144
frame() const145 Frame Thread::frame() const
146 {
147 marl::lock lock(mutex);
148 return *frames.back();
149 }
150
stack() const151 std::vector<Frame> Thread::stack() const
152 {
153 marl::lock lock(mutex);
154 std::vector<Frame> out;
155 out.reserve(frames.size());
156 for(auto frame : frames)
157 {
158 out.push_back(*frame);
159 }
160 return out;
161 }
162
depth() const163 size_t Thread::depth() const
164 {
165 marl::lock lock(mutex);
166 return frames.size();
167 }
168
state() const169 Thread::State Thread::state() const
170 {
171 marl::lock lock(mutex);
172 return state_;
173 }
174
resume()175 void Thread::resume()
176 {
177 {
178 marl::lock lock(mutex);
179 state_ = State::Running;
180 }
181 stateCV.notify_all();
182 }
183
pause()184 void Thread::pause()
185 {
186 marl::lock lock(mutex);
187 state_ = State::Paused;
188 }
189
stepIn()190 void Thread::stepIn()
191 {
192 marl::lock lock(mutex);
193 state_ = State::Stepping;
194 pauseAtFrame.reset();
195 stateCV.notify_all();
196 }
197
stepOver()198 void Thread::stepOver()
199 {
200 marl::lock lock(mutex);
201 state_ = State::Stepping;
202 pauseAtFrame = frames.back();
203 stateCV.notify_all();
204 }
205
stepOut()206 void Thread::stepOut()
207 {
208 marl::lock lock(mutex);
209 state_ = State::Stepping;
210 pauseAtFrame = (frames.size() > 1) ? frames[frames.size() - 2] : nullptr;
211 stateCV.notify_all();
212 }
213
214 } // namespace dbg
215 } // namespace vk
216