summaryrefslogtreecommitdiffstats
path: root/sys/contrib/dev/acpica/dsmethod.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/dev/acpica/dsmethod.c')
-rw-r--r--sys/contrib/dev/acpica/dsmethod.c547
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;
}
OpenPOWER on IntegriCloud