void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); /* method_desc is required, walk_state is optional */ if (!method_desc) { return_VOID; } if (walk_state) { /* Delete all arguments and locals */ acpi_ds_method_data_delete_all(walk_state); /* * Delete any namespace objects created anywhere within the * namespace by the execution of this method. Unless: * 1) This method is a module-level executable code method, in which * case we want make the objects permanent. * 2) There are other threads executing the method, in which case we * will wait until the last thread has completed. */ if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) && (method_desc->method.thread_count == 1)) { /* Delete any direct children of (created by) this method */ (void)acpi_ex_exit_interpreter(); acpi_ns_delete_namespace_subtree(walk_state-> method_node); (void)acpi_ex_enter_interpreter(); /* * Delete any objects that were created by this method * elsewhere in the namespace (if any were created). * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the * deletion such that we don't have to perform an entire * namespace walk for every control method execution. */ if (method_desc->method. info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) { (void)acpi_ex_exit_interpreter(); acpi_ns_delete_namespace_by_owner(method_desc-> method. owner_id); (void)acpi_ex_enter_interpreter(); method_desc->method.info_flags &= ~ACPI_METHOD_MODIFIED_NAMESPACE; } } /* * If method is serialized, release the mutex and restore the * current sync level for this thread */ if (method_desc->method.mutex) { /* Acquisition Depth handles recursive calls */ method_desc->method.mutex->mutex.acquisition_depth--; if (!method_desc->method.mutex->mutex.acquisition_depth) { walk_state->thread->current_sync_level = method_desc->method.mutex->mutex. original_sync_level; acpi_os_release_mutex(method_desc->method. mutex->mutex.os_mutex); method_desc->method.mutex->mutex.thread_id = 0; } } } /* Decrement the thread count on the method */ if (method_desc->method.thread_count) { method_desc->method.thread_count--; } else { ACPI_ERROR((AE_INFO, "Invalid zero thread count in method")); } /* Are there any other threads currently executing this method? */ if (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, "*** Completed execution of one thread, %u threads remaining\n", method_desc->method.thread_count)); } 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 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 marking the method as serialized. */ if (method_desc->method. info_flags & ACPI_METHOD_SERIALIZED_PENDING) { if (walk_state) { ACPI_INFO(("Marking method %4.4s as Serialized " "because of AE_ALREADY_EXISTS error", walk_state->method_node->name. ascii)); } /* * Method tried to create an object twice and was marked as * "pending serialized". The probable cause is that the method * cannot handle reentrancy. * * The method was created as not_serialized, but it tried to create * a named object and then blocked, causing the second thread * entrance to begin and then fail. Workaround this problem by * marking the method permanently as Serialized when the last * thread exits here. */ method_desc->method.info_flags &= ~ACPI_METHOD_SERIALIZED_PENDING; method_desc->method.info_flags |= (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); method_desc->method.sync_level = 0; } /* No more threads, we can free the owner_id */ if (! (method_desc->method. info_flags & ACPI_METHOD_MODULE_LEVEL)) { acpi_ut_release_owner_id(&method_desc->method.owner_id); } } acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc-> method.node, method_desc, walk_state); return_VOID; }
void acpi_ds_dump_method_stack(acpi_status status, struct acpi_walk_state *walk_state, union acpi_parse_object *op) { union acpi_parse_object *next; struct acpi_thread_state *thread; struct acpi_walk_state *next_walk_state; struct acpi_namespace_node *previous_method = NULL; union acpi_operand_object *method_desc; ACPI_FUNCTION_TRACE(ds_dump_method_stack); /* Ignore control codes, they are not errors */ if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) { return_VOID; } /* We may be executing a deferred opcode */ if (walk_state->deferred_node) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Executing subtree for Buffer/Package/Region\n")); return_VOID; } /* * If there is no Thread, we are not actually executing a method. * This can happen when the iASL compiler calls the interpreter * to perform constant folding. */ thread = walk_state->thread; if (!thread) { return_VOID; } /* Display exception and method name */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "\n**** Exception %s during execution of method ", acpi_format_exception(status))); acpi_ds_print_node_pathname(walk_state->method_node, NULL); /* Display stack of executing methods */ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n\nMethod Execution Stack:\n")); next_walk_state = thread->walk_state_list; /* Walk list of linked walk states */ while (next_walk_state) { method_desc = next_walk_state->method_desc; if (method_desc) { acpi_ex_stop_trace_method((struct acpi_namespace_node *) method_desc->method.node, method_desc, walk_state); } ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, " Method [%4.4s] executing: ", acpi_ut_get_node_name(next_walk_state-> method_node))); /* First method is the currently executing method */ if (next_walk_state == walk_state) { if (op) { /* Display currently executing ASL statement */ next = op->common.next; op->common.next = NULL; #ifdef ACPI_DISASSEMBLER acpi_dm_disassemble(next_walk_state, op, ACPI_UINT32_MAX); #endif op->common.next = next; } } else { /* * This method has called another method * NOTE: the method call parse subtree is already deleted at * this point, so we cannot disassemble the method invocation. */ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "Call to method ")); acpi_ds_print_node_pathname(previous_method, NULL); } previous_method = next_walk_state->method_node; next_walk_state = next_walk_state->next; ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n")); } return_VOID; }