Skip to content

Commit

Permalink
[ACPI] ACPICA 20051202
Browse files Browse the repository at this point in the history
Modified the parsing of control methods to no longer
create namespace objects during the first pass of the
parse. Objects are now created only during the execute
phase, at the moment the namespace creation operator
is encountered in the AML (Name, OperationRegion,
CreateByteField, etc.) This should eliminate ALREADY_EXISTS
exceptions seen on some machines where reentrant control
methods are protected by an AML mutex. The mutex will now
correctly block multiple threads from attempting to create
the same object more than once.

Increased the number of available Owner Ids for namespace
object tracking from 32 to 255. This should eliminate the
OWNER_ID_LIMIT exceptions seen on some machines with a
large number of ACPI tables (either static or dynamic).

Enhanced the namespace dump routine to output the owner
ID for each namespace object.

Signed-off-by: Bob Moore <[email protected]>
Signed-off-by: Len Brown <[email protected]>
  • Loading branch information
acpibob authored and lenb committed Dec 10, 2005
1 parent c51a4de commit 28f55eb
Show file tree
Hide file tree
Showing 8 changed files with 350 additions and 226 deletions.
337 changes: 179 additions & 158 deletions drivers/acpi/dispatcher/dsmethod.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,133 +51,6 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsmethod")

/*******************************************************************************
*
* FUNCTION: acpi_ds_parse_method
*
* PARAMETERS: Node - Method node
*
* RETURN: Status
*
* DESCRIPTION: Parse the AML that is associated with the method.
*
* MUTEX: Assumes parser is locked
*
******************************************************************************/
acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
{
acpi_status status;
union acpi_operand_object *obj_desc;
union acpi_parse_object *op;
struct acpi_walk_state *walk_state;

ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node);

/* Parameter Validation */

if (!node) {
return_ACPI_STATUS(AE_NULL_ENTRY);
}

ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** Parsing [%4.4s] **** named_obj=%p\n",
acpi_ut_get_node_name(node), node));

/* Extract the method object from the method Node */

obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
return_ACPI_STATUS(AE_NULL_OBJECT);
}

/* Create a mutex for the method if there is a concurrency limit */

if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
(!obj_desc->method.semaphore)) {
status = acpi_os_create_semaphore(obj_desc->method.concurrency,
obj_desc->method.concurrency,
&obj_desc->method.semaphore);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
}

/*
* Allocate a new parser op to be the root of the parsed
* method tree
*/
op = acpi_ps_alloc_op(AML_METHOD_OP);
if (!op) {
return_ACPI_STATUS(AE_NO_MEMORY);
}

/* Init new op with the method name and pointer back to the Node */

acpi_ps_set_name(op, node->name.integer);
op->common.node = node;

/*
* Get a new owner_id for objects created by this method. Namespace
* objects (such as Operation Regions) can be created during the
* first pass parse.
*/
status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
if (ACPI_FAILURE(status)) {
goto cleanup;
}

/* Create and initialize a new walk state */

walk_state =
acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL,
NULL);
if (!walk_state) {
status = AE_NO_MEMORY;
goto cleanup2;
}

status = acpi_ds_init_aml_walk(walk_state, op, node,
obj_desc->method.aml_start,
obj_desc->method.aml_length, NULL, 1);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup2;
}

/*
* 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 = acpi_ps_parse_aml(walk_state);
if (ACPI_FAILURE(status)) {
goto cleanup2;
}

ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
acpi_ut_get_node_name(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)
*/
acpi_ns_delete_namespace_subtree(node);
acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);

cleanup2:
acpi_ut_release_owner_id(&obj_desc->method.owner_id);

cleanup:
acpi_ps_delete_parse_tree(op);
return_ACPI_STATUS(status);
}

/*******************************************************************************
*
* FUNCTION: acpi_ds_begin_method_execution
Expand All @@ -193,7 +66,6 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
* for clearance to execute.
*
******************************************************************************/

acpi_status
acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
union acpi_operand_object *obj_desc,
Expand Down Expand Up @@ -545,16 +417,54 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state)
}
}

/*
* There are no more threads executing this method. Perform
* additional cleanup.
*
* The method Node is stored in the walk state
*/
method_node = walk_state->method_node;

/* Lock namespace for possible update */

status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
goto exit;
}

/*
* Delete any namespace entries created immediately underneath
* the method
*/
if (method_node->child) {
acpi_ns_delete_namespace_subtree(method_node);
}

/*
* Delete any namespace entries created anywhere else within
* the namespace by the execution of this method
*/
acpi_ns_delete_namespace_by_owner(walk_state->method_desc->method.
owner_id);
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);

/* Are there any other threads currently executing this method? */

if (walk_state->method_desc->method.thread_count) {
/*
* Additional threads. Do not release the owner_id 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",
"*** Completed execution of one thread, %d threads remaining\n",
walk_state->method_desc->method.
thread_count));
} else { /* This is the last executing thread */
} else {
/* This is the only executing thread for this method */

/*
* Support to dynamically change a method from not_serialized to
* Serialized if it appears that the method is written foolishly and
* 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
Expand All @@ -570,34 +480,8 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state)
semaphore);
}

/*
* There are no more threads executing this method. Perform
* additional cleanup.
*
* The method Node is stored in the walk state
*/
method_node = walk_state->method_node;

/*
* Delete any namespace entries created immediately underneath
* the method
*/
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
goto exit;
}

if (method_node->child) {
acpi_ns_delete_namespace_subtree(method_node);
}
/* No more threads, we can free the owner_id */

/*
* Delete any namespace entries created anywhere else within
* the namespace
*/
acpi_ns_delete_namespace_by_owner(walk_state->method_desc->
method.owner_id);
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
acpi_ut_release_owner_id(&walk_state->method_desc->method.
owner_id);
}
Expand All @@ -606,3 +490,140 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state)
(void)acpi_ut_release_mutex(ACPI_MTX_PARSER);
return_VOID;
}

#ifdef ACPI_INIT_PARSE_METHODS
/*
* Note 11/2005: Removed this code to parse all methods during table
* load because it causes problems if there are any errors during the
* parse. Also, it seems like overkill and we probably don't want to
* abort a table load because of an issue with a single method.
*/

/*******************************************************************************
*
* FUNCTION: acpi_ds_parse_method
*
* PARAMETERS: Node - Method node
*
* RETURN: Status
*
* DESCRIPTION: Parse the AML that is associated with the method.
*
* MUTEX: Assumes parser is locked
*
******************************************************************************/

acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
{
acpi_status status;
union acpi_operand_object *obj_desc;
union acpi_parse_object *op;
struct acpi_walk_state *walk_state;

ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node);

/* Parameter Validation */

if (!node) {
return_ACPI_STATUS(AE_NULL_ENTRY);
}

ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** Parsing [%4.4s] **** named_obj=%p\n",
acpi_ut_get_node_name(node), node));

/* Extract the method object from the method Node */

obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
return_ACPI_STATUS(AE_NULL_OBJECT);
}

/* Create a mutex for the method if there is a concurrency limit */

if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
(!obj_desc->method.semaphore)) {
status = acpi_os_create_semaphore(obj_desc->method.concurrency,
obj_desc->method.concurrency,
&obj_desc->method.semaphore);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
}

/*
* Allocate a new parser op to be the root of the parsed
* method tree
*/
op = acpi_ps_alloc_op(AML_METHOD_OP);
if (!op) {
return_ACPI_STATUS(AE_NO_MEMORY);
}

/* Init new op with the method name and pointer back to the Node */

acpi_ps_set_name(op, node->name.integer);
op->common.node = node;

/*
* Get a new owner_id for objects created by this method. Namespace
* objects (such as Operation Regions) can be created during the
* first pass parse.
*/
status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
if (ACPI_FAILURE(status)) {
goto cleanup;
}

/* Create and initialize a new walk state */

walk_state =
acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL,
NULL);
if (!walk_state) {
status = AE_NO_MEMORY;
goto cleanup2;
}

status = acpi_ds_init_aml_walk(walk_state, op, node,
obj_desc->method.aml_start,
obj_desc->method.aml_length, NULL, 1);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup2;
}

/*
* 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 = acpi_ps_parse_aml(walk_state);
if (ACPI_FAILURE(status)) {
goto cleanup2;
}

ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
acpi_ut_get_node_name(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)
*/
acpi_ns_delete_namespace_subtree(node);
acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);

cleanup2:
acpi_ut_release_owner_id(&obj_desc->method.owner_id);

cleanup:
acpi_ps_delete_parse_tree(op);
return_ACPI_STATUS(status);
}
#endif
Loading

0 comments on commit 28f55eb

Please sign in to comment.