📄 dsmethod.c
字号:
if (ACPI_FAILURE (Status)) { goto Cleanup; } } /* * Increment the method parse tree thread count since it has been * reentered one more time (even if it is the same thread) */ ObjDesc->Method.ThreadCount++; AcpiMethodCount++; return_ACPI_STATUS (Status);Cleanup: /* On error, must release the method mutex (if present) */ if (ObjDesc->Method.Mutex) { AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex); } return_ACPI_STATUS (Status);}/******************************************************************************* * * FUNCTION: AcpiDsCallControlMethod * * PARAMETERS: Thread - Info for this thread * ThisWalkState - Current walk state * Op - Current Op to be walked * * RETURN: Status * * DESCRIPTION: Transfer execution to a called control method * ******************************************************************************/ACPI_STATUSAcpiDsCallControlMethod ( ACPI_THREAD_STATE *Thread, ACPI_WALK_STATE *ThisWalkState, ACPI_PARSE_OBJECT *Op){ ACPI_STATUS Status; ACPI_NAMESPACE_NODE *MethodNode; ACPI_WALK_STATE *NextWalkState = NULL; ACPI_OPERAND_OBJECT *ObjDesc; ACPI_EVALUATE_INFO *Info; UINT32 i; ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n", ThisWalkState->PrevOp, ThisWalkState)); /* * Get the namespace entry for the control method we are about to call */ MethodNode = ThisWalkState->MethodCallNode; if (!MethodNode) { return_ACPI_STATUS (AE_NULL_ENTRY); } ObjDesc = AcpiNsGetAttachedObject (MethodNode); if (!ObjDesc) { return_ACPI_STATUS (AE_NULL_OBJECT); } /* Init for new method, possibly wait on method mutex */ Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc, ThisWalkState); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Begin method parse/execution. Create a new walk state */ NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread); if (!NextWalkState) { Status = AE_NO_MEMORY; goto Cleanup; } /* * The resolved arguments were put on the previous walk state's operand * stack. Operands on the previous walk state stack always * start at index 0. Also, null terminate the list of arguments */ ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; /* * Allocate and initialize the evaluation information block * TBD: this is somewhat inefficient, should change interface to * DsInitAmlWalk. For now, keeps this struct off the CPU stack */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { return_ACPI_STATUS (AE_NO_MEMORY); } Info->Parameters = &ThisWalkState->Operands[0]; Info->ParameterType = ACPI_PARAM_ARGS; Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, Info, ACPI_IMODE_EXECUTE); ACPI_FREE (Info); if (ACPI_FAILURE (Status)) { goto Cleanup; } /* * Delete the operands on the previous walkstate operand stack * (they were copied to new objects) */ for (i = 0; i < ObjDesc->Method.ParamCount; i++) { AcpiUtRemoveReference (ThisWalkState->Operands [i]); ThisWalkState->Operands [i] = NULL; } /* Clear the operand stack */ ThisWalkState->NumOperands = 0; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", MethodNode->Name.Ascii, NextWalkState)); /* Invoke an internal method if necessary */ if (ObjDesc->Method.MethodFlags & AML_METHOD_INTERNAL_ONLY) { Status = ObjDesc->Method.Implementation (NextWalkState); } return_ACPI_STATUS (Status);Cleanup: /* On error, we must terminate the method properly */ AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); if (NextWalkState) { AcpiDsDeleteWalkState (NextWalkState); } return_ACPI_STATUS (Status);}/******************************************************************************* * * FUNCTION: AcpiDsRestartControlMethod * * PARAMETERS: WalkState - State for preempted method (caller) * ReturnDesc - Return value from the called method * * RETURN: Status * * DESCRIPTION: Restart a method that was preempted by another (nested) method * invocation. Handle the return value (if any) from the callee. * ******************************************************************************/ACPI_STATUSAcpiDsRestartControlMethod ( ACPI_WALK_STATE *WalkState, ACPI_OPERAND_OBJECT *ReturnDesc){ ACPI_STATUS Status; int SameAsImplicitReturn; ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", AcpiUtGetNodeName (WalkState->MethodNode), WalkState->MethodCallOp, ReturnDesc)); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", WalkState->ReturnUsed, WalkState->Results, WalkState)); /* Did the called method return a value? */ if (ReturnDesc) { /* Is the implicit return object the same as the return desc? */ SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); /* Are we actually going to use the return value? */ if (WalkState->ReturnUsed) { /* Save the return value from the previous method */ Status = AcpiDsResultPush (ReturnDesc, WalkState); if (ACPI_FAILURE (Status)) { AcpiUtRemoveReference (ReturnDesc); return_ACPI_STATUS (Status); } /* * Save as THIS method's return value in case it is returned * immediately to yet another method */ WalkState->ReturnDesc = ReturnDesc; } /* * The following code is the optional support for the so-called * "implicit return". Some AML code assumes that the last value of the * method is "implicitly" returned to the caller, in the absence of an * explicit return value. * * Just save the last result of the method as the return value. * * NOTE: this is optional because the ASL language does not actually * support this behavior. */ else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || SameAsImplicitReturn) { /* * Delete the return value if it will not be used by the * calling method or remove one reference if the explicit return * is the same as the implicit return value. */ AcpiUtRemoveReference (ReturnDesc); } } return_ACPI_STATUS (AE_OK);}/******************************************************************************* * * FUNCTION: AcpiDsTerminateControlMethod * * PARAMETERS: MethodDesc - Method object * WalkState - State associated with the method * * RETURN: None * * DESCRIPTION: Terminate a control method. Delete everything that the method * created, delete all locals and arguments, and delete the parse * tree if requested. * * MUTEX: Interpreter is locked * ******************************************************************************/voidAcpiDsTerminateControlMethod ( ACPI_OPERAND_OBJECT *MethodDesc, ACPI_WALK_STATE *WalkState){ ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); /* MethodDesc is required, WalkState is optional */ if (!MethodDesc) { return_VOID; } if (WalkState) { /* Delete all arguments and locals */ AcpiDsMethodDataDeleteAll (WalkState); /* * If method is serialized, release the mutex and restore the * current sync level for this thread */ if (MethodDesc->Method.Mutex) { /* Acquisition Depth handles recursive calls */ MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) { WalkState->Thread->CurrentSyncLevel = MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex); MethodDesc->Method.Mutex->Mutex.ThreadId = 0; } } /* * Delete any namespace objects created anywhere within * the namespace by the execution of this method */ AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); } /* Decrement the thread count on the method */ if (MethodDesc->Method.ThreadCount) { MethodDesc->Method.ThreadCount--; } else { ACPI_ERROR ((AE_INFO, "Invalid zero thread count in method")); } /* Are there any other threads currently executing this method? */ if (MethodDesc->Method.ThreadCount) { /* * Additional threads. Do not release the OwnerId in this case, * we immediately reuse it for the next thread executing this method */ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "*** Completed execution of one thread, %d threads remaining\n", MethodDesc->Method.ThreadCount)); } else { /* This is the only executing thread for this method */ /* * Support to dynamically change a method from NotSerialized to * Serialized if it appears that the method is incorrectly written and * does not support multiple thread execution. The best example of this * is if such a method creates namespace objects and blocks. A second * thread will fail with an AE_ALREADY_EXISTS exception * * This code is here because we must wait until the last thread exits * before creating the synchronization semaphore. */ if ((MethodDesc->Method.MethodFlags & AML_METHOD_SERIALIZED) && (!MethodDesc->Method.Mutex)) { (void) AcpiDsCreateMethodMutex (MethodDesc); } /* No more threads, we can free the OwnerId */ AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); } return_VOID;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -