dsmethod.c

来自「linux2.6.16版本」· C语言 代码 · 共 691 行 · 第 1/2 页

C
691
字号
 * * FUNCTION:    acpi_ds_restart_control_method * * PARAMETERS:  walk_state          - State for preempted method (caller) *              return_desc         - Return value from the called method * * RETURN:      Status * * DESCRIPTION: Restart a method that was preempted by another (nested) method *              invocation.  Handle the return value (if any) from the callee. * ******************************************************************************/acpi_statusacpi_ds_restart_control_method(struct acpi_walk_state *walk_state,			       union acpi_operand_object *return_desc){	acpi_status status;	ACPI_FUNCTION_TRACE_PTR("ds_restart_control_method", walk_state);	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,			  "****Restart [%4.4s] Op %p return_value_from_callee %p\n",			  (char *)&walk_state->method_node->name,			  walk_state->method_call_op, return_desc));	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,			  "    return_from_this_method_used?=%X res_stack %p Walk %p\n",			  walk_state->return_used,			  walk_state->results, walk_state));	/* Did the called method return a value? */	if (return_desc) {		/* Are we actually going to use the return value? */		if (walk_state->return_used) {			/* Save the return value from the previous method */			status = acpi_ds_result_push(return_desc, walk_state);			if (ACPI_FAILURE(status)) {				acpi_ut_remove_reference(return_desc);				return_ACPI_STATUS(status);			}			/*			 * Save as THIS method's return value in case it is returned			 * immediately to yet another method			 */			walk_state->return_desc = return_desc;		}		/*		 * 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.		 * NOTE: this is optional because the ASL language does not actually		 * support this behavior.		 */		else if (!acpi_ds_do_implicit_return			 (return_desc, walk_state, FALSE)) {			/*			 * Delete the return value if it will not be used by the			 * calling method			 */			acpi_ut_remove_reference(return_desc);		}	}	return_ACPI_STATUS(AE_OK);}/******************************************************************************* * * FUNCTION:    acpi_ds_terminate_control_method * * PARAMETERS:  walk_state          - State of the method * * RETURN:      None * * DESCRIPTION: Terminate a control method.  Delete everything that the method *              created, delete all locals and arguments, and delete the parse *              tree if requested. * ******************************************************************************/void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state){	union acpi_operand_object *obj_desc;	struct acpi_namespace_node *method_node;	acpi_status status;	ACPI_FUNCTION_TRACE_PTR("ds_terminate_control_method", walk_state);	if (!walk_state) {		return_VOID;	}	/* The current method object was saved in the walk state */	obj_desc = walk_state->method_desc;	if (!obj_desc) {		return_VOID;	}	/* Delete all arguments and locals */	acpi_ds_method_data_delete_all(walk_state);	/*	 * Lock the parser while we terminate this method.	 * If this is the last thread executing the method,	 * we have additional cleanup to perform	 */	status = acpi_ut_acquire_mutex(ACPI_MTX_PARSER);	if (ACPI_FAILURE(status)) {		return_VOID;	}	/* Signal completion of the execution of this method if necessary */	if (walk_state->method_desc->method.semaphore) {		status =		    acpi_os_signal_semaphore(walk_state->method_desc->method.					     semaphore, 1);		if (ACPI_FAILURE(status)) {			ACPI_ERROR((AE_INFO,				    "Could not signal method semaphore"));			/* Ignore error and continue cleanup */		}	}	/*	 * 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,				  "*** Completed execution of one thread, %d threads remaining\n",				  walk_state->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 creating the synchronization semaphore.		 */		if ((walk_state->method_desc->method.concurrency == 1) &&		    (!walk_state->method_desc->method.semaphore)) {			status = acpi_os_create_semaphore(1, 1,							  &walk_state->							  method_desc->method.							  semaphore);		}		/* No more threads, we can free the owner_id */		acpi_ut_release_owner_id(&walk_state->method_desc->method.					 owner_id);	}      exit:	(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

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?