* Copyright 2012-2015, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Jobs.h"
#include <AutoLocker.h>
#include "Architecture.h"
#include "CpuState.h"
#include "DebuggerInterface.h"
#include "TeamTypeInformation.h"
#include "Tracing.h"
#include "Value.h"
#include "ValueLoader.h"
#include "ValueLocation.h"
#include "ValueNode.h"
#include "ValueNodeContainer.h"
#include "Variable.h"
#include "VariableValueNodeChild.h"
ResolveValueNodeValueJob::ResolveValueNodeValueJob(
DebuggerInterface* debuggerInterface, Architecture* architecture,
CpuState* cpuState, TeamTypeInformation* typeInformation,
ValueNodeContainer* container, ValueNode* valueNode)
:
fKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE),
fDebuggerInterface(debuggerInterface),
fArchitecture(architecture),
fCpuState(cpuState),
fTypeInformation(typeInformation),
fContainer(container),
fValueNode(valueNode)
{
if (fCpuState != NULL)
fCpuState->AcquireReference();
fContainer->AcquireReference();
fValueNode->AcquireReference();
}
ResolveValueNodeValueJob::~ResolveValueNodeValueJob()
{
if (fCpuState != NULL)
fCpuState->ReleaseReference();
fContainer->ReleaseReference();
fValueNode->ReleaseReference();
}
const JobKey&
ResolveValueNodeValueJob::Key() const
{
return fKey;
}
status_t
ResolveValueNodeValueJob::Do()
{
AutoLocker<ValueNodeContainer> containerLocker(fContainer);
if (fValueNode->Container() != fContainer)
return B_BAD_VALUE;
status_t nodeResolutionState
= fValueNode->LocationAndValueResolutionState();
if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
return nodeResolutionState;
containerLocker.Unlock();
status_t error = _ResolveNodeValue();
if (error != B_OK) {
nodeResolutionState = fValueNode->LocationAndValueResolutionState();
if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
return nodeResolutionState;
containerLocker.Lock();
fValueNode->SetLocationAndValue(NULL, NULL, error);
containerLocker.Unlock();
}
return error;
}
status_t
ResolveValueNodeValueJob::_ResolveNodeValue()
{
AutoLocker<ValueNodeContainer> containerLocker(fContainer);
ValueNodeChild* nodeChild = fValueNode->NodeChild();
BReference<ValueNodeChild> nodeChildReference(nodeChild);
ValueNode* parentNode = nodeChild->Parent();
BReference<ValueNode> parentNodeReference(parentNode);
status_t nodeChildResolutionState = nodeChild->LocationResolutionState();
bool nodeChildDone = nodeChildResolutionState != VALUE_NODE_UNRESOLVED;
if (nodeChildDone && nodeChildResolutionState != B_OK)
return nodeChildResolutionState;
bool parentDone = true;
if (!nodeChildDone && parentNode != NULL) {
status_t parentResolutionState
= parentNode->LocationAndValueResolutionState();
parentDone = parentResolutionState != VALUE_NODE_UNRESOLVED;
if (parentDone && parentResolutionState != B_OK)
return parentResolutionState;
}
containerLocker.Unlock();
if (!parentDone) {
status_t error = _ResolveParentNodeValue(parentNode);
if (error != B_OK) {
TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
"node: %p (\"%s\"): _ResolveParentNodeValue(%p) failed\n",
fValueNode, fValueNode->Name().String(), parentNode);
return error;
}
if (State() == JOB_STATE_WAITING)
return B_OK;
}
if (!nodeChildDone) {
status_t error = _ResolveNodeChildLocation(nodeChild);
if (error != B_OK) {
TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
"node: %p (\"%s\"): _ResolveNodeChildLocation(%p) failed\n",
fValueNode, fValueNode->Name().String(), nodeChild);
return error;
}
}
CpuState* variableCpuState = NULL;
VariableValueNodeChild* variableChild = dynamic_cast<
VariableValueNodeChild*>(nodeChild);
if (variableChild != NULL)
variableCpuState = variableChild->GetVariable()->GetCpuState();
ValueLoader valueLoader(fArchitecture, fDebuggerInterface,
variableCpuState != NULL ? variableCpuState : fCpuState);
ValueLocation* location;
Value* value;
status_t error = fValueNode->ResolvedLocationAndValue(&valueLoader,
location, value);
if (error != B_OK) {
TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value "
"node: %p (\"%s\"): fValueNode->ResolvedLocationAndValue() "
"failed\n", fValueNode, fValueNode->Name().String());
return error;
}
BReference<ValueLocation> locationReference(location, true);
BReference<Value> valueReference(value, true);
containerLocker.Lock();
status_t nodeResolutionState
= fValueNode->LocationAndValueResolutionState();
if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
return nodeResolutionState;
fValueNode->SetLocationAndValue(location, value, B_OK);
containerLocker.Unlock();
return B_OK;
}
status_t
ResolveValueNodeValueJob::_ResolveNodeChildLocation(ValueNodeChild* nodeChild)
{
ValueLoader valueLoader(fArchitecture, fDebuggerInterface, fCpuState);
ValueLocation* location = NULL;
status_t error = nodeChild->ResolveLocation(&valueLoader, location);
BReference<ValueLocation> locationReference(location, true);
AutoLocker<ValueNodeContainer> containerLocker(fContainer);
status_t nodeChildResolutionState = nodeChild->LocationResolutionState();
if (nodeChildResolutionState == VALUE_NODE_UNRESOLVED)
nodeChild->SetLocation(location, error);
else
error = nodeChildResolutionState;
return error;
}
status_t
ResolveValueNodeValueJob::_ResolveParentNodeValue(ValueNode* parentNode)
{
AutoLocker<ValueNodeContainer> containerLocker(fContainer);
if (parentNode->Container() != fContainer)
return B_BAD_VALUE;
status_t nodeResolutionState
= parentNode->LocationAndValueResolutionState();
if (nodeResolutionState != VALUE_NODE_UNRESOLVED)
return nodeResolutionState;
AutoLocker<Worker> workerLocker(GetWorker());
SimpleJobKey jobKey(parentNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
if (GetWorker()->GetJob(jobKey) == NULL) {
workerLocker.Unlock();
status_t error = GetWorker()->ScheduleJob(
new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
fArchitecture, fCpuState, fTypeInformation, fContainer,
parentNode));
if (error != B_OK) {
parentNode->SetLocationAndValue(NULL, NULL, error);
return error;
}
}
workerLocker.Unlock();
containerLocker.Unlock();
switch (WaitFor(jobKey)) {
case JOB_DEPENDENCY_SUCCEEDED:
case JOB_DEPENDENCY_NOT_FOUND:
break;
case JOB_DEPENDENCY_ACTIVE:
return B_OK;
case JOB_DEPENDENCY_FAILED:
case JOB_DEPENDENCY_ABORTED:
default:
return B_ERROR;
}
containerLocker.Lock();
nodeResolutionState = parentNode->LocationAndValueResolutionState();
return nodeResolutionState != VALUE_NODE_UNRESOLVED
? nodeResolutionState : B_ERROR;
}