xref: /haiku/src/kits/debugger/jobs/ResolveValueNodeJob.cpp (revision fce4895d1884da5ae6fb299d23c735c598e690b1)
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