diff options
Diffstat (limited to 'sys/contrib/dev/acpica/dsmethod.c')
-rw-r--r-- | sys/contrib/dev/acpica/dsmethod.c | 547 |
1 files changed, 282 insertions, 265 deletions
diff --git a/sys/contrib/dev/acpica/dsmethod.c b/sys/contrib/dev/acpica/dsmethod.c index e66c828..514f3a1 100644 --- a/sys/contrib/dev/acpica/dsmethod.c +++ b/sys/contrib/dev/acpica/dsmethod.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dsmethod - Parser/Interpreter interface - control method parsing - * $Revision: 1.110 $ + * $Revision: 1.136 $ * *****************************************************************************/ @@ -9,7 +9,7 @@ * * 1. Copyright Notice * - * Some or all of this work - Copyright (c) 1999 - 2005, Intel Corp. + * Some or all of this work - Copyright (c) 1999 - 2007, Intel Corp. * All rights reserved. * * 2. License @@ -122,149 +122,125 @@ #include <contrib/dev/acpica/acdispat.h> #include <contrib/dev/acpica/acinterp.h> #include <contrib/dev/acpica/acnamesp.h> +#include <contrib/dev/acpica/acdisasm.h> #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsmethod") +/* Local prototypes */ + +static ACPI_STATUS +AcpiDsCreateMethodMutex ( + ACPI_OPERAND_OBJECT *MethodDesc); + /******************************************************************************* * - * FUNCTION: AcpiDsParseMethod + * FUNCTION: AcpiDsMethodError * - * PARAMETERS: Node - Method node + * PARAMETERS: Status - Execution status + * WalkState - Current state * * RETURN: Status * - * DESCRIPTION: Parse the AML that is associated with the method. + * DESCRIPTION: Called on method error. Invoke the global exception handler if + * present, dump the method data if the disassembler is configured * - * MUTEX: Assumes parser is locked + * Note: Allows the exception handler to change the status code * ******************************************************************************/ ACPI_STATUS -AcpiDsParseMethod ( - ACPI_NAMESPACE_NODE *Node) +AcpiDsMethodError ( + ACPI_STATUS Status, + ACPI_WALK_STATE *WalkState) { - ACPI_STATUS Status; - ACPI_OPERAND_OBJECT *ObjDesc; - ACPI_PARSE_OBJECT *Op; - ACPI_WALK_STATE *WalkState; - + ACPI_FUNCTION_ENTRY (); - ACPI_FUNCTION_TRACE_PTR ("DsParseMethod", Node); + /* Ignore AE_OK and control exception codes */ - /* Parameter Validation */ - - if (!Node) + if (ACPI_SUCCESS (Status) || + (Status & AE_CODE_CONTROL)) { - return_ACPI_STATUS (AE_NULL_ENTRY); + return (Status); } - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** NamedObj=%p\n", - AcpiUtGetNodeName (Node), Node)); - - /* Extract the method object from the method Node */ + /* Invoke the global exception handler */ - ObjDesc = AcpiNsGetAttachedObject (Node); - if (!ObjDesc) + if (AcpiGbl_ExceptionHandler) { - return_ACPI_STATUS (AE_NULL_OBJECT); - } + /* Exit the interpreter, allow handler to execute methods */ - /* Create a mutex for the method if there is a concurrency limit */ + AcpiExExitInterpreter (); - if ((ObjDesc->Method.Concurrency != ACPI_INFINITE_CONCURRENCY) && - (!ObjDesc->Method.Semaphore)) - { - Status = AcpiOsCreateSemaphore (ObjDesc->Method.Concurrency, - ObjDesc->Method.Concurrency, - &ObjDesc->Method.Semaphore); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } + /* + * Handler can map the exception code to anything it wants, including + * AE_OK, in which case the executing method will not be aborted. + */ + Status = AcpiGbl_ExceptionHandler (Status, + WalkState->MethodNode ? + WalkState->MethodNode->Name.Integer : 0, + WalkState->Opcode, WalkState->AmlOffset, NULL); + (void) AcpiExEnterInterpreter (); } - /* - * Allocate a new parser op to be the root of the parsed - * method tree - */ - Op = AcpiPsAllocOp (AML_METHOD_OP); - if (!Op) +#ifdef ACPI_DISASSEMBLER + if (ACPI_FAILURE (Status)) { - return_ACPI_STATUS (AE_NO_MEMORY); + /* Display method locals/args if disassembler is present */ + + AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op); } +#endif - /* Init new op with the method name and pointer back to the Node */ + return (Status); +} - AcpiPsSetName (Op, Node->Name.Integer); - Op->Common.Node = Node; - /* - * Get a new OwnerId for objects created by this method. Namespace - * objects (such as Operation Regions) can be created during the - * first pass parse. - */ - Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); - if (ACPI_FAILURE (Status)) - { - goto Cleanup; - } +/******************************************************************************* + * + * FUNCTION: AcpiDsCreateMethodMutex + * + * PARAMETERS: ObjDesc - The method object + * + * RETURN: Status + * + * DESCRIPTION: Create a mutex object for a serialized control method + * + ******************************************************************************/ - /* Create and initialize a new walk state */ +static ACPI_STATUS +AcpiDsCreateMethodMutex ( + ACPI_OPERAND_OBJECT *MethodDesc) +{ + ACPI_OPERAND_OBJECT *MutexDesc; + ACPI_STATUS Status; - WalkState = AcpiDsCreateWalkState ( - ObjDesc->Method.OwnerId, NULL, NULL, NULL); - if (!WalkState) - { - Status = AE_NO_MEMORY; - goto Cleanup2; - } - Status = AcpiDsInitAmlWalk (WalkState, Op, Node, - ObjDesc->Method.AmlStart, - ObjDesc->Method.AmlLength, NULL, 1); - if (ACPI_FAILURE (Status)) + ACPI_FUNCTION_TRACE (DsCreateMethodMutex); + + + /* Create the new mutex object */ + + MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX); + if (!MutexDesc) { - AcpiDsDeleteWalkState (WalkState); - goto Cleanup2; + return_ACPI_STATUS (AE_NO_MEMORY); } - /* - * Parse the method, first pass - * - * The first pass load is where newly declared named objects are added into - * the namespace. Actual evaluation of the named objects (what would be - * called a "second pass") happens during the actual execution of the - * method so that operands to the named objects can take on dynamic - * run-time values. - */ - Status = AcpiPsParseAml (WalkState); + /* Create the actual OS Mutex */ + + Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex); if (ACPI_FAILURE (Status)) { - goto Cleanup2; + return_ACPI_STATUS (Status); } - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, - "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n", - AcpiUtGetNodeName (Node), Node, Op)); - - /* - * Delete the parse tree. We simply re-parse the method for every - * execution since there isn't much overhead (compared to keeping lots - * of parse trees around) - */ - AcpiNsDeleteNamespaceSubtree (Node); - AcpiNsDeleteNamespaceByOwner (ObjDesc->Method.OwnerId); - -Cleanup2: - AcpiUtReleaseOwnerId (&ObjDesc->Method.OwnerId); - -Cleanup: - AcpiPsDeleteParseTree (Op); - return_ACPI_STATUS (Status); + MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel; + MethodDesc->Method.Mutex = MutexDesc; + return_ACPI_STATUS (AE_OK); } @@ -274,7 +250,8 @@ Cleanup: * * PARAMETERS: MethodNode - Node of the method * ObjDesc - The method object - * CallingMethodNode - Caller of this method (if non-null) + * WalkState - current state, NULL if not yet executing + * a method. * * RETURN: Status * @@ -288,12 +265,12 @@ ACPI_STATUS AcpiDsBeginMethodExecution ( ACPI_NAMESPACE_NODE *MethodNode, ACPI_OPERAND_OBJECT *ObjDesc, - ACPI_NAMESPACE_NODE *CallingMethodNode) + ACPI_WALK_STATE *WalkState) { ACPI_STATUS Status = AE_OK; - ACPI_FUNCTION_TRACE_PTR ("DsBeginMethodExecution", MethodNode); + ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode); if (!MethodNode) @@ -305,39 +282,87 @@ AcpiDsBeginMethodExecution ( if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX) { - ACPI_REPORT_ERROR (( - "Method reached maximum reentrancy limit (255)\n")); + ACPI_ERROR ((AE_INFO, + "Method reached maximum reentrancy limit (255)")); return_ACPI_STATUS (AE_AML_METHOD_LIMIT); } /* - * If there is a concurrency limit on this method, we need to - * obtain a unit from the method semaphore. + * If this method is serialized, we need to acquire the method mutex. */ - if (ObjDesc->Method.Semaphore) + if (ObjDesc->Method.MethodFlags & AML_METHOD_SERIALIZED) { /* - * Allow recursive method calls, up to the reentrancy/concurrency - * limit imposed by the SERIALIZED rule and the SyncLevel method - * parameter. - * - * The point of this code is to avoid permanently blocking a - * thread that is making recursive method calls. + * Create a mutex for the method if it is defined to be Serialized + * and a mutex has not already been created. We defer the mutex creation + * until a method is actually executed, to minimize the object count */ - if (MethodNode == CallingMethodNode) + if (!ObjDesc->Method.Mutex) { - if (ObjDesc->Method.ThreadCount >= ObjDesc->Method.Concurrency) + Status = AcpiDsCreateMethodMutex (ObjDesc); + if (ACPI_FAILURE (Status)) { - return_ACPI_STATUS (AE_AML_METHOD_LIMIT); + return_ACPI_STATUS (Status); } } /* - * Get a unit from the method semaphore. This releases the - * interpreter if we block + * The CurrentSyncLevel (per-thread) must be less than or equal to + * the sync level of the method. This mechanism provides some + * deadlock prevention + * + * Top-level method invocation has no walk state at this point */ - Status = AcpiExSystemWaitSemaphore (ObjDesc->Method.Semaphore, - ACPI_WAIT_FOREVER); + if (WalkState && + (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel)) + { + ACPI_ERROR ((AE_INFO, + "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%d)", + AcpiUtGetNodeName (MethodNode), + WalkState->Thread->CurrentSyncLevel)); + + return_ACPI_STATUS (AE_AML_MUTEX_ORDER); + } + + /* + * Obtain the method mutex if necessary. Do not acquire mutex for a + * recursive call. + */ + if (!WalkState || + !ObjDesc->Method.Mutex->Mutex.ThreadId || + (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId)) + { + /* + * Acquire the method mutex. This releases the interpreter if we + * block (and reacquires it before it returns) + */ + Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex, + ACPI_WAIT_FOREVER); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Update the mutex and walk info and save the original SyncLevel */ + + if (WalkState) + { + ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = + WalkState->Thread->CurrentSyncLevel; + + ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId; + WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel; + } + else + { + ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = + ObjDesc->Method.Mutex->Mutex.SyncLevel; + } + } + + /* Always increase acquisition depth */ + + ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++; } /* @@ -345,14 +370,14 @@ AcpiDsBeginMethodExecution ( * to begin concurrent execution. We only need one OwnerId, even if the * method is invoked recursively. */ - if (!ObjDesc->Method.OwnerId) - { - Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } - } + if (!ObjDesc->Method.OwnerId) + { + Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); + if (ACPI_FAILURE (Status)) + { + goto Cleanup; + } + } /* * Increment the method parse tree thread count since it has been @@ -360,6 +385,16 @@ AcpiDsBeginMethodExecution ( */ ObjDesc->Method.ThreadCount++; 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); } @@ -387,13 +422,13 @@ AcpiDsCallControlMethod ( ACPI_NAMESPACE_NODE *MethodNode; ACPI_WALK_STATE *NextWalkState = NULL; ACPI_OPERAND_OBJECT *ObjDesc; - ACPI_PARAMETER_INFO Info; + ACPI_EVALUATE_INFO *Info; UINT32 i; - ACPI_FUNCTION_TRACE_PTR ("DsCallControlMethod", ThisWalkState); + ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n", ThisWalkState->PrevOp, ThisWalkState)); /* @@ -411,59 +446,25 @@ AcpiDsCallControlMethod ( return_ACPI_STATUS (AE_NULL_OBJECT); } - /* Init for new method, wait on concurrency semaphore */ + /* Init for new method, possibly wait on method mutex */ Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc, - ThisWalkState->MethodNode); + ThisWalkState); if (ACPI_FAILURE (Status)) { - goto Cleanup; + return_ACPI_STATUS (Status); } - if (!(ObjDesc->Method.MethodFlags & AML_METHOD_INTERNAL_ONLY)) - { - /* 1) Parse: Create a new walk state for the preempting walk */ - - NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId, - Op, ObjDesc, NULL); - if (!NextWalkState) - { - return_ACPI_STATUS (AE_NO_MEMORY); - } - - /* Create and init a Root Node */ - - Op = AcpiPsCreateScopeOp (); - if (!Op) - { - Status = AE_NO_MEMORY; - goto Cleanup; - } - - Status = AcpiDsInitAmlWalk (NextWalkState, Op, MethodNode, - ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, - NULL, 1); - if (ACPI_FAILURE (Status)) - { - AcpiDsDeleteWalkState (NextWalkState); - goto Cleanup; - } - - /* Begin AML parse */ - - Status = AcpiPsParseAml (NextWalkState); - AcpiPsDeleteParseTree (Op); - } - - /* 2) Execute: Create a new state for the preempting walk */ + /* Begin method parse/execution. Create a new walk state */ NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId, - NULL, ObjDesc, Thread); + 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 @@ -471,12 +472,25 @@ AcpiDsCallControlMethod ( */ ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; - Info.Parameters = &ThisWalkState->Operands[0]; - Info.ParameterType = ACPI_PARAM_ARGS; + /* + * 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, 3); + ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, + Info, ACPI_IMODE_EXECUTE); + + ACPI_FREE (Info); if (ACPI_FAILURE (Status)) { goto Cleanup; @@ -497,7 +511,10 @@ AcpiDsCallControlMethod ( ThisWalkState->NumOperands = 0; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, - "Starting nested execution, newstate=%p\n", NextWalkState)); + "**** 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) { @@ -508,17 +525,15 @@ AcpiDsCallControlMethod ( Cleanup: - /* Decrement the thread count on the method parse tree */ - if (NextWalkState && (NextWalkState->MethodDesc)) + /* On error, we must terminate the method properly */ + + AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); + if (NextWalkState) { - NextWalkState->MethodDesc->Method.ThreadCount--; + AcpiDsDeleteWalkState (NextWalkState); } - /* On error, we must delete the new walk state */ - - AcpiDsTerminateControlMethod (NextWalkState); - AcpiDsDeleteWalkState (NextWalkState); return_ACPI_STATUS (Status); } @@ -543,15 +558,16 @@ AcpiDsRestartControlMethod ( ACPI_OPERAND_OBJECT *ReturnDesc) { ACPI_STATUS Status; + int SameAsImplicitReturn; - ACPI_FUNCTION_TRACE_PTR ("DsRestartControlMethod", WalkState); + ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", - (char *) &WalkState->MethodNode->Name, WalkState->MethodCallOp, - ReturnDesc)); + AcpiUtGetNodeName (WalkState->MethodNode), + WalkState->MethodCallOp, ReturnDesc)); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", @@ -562,6 +578,10 @@ AcpiDsRestartControlMethod ( 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) @@ -583,18 +603,23 @@ AcpiDsRestartControlMethod ( } /* - * The following code is the - * optional support for a so-called "implicit return". Some AML code - * assumes that the last value of the method is "implicitly" returned - * to the caller. Just save the last result as the return value. + * 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)) + else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || + SameAsImplicitReturn) { /* * Delete the return value if it will not be used by the - * calling method + * calling method or remove one reference if the explicit return + * is the same as the implicit return value. */ AcpiUtRemoveReference (ReturnDesc); } @@ -608,7 +633,8 @@ AcpiDsRestartControlMethod ( * * FUNCTION: AcpiDsTerminateControlMethod * - * PARAMETERS: WalkState - State of the method + * PARAMETERS: MethodDesc - Method object + * WalkState - State associated with the method * * RETURN: None * @@ -616,121 +642,112 @@ AcpiDsRestartControlMethod ( * created, delete all locals and arguments, and delete the parse * tree if requested. * + * MUTEX: Interpreter is locked + * ******************************************************************************/ void AcpiDsTerminateControlMethod ( + ACPI_OPERAND_OBJECT *MethodDesc, ACPI_WALK_STATE *WalkState) { - ACPI_OPERAND_OBJECT *ObjDesc; - ACPI_NAMESPACE_NODE *MethodNode; ACPI_STATUS Status; - ACPI_FUNCTION_TRACE_PTR ("DsTerminateControlMethod", WalkState); - + ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); - if (!WalkState) - { - return_VOID; - } - /* The current method object was saved in the walk state */ + /* MethodDesc is required, WalkState is optional */ - ObjDesc = WalkState->MethodDesc; - if (!ObjDesc) + if (!MethodDesc) { return_VOID; } - /* Delete all arguments and locals */ + if (WalkState) + { + /* Delete all arguments and locals */ - AcpiDsMethodDataDeleteAll (WalkState); + AcpiDsMethodDataDeleteAll (WalkState); + } /* - * Lock the parser while we terminate this method. - * If this is the last thread executing the method, - * we have additional cleanup to perform + * If method is serialized, release the mutex and restore the + * current sync level for this thread */ - Status = AcpiUtAcquireMutex (ACPI_MTX_PARSER); - if (ACPI_FAILURE (Status)) + if (MethodDesc->Method.Mutex) { - return_VOID; - } - - /* Signal completion of the execution of this method if necessary */ + /* Acquisition Depth handles recursive calls */ - if (WalkState->MethodDesc->Method.Semaphore) - { - Status = AcpiOsSignalSemaphore ( - WalkState->MethodDesc->Method.Semaphore, 1); - if (ACPI_FAILURE (Status)) + MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; + if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) { - ACPI_REPORT_ERROR (("Could not signal method semaphore\n")); + WalkState->Thread->CurrentSyncLevel = + MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; - /* Ignore error and continue cleanup */ + AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex); + MethodDesc->Method.Mutex->Mutex.ThreadId = 0; } } - if (WalkState->MethodDesc->Method.ThreadCount) + if (WalkState) + { + /* + * 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, - "*** Not deleting method namespace, there are still %d threads\n", - WalkState->MethodDesc->Method.ThreadCount)); + "*** Completed execution of one thread, %d threads remaining\n", + MethodDesc->Method.ThreadCount)); } - else /* This is the last executing thread */ + 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 written foolishly and - * does not support multiple thread execution. The best example of this - * is if such a method creates namespace objects and blocks. A second + * 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 ((WalkState->MethodDesc->Method.Concurrency == 1) && - (!WalkState->MethodDesc->Method.Semaphore)) - { - Status = AcpiOsCreateSemaphore (1, 1, - &WalkState->MethodDesc->Method.Semaphore); - } - - /* - * There are no more threads executing this method. Perform - * additional cleanup. - * - * The method Node is stored in the walk state - */ - MethodNode = WalkState->MethodNode; - - /* - * Delete any namespace entries created immediately underneath - * the method - */ - Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (Status)) + if ((MethodDesc->Method.MethodFlags & AML_METHOD_SERIALIZED) && + (!MethodDesc->Method.Mutex)) { - goto Exit; + Status = AcpiDsCreateMethodMutex (MethodDesc); } - if (MethodNode->Child) - { - AcpiNsDeleteNamespaceSubtree (MethodNode); - } + /* No more threads, we can free the OwnerId */ - /* - * Delete any namespace entries created anywhere else within - * the namespace - */ - AcpiNsDeleteNamespaceByOwner (WalkState->MethodDesc->Method.OwnerId); - Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); - AcpiUtReleaseOwnerId (&WalkState->MethodDesc->Method.OwnerId); + AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); } -Exit: - (void) AcpiUtReleaseMutex (ACPI_MTX_PARSER); return_VOID; } |