|
@@ -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
|
|
@@ -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,
|
|
@@ -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
|
|
@@ -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);
|
|
|
}
|
|
@@ -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
|