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