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 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 45 ResolveValueNodeValueJob::~ResolveValueNodeValueJob() 46 { 47 if (fCpuState != NULL) 48 fCpuState->ReleaseReference(); 49 fContainer->ReleaseReference(); 50 fValueNode->ReleaseReference(); 51 } 52 53 54 const JobKey& 55 ResolveValueNodeValueJob::Key() const 56 { 57 return fKey; 58 } 59 60 61 status_t 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 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 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 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