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