1 /*
2 * Copyright 2012-2015, Rene Gollent, rene@gollent.com.
3 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7 #include "Jobs.h"
8
9 #include <AutoLocker.h>
10
11 #include "Architecture.h"
12 #include "CpuState.h"
13 #include "DebuggerInterface.h"
14 #include "TeamTypeInformation.h"
15 #include "Tracing.h"
16 #include "Value.h"
17 #include "ValueLoader.h"
18 #include "ValueLocation.h"
19 #include "ValueNode.h"
20 #include "ValueNodeContainer.h"
21 #include "Variable.h"
22 #include "VariableValueNodeChild.h"
23
24
ResolveValueNodeValueJob(DebuggerInterface * debuggerInterface,Architecture * architecture,CpuState * cpuState,TeamTypeInformation * typeInformation,ValueNodeContainer * container,ValueNode * valueNode)25 ResolveValueNodeValueJob::ResolveValueNodeValueJob(
26 DebuggerInterface* debuggerInterface, Architecture* architecture,
27 CpuState* cpuState, TeamTypeInformation* typeInformation,
28 ValueNodeContainer* container, ValueNode* valueNode)
29 :
30 fKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE),
31 fDebuggerInterface(debuggerInterface),
32 fArchitecture(architecture),
33 fCpuState(cpuState),
34 fTypeInformation(typeInformation),
35 fContainer(container),
36 fValueNode(valueNode)
37 {
38 if (fCpuState != NULL)
39 fCpuState->AcquireReference();
40 fContainer->AcquireReference();
41 fValueNode->AcquireReference();
42 }
43
44
~ResolveValueNodeValueJob()45 ResolveValueNodeValueJob::~ResolveValueNodeValueJob()
46 {
47 if (fCpuState != NULL)
48 fCpuState->ReleaseReference();
49 fContainer->ReleaseReference();
50 fValueNode->ReleaseReference();
51 }
52
53
54 const JobKey&
Key() const55 ResolveValueNodeValueJob::Key() const
56 {
57 return fKey;
58 }
59
60
61 status_t
Do()62 ResolveValueNodeValueJob::Do()
63 {
64 // check whether the node still belongs to the container
65 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
66 if (fValueNode->Container() != fContainer)
67 return B_BAD_VALUE;
68
69 // if already resolved, we're done
70 status_t nodeResolutionState
71 = fValueNode->LocationAndValueResolutionState();
72 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
73 return nodeResolutionState;
74
75 containerLocker.Unlock();
76
77 // resolve
78 status_t error = _ResolveNodeValue();
79 if (error != B_OK) {
80 nodeResolutionState = fValueNode->LocationAndValueResolutionState();
81 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
82 return nodeResolutionState;
83
84 containerLocker.Lock();
85 fValueNode->SetLocationAndValue(NULL, NULL, error);
86 containerLocker.Unlock();
87 }
88
89 return error;
90 }
91
92
93 status_t
_ResolveNodeValue()94 ResolveValueNodeValueJob::_ResolveNodeValue()
95 {
96 // get the node child and parent node
97 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
98 ValueNodeChild* nodeChild = fValueNode->NodeChild();
99 BReference<ValueNodeChild> nodeChildReference(nodeChild);
100
101 ValueNode* parentNode = nodeChild->Parent();
102 BReference<ValueNode> parentNodeReference(parentNode);
103
104 // Check whether the node child location has been resolved already
105 // (successfully).
106 status_t nodeChildResolutionState = nodeChild->LocationResolutionState();
107 bool nodeChildDone = nodeChildResolutionState != VALUE_NODE_UNRESOLVED;
108 if (nodeChildDone && nodeChildResolutionState != B_OK)
109 return nodeChildResolutionState;
110
111 // If the child node location has not been resolved yet, check whether the
112 // parent node location and value have been resolved already (successfully).
113 bool parentDone = true;
114 if (!nodeChildDone && parentNode != NULL) {
115 status_t parentResolutionState
116 = parentNode->LocationAndValueResolutionState();
117 parentDone = parentResolutionState != VALUE_NODE_UNRESOLVED;
118 if (parentDone && parentResolutionState != B_OK)
119 return parentResolutionState;
120 }
121
122 containerLocker.Unlock();
123
124 // resolve the parent node location and value, if necessary
125 if (!parentDone) {
126 status_t error = _ResolveParentNodeValue(parentNode);
127 if (error != B_OK) {
128 TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
129 "node: %p (\"%s\"): _ResolveParentNodeValue(%p) failed\n",
130 fValueNode, fValueNode->Name().String(), parentNode);
131 return error;
132 }
133
134 if (State() == JOB_STATE_WAITING)
135 return B_OK;
136 }
137
138 // resolve the node child location, if necessary
139 if (!nodeChildDone) {
140 status_t error = _ResolveNodeChildLocation(nodeChild);
141 if (error != B_OK) {
142 TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
143 "node: %p (\"%s\"): _ResolveNodeChildLocation(%p) failed\n",
144 fValueNode, fValueNode->Name().String(), nodeChild);
145 return error;
146 }
147 }
148
149 CpuState* variableCpuState = NULL;
150 VariableValueNodeChild* variableChild = dynamic_cast<
151 VariableValueNodeChild*>(nodeChild);
152 if (variableChild != NULL)
153 variableCpuState = variableChild->GetVariable()->GetCpuState();
154
155 // resolve the node location and value
156 ValueLoader valueLoader(fArchitecture, fDebuggerInterface,
157 variableCpuState != NULL ? variableCpuState : fCpuState);
158 ValueLocation* location;
159 Value* value;
160 status_t error = fValueNode->ResolvedLocationAndValue(&valueLoader,
161 location, value);
162 if (error != B_OK) {
163 TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
164 "node: %p (\"%s\"): fValueNode->ResolvedLocationAndValue() "
165 "failed\n", fValueNode, fValueNode->Name().String());
166 return error;
167 }
168 BReference<ValueLocation> locationReference(location, true);
169 BReference<Value> valueReference(value, true);
170
171 // set location and value on the node
172 containerLocker.Lock();
173 status_t nodeResolutionState
174 = fValueNode->LocationAndValueResolutionState();
175 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
176 return nodeResolutionState;
177 fValueNode->SetLocationAndValue(location, value, B_OK);
178 containerLocker.Unlock();
179
180 return B_OK;
181 }
182
183
184 status_t
_ResolveNodeChildLocation(ValueNodeChild * nodeChild)185 ResolveValueNodeValueJob::_ResolveNodeChildLocation(ValueNodeChild* nodeChild)
186 {
187 // resolve the location
188 ValueLoader valueLoader(fArchitecture, fDebuggerInterface, fCpuState);
189 ValueLocation* location = NULL;
190 status_t error = nodeChild->ResolveLocation(&valueLoader, location);
191 BReference<ValueLocation> locationReference(location, true);
192
193 // set the location on the node child
194 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
195 status_t nodeChildResolutionState = nodeChild->LocationResolutionState();
196 if (nodeChildResolutionState == VALUE_NODE_UNRESOLVED)
197 nodeChild->SetLocation(location, error);
198 else
199 error = nodeChildResolutionState;
200
201 return error;
202 }
203
204
205 status_t
_ResolveParentNodeValue(ValueNode * parentNode)206 ResolveValueNodeValueJob::_ResolveParentNodeValue(ValueNode* parentNode)
207 {
208 AutoLocker<ValueNodeContainer> containerLocker(fContainer);
209
210 if (parentNode->Container() != fContainer)
211 return B_BAD_VALUE;
212
213 // if the parent node already has a value, we're done
214 status_t nodeResolutionState
215 = parentNode->LocationAndValueResolutionState();
216 if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
217 return nodeResolutionState;
218
219 // check whether a job is already in progress
220 AutoLocker<Worker> workerLocker(GetWorker());
221 SimpleJobKey jobKey(parentNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
222 if (GetWorker()->GetJob(jobKey) == NULL) {
223 workerLocker.Unlock();
224
225 // schedule the job
226 status_t error = GetWorker()->ScheduleJob(
227 new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
228 fArchitecture, fCpuState, fTypeInformation, fContainer,
229 parentNode));
230 if (error != B_OK) {
231 // scheduling failed -- set the value to invalid
232 parentNode->SetLocationAndValue(NULL, NULL, error);
233 return error;
234 }
235 }
236
237 // wait for the job to finish
238 workerLocker.Unlock();
239 containerLocker.Unlock();
240
241 switch (WaitFor(jobKey)) {
242 case JOB_DEPENDENCY_SUCCEEDED:
243 case JOB_DEPENDENCY_NOT_FOUND:
244 // "Not found" can happen due to a race condition between
245 // unlocking the worker and starting to wait.
246 break;
247 case JOB_DEPENDENCY_ACTIVE:
248 return B_OK;
249 case JOB_DEPENDENCY_FAILED:
250 case JOB_DEPENDENCY_ABORTED:
251 default:
252 return B_ERROR;
253 }
254
255 containerLocker.Lock();
256
257 // now there should be a value for the node
258 nodeResolutionState = parentNode->LocationAndValueResolutionState();
259 return nodeResolutionState != VALUE_NODE_UNRESOLVED
260 ? nodeResolutionState : B_ERROR;
261 }
262